func TestRepeatSim(t *testing.T) { clk := loadsim.NewSimClock() req, err := http.NewRequest("GET", "", nil) if err != nil { log.Fatal(err) } agents := []loadsim.Agent{ &loadsim.RepeatAgent{ BaseRequest: req, Clock: clk, }, } worker := makeSimWorker(clk) stop := make(chan struct{}) resCh := loadsim.Simulate(agents, worker, clk, 10*time.Second) go clk.Run(stop) results := collectResults(resCh)[""] close(stop) if err := assertStatus(results, http.StatusOK); err != nil { t.Error(err) } if err := assertWorkDurations(results, 100*time.Millisecond, time.Millisecond); err != nil { t.Error(err) } count := len(results) if count < 99 || count > 101 { t.Errorf("expected 99-101 requests, got %d", count) } }
func TestHTTP(t *testing.T) { var clk loadsim.WallClock server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { time.Sleep(100 * time.Millisecond) v := r.FormValue("a") switch v { case "1": w.WriteHeader(1) case "2": w.WriteHeader(2) default: t.Fatalf("unexpected or missing value for GET parameter `a`: %q", v) } })) req1, err := http.NewRequest("GET", server.URL+"?a=1", nil) if err != nil { log.Fatal(err) } req2, err := http.NewRequest("GET", server.URL+"?a=2", nil) if err != nil { log.Fatal(err) } agents := []loadsim.Agent{ &loadsim.RepeatAgent{ BaseRequest: req1, Clock: &clk, ID: "repeat", }, &loadsim.IntervalAgent{ BaseRequest: req2, Clock: &clk, Interval: time.Millisecond * 51, ID: "interval", }, } expectations := map[string]struct { Code, Count int }{ "repeat": {1, 3}, "interval": {2, 6}, } counts := make(map[string]int, len(agents)) durations := make(map[string][]time.Duration, len(agents)) worker := &loadsim.HTTPWorker{ Clock: &clk, } results := loadsim.Simulate(agents, worker, &clk, 290*time.Millisecond) for res := range results { id := res.AgentID if want, have := expectations[id].Code, res.StatusCode; want != have { t.Errorf("%s: expected status %d, got %d", id, want, have) } counts[id]++ durations[id] = append(durations[id], res.End.Sub(res.Start)) } for id, have := range counts { want := expectations[id].Count if have != want { t.Errorf("%s: expected %d requests, got %d (%v)", id, want, have, durations[id]) } } }
func TestPoolSim(t *testing.T) { clk := loadsim.NewSimClock() req, err := http.NewRequest("GET", "", nil) if err != nil { log.Fatal(err) } agents := []loadsim.Agent{ &loadsim.RepeatAgent{ BaseRequest: req, Clock: clk, ID: "repeat1", }, &loadsim.RepeatAgent{ BaseRequest: req, Clock: clk, ID: "repeat2", }, &loadsim.IntervalAgent{ BaseRequest: req, Clock: clk, Interval: 510 * time.Millisecond, ID: "interval", }, } worker := &loadsim.WorkerPool{ Backlog: 10, Timeout: 200 * time.Millisecond, Workers: []loadsim.Worker{makeSimWorker(clk), makeSimWorker(clk)}, Clock: clk, } stop := make(chan struct{}) resCh := loadsim.Simulate(agents, worker, clk, 10*time.Second) go clk.Run(stop) agentResults := collectResults(resCh) close(stop) for id, results := range agentResults { if err := assertStatus(results, http.StatusOK); err != nil { t.Errorf("%s: %s", id, err) } if err := assertWorkDurations(results, 100*time.Millisecond, time.Millisecond); err != nil { t.Errorf("%s: %s", id, err) } count := len(results) switch id { case "repeat1", "repeat2": if count < 85 || count > 95 { t.Errorf("%s: expected 85-95 requests, got %d", id, count) } case "interval": if count != 20 { t.Errorf("%s: expected 20 requests, got %d", id, count) } } } }
func httpRun(cfg WorkerConfig, agents []loadsim.Agent, clk loadsim.Clock) []loadsim.Result { resultCh := loadsim.Simulate(agents, &loadsim.HTTPWorker{ Clock: clk, }, clk, cfg.Duration) return collect(resultCh) }
func simRun(cfg WorkerConfig, agents []loadsim.Agent, clk loadsim.Clock) []loadsim.Result { var workers []loadsim.Worker var allResources []loadsim.Resource simClk := clk.(*loadsim.SimClock) var limiter loadsim.Limiter if cfg.WallClockRate > 0 { var err error limiter, err = loadsim.NewWallClockLimiter(cfg.WallClockBurst, cfg.WallClockRate, clk) if err != nil { panic(err) } } for host := 0; host < cfg.Hosts; host++ { cpu := &loadsim.CPUResource{Count: cfg.CPUs} allResources = append(allResources, cpu) for proc := 0; proc < cfg.Workers; proc++ { time := &loadsim.TimeResource{} allResources = append(allResources, time) workerResources := []loadsim.Resource{cpu, time} var worker loadsim.Worker worker = &loadsim.SimWorker{ ResourceMapper: cfg.ResourceMapper, Resources: workerResources, Clock: clk, Limiter: limiter, } if len(cfg.RequestOverhead) > 0 { worker = &loadsim.WorkerOverhead{ Worker: worker, Clock: clk, Resources: workerResources, Needs: cfg.RequestOverhead, } } workers = append(workers, worker) } } worker := loadsim.WorkerPool{ Backlog: cfg.Backlog, Timeout: cfg.Timeout, Workers: workers, Clock: clk, } stop := make(chan struct{}) simClk.Hook = func() { for _, res := range allResources { res.Reset() } } resultCh := loadsim.Simulate(agents, &worker, clk, cfg.Duration) go simClk.Run(stop) results := collect(resultCh) close(stop) return results }