package base import ( "fmt" "sync" "testing" "time" ) func TestRegulatorEnterExit(t *testing.T) { const limit = 500 r := NewRegulator(nil, limit).(*regulator) for try := 0; try < 50; try++ { run := make(chan struct{}) var firstGroupReady sync.WaitGroup var firstGroupDone sync.WaitGroup firstGroupReady.Add(limit) firstGroupDone.Add(limit) for i := 0; i < limit; i++ { go func() { r.enter() firstGroupReady.Done() <-run r.exit() firstGroupDone.Done() }() } firstGroupReady.Wait() // now we exhausted all the limit, let's run a little bit more var secondGroupReady sync.WaitGroup var secondGroupDone sync.WaitGroup for i := 0; i < 50; i++ { secondGroupReady.Add(1) secondGroupDone.Add(1) go func() { secondGroupReady.Done() r.enter() r.exit() secondGroupDone.Done() }() } secondGroupReady.Wait() // allow the first group to return resources close(run) done := make(chan struct{}) go func() { secondGroupDone.Wait() close(done) }() select { case <-done: case <-time.After(5 * time.Second): t.Fatal("some r.enter() are still locked") } firstGroupDone.Wait() if r.available != limit { t.Fatalf("r.available: got %d, want %d", r.available, limit) } } } func TestGetLimitFromParameter(t *testing.T) { tests := []struct { Input interface{} Expected uint64 Min uint64 Default uint64 Err error }{ {"foo", 0, 5, 5, fmt.Errorf("parameter must be an integer, 'foo' invalid")}, {"50", 50, 5, 5, nil}, {"5", 25, 25, 50, nil}, // lower than Min returns Min {nil, 50, 25, 50, nil}, // nil returns default {812, 812, 25, 50, nil}, } for _, item := range tests { t.Run(fmt.Sprint(item.Input), func(t *testing.T) { actual, err := GetLimitFromParameter(item.Input, item.Min, item.Default) if err != nil && item.Err != nil && err.Error() != item.Err.Error() { t.Fatalf("GetLimitFromParameter error, expected %#v got %#v", item.Err, err) } if actual != item.Expected { t.Fatalf("GetLimitFromParameter result error, expected %d got %d", item.Expected, actual) } }) } }