func TestHttpGunWithHttp(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() result := make(chan *aggregate.Sample) requests := make(chan *http.Request) ts := httptest.NewServer( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Hello, client") go func() { requests <- r }() })) defer ts.Close() gun := &HttpGun{ target: ts.Listener.Addr().String(), ssl: false, results: result, } promise := utils.Promise(func() error { defer close(result) return gun.Shoot(ctx, &ammo.Http{ Host: "example.org", Method: "GET", Uri: "/path", Headers: map[string]string{ "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Host": "example.org", "User-Agent": "Pandora/0.0.1", }, }) }) results := aggregate.Drain(ctx, result) require.Len(t, results, 1) assert.Equal(t, "REQUEST", results[0].Tag) assert.Equal(t, 200, results[0].ProtoCode) select { case r := <-requests: assert.Equal(t, "GET", r.Method) assert.Equal(t, "example.org", r.Host) assert.Equal(t, "/path", r.URL.Path) assert.Equal(t, "Pandora/0.0.1", r.Header.Get("User-Agent")) case <-ctx.Done(): t.Fatal(ctx.Err()) } // TODO: test scenaries with errors select { case err := <-promise: require.NoError(t, err) case <-ctx.Done(): t.Fatal(ctx.Err()) } }
func TestSpdyGun(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() result := make(chan aggregate.Sample) gun := &SpdyGun{ target: "localhost:3000", pingPeriod: time.Second * 5, } promise := utils.Promise(func() error { defer close(result) return gun.Shoot(ctx, &ammo.Http{ Host: "example.org", Method: "GET", Uri: "/path", Headers: map[string]string{ "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Host": "example.org", "User-Agent": "Pandora/0.0.1", }, }, result) }) results := aggregate.Drain(ctx, result) require.Len(t, results, 2) { // first result is connect rPhout, casted := (results[0]).(aggregate.PhantomCompatible) require.True(t, casted, "Should be phantom compatible") phoutSample := rPhout.PhoutSample() assert.Equal(t, "CONNECT", phoutSample.Tag) assert.Equal(t, 200, phoutSample.ProtoCode) } { // second result is request rPhout, casted := (results[1]).(aggregate.PhantomCompatible) require.True(t, casted, "Should be phantom compatible") phoutSample := rPhout.PhoutSample() spew.Dump(phoutSample) assert.Equal(t, "REQUEST", phoutSample.Tag) assert.Equal(t, 200, phoutSample.ProtoCode) } // TODO: test scenaries with errors // TODO: test ping logic select { case err := <-promise: require.NoError(t, err) case <-ctx.Done(): t.Fatal(ctx.Err()) } }
func Run() { fmt.Printf("Pandora v0.1.1\n") flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage of Pandora: pandora [<config_filename>]\n"+ "<config_filename> is './load.json' by default\n") flag.PrintDefaults() } example := flag.Bool("example", false, "print example config to STDOUT and exit") flag.Parse() if *example { fmt.Printf(exampleConfig) return } configFileName := "./load.json" if len(flag.Args()) > 0 { configFileName = flag.Args()[0] } log.Printf("Reading config from '%s'...\n", configFileName) jsonDoc, err := ioutil.ReadFile(configFileName) if err != nil { log.Printf("Could not read config from file: %s", err) return } cfg, err := config.NewGlobalFromJSON(jsonDoc) if err != nil { log.Printf("Could not unmarshal config from json: %s", err) return } pandora := engine.New(cfg) ctx, cancel := context.WithCancel(context.Background()) defer cancel() promise := utils.Promise(func() error { return pandora.Serve(ctx) }) select { case <-utils.NotifyInterrupt(): log.Print("Interrupting by signal, trying to stop") cancel() select { case err = <-promise: case <-time.After(time.Second * 5): err = fmt.Errorf("timeout exceeded") } case err = <-promise: } if err != nil { log.Fatal(err) } }
func TestSpdyGun(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() result := make(chan *aggregate.Sample) gun := &SpdyGun{ target: "localhost:3000", results: result, } promise := utils.Promise(func() error { defer gun.Close() defer close(result) return gun.Shoot(ctx, &ammo.Http{ Host: "example.org", Method: "GET", Uri: "/path", Headers: map[string]string{ "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Host": "example.org", "User-Agent": "Pandora/0.0.1", }, }) }) results := aggregate.Drain(ctx, result) require.Len(t, results, 2) { // first result is connect assert.Equal(t, "CONNECT", results[0].Tag) assert.Equal(t, 200, results[0].ProtoCode) } { // second result is request assert.Equal(t, "REQUEST", results[1].Tag) assert.Equal(t, 200, results[1].ProtoCode) } // TODO: test scenaries with errors select { case err := <-promise: require.NoError(t, err) case <-ctx.Done(): t.Fatal(ctx.Err()) } }
func TestSpdyConnectPing(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() result := make(chan *aggregate.Sample) gun := &SpdyGun{ target: "localhost:3000", results: result, } promise := utils.Promise(func() error { defer gun.Close() defer close(result) if err := gun.Connect(); err != nil { return err } gun.Ping() return nil }) results := aggregate.Drain(ctx, result) require.Len(t, results, 2) { // first result is connect assert.Equal(t, "CONNECT", results[0].Tag) assert.Equal(t, 200, results[0].ProtoCode) } { // second result is PING assert.Equal(t, "PING", results[1].Tag) assert.Equal(t, 200, results[1].ProtoCode) } select { case err := <-promise: require.NoError(t, err) case <-ctx.Done(): t.Fatal(ctx.Err()) } }
func Run() { fmt.Printf("Pandora v%s\n", Version) flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage of Pandora: pandora [<config_filename>]\n"+ "<config_filename> is './load.json' by default\n") flag.PrintDefaults() } example := flag.Bool("example", false, "print example config to STDOUT and exit") cpuprofile := flag.String("cpuprofile", "", "write cpu profile to file") memprofile := flag.String("memprofile", "", "write memory profile to this file") expvarHttp := flag.Bool("expvar", false, "start HTTP server with monitoring variables") flag.Parse() if *example { fmt.Printf(exampleConfig) return } if *expvarHttp { go http.ListenAndServe(":1234", nil) } configFileName := "./load.json" if len(flag.Args()) > 0 { configFileName = flag.Args()[0] } log.Printf("Reading config from '%s'...\n", configFileName) jsonDoc, err := ioutil.ReadFile(configFileName) if err != nil { log.Printf("Could not read config from file: %s", err) return } cfg, err := config.NewGlobalFromJSON(jsonDoc) if err != nil { log.Printf("Could not unmarshal config from json: %s", err) return } if *cpuprofile != "" { f, err := os.Create(*cpuprofile) if err != nil { log.Fatal(err) } pprof.StartCPUProfile(f) defer pprof.StopCPUProfile() } if *memprofile != "" { defer func() { f, err := os.Create(*memprofile) if err != nil { log.Fatal(err) } pprof.WriteHeapProfile(f) f.Close() }() } pandora := engine.New(cfg) ctx, cancel := context.WithCancel(context.Background()) defer cancel() promise := utils.Promise(func() error { return pandora.Serve(ctx) }) select { case <-utils.NotifyInterrupt(): log.Print("Interrupting by signal, trying to stop") cancel() select { case err = <-promise: case <-time.After(time.Second * 5): err = fmt.Errorf("timeout exceeded") } case err = <-promise: } if err != nil { log.Fatal(err) } }