diff options
Diffstat (limited to 'plugins/http/plugin_test.go')
-rw-r--r-- | plugins/http/plugin_test.go | 759 |
1 files changed, 759 insertions, 0 deletions
diff --git a/plugins/http/plugin_test.go b/plugins/http/plugin_test.go new file mode 100644 index 00000000..f7ee33cc --- /dev/null +++ b/plugins/http/plugin_test.go @@ -0,0 +1,759 @@ +package http + +import ( + "github.com/cenkalti/backoff/v4" + json "github.com/json-iterator/go" + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" + "github.com/spiral/roadrunner" + "github.com/spiral/roadrunner/service" + "github.com/spiral/roadrunner/service/env" + "github.com/spiral/roadrunner/service/rpc" + "github.com/stretchr/testify/assert" + "io/ioutil" + "net/http" + "os" + "testing" + "time" +) + +type testCfg struct { + httpCfg string + rpcCfg string + envCfg string + target string +} + +func (cfg *testCfg) Get(name string) service.Config { + if name == ID { + if cfg.httpCfg == "" { + return nil + } + + return &testCfg{target: cfg.httpCfg} + } + + if name == rpc.ID { + return &testCfg{target: cfg.rpcCfg} + } + + if name == env.ID { + return &testCfg{target: cfg.envCfg} + } + + return nil +} +func (cfg *testCfg) Unmarshal(out interface{}) error { + j := json.ConfigCompatibleWithStandardLibrary + return j.Unmarshal([]byte(cfg.target), out) +} + +func Test_Service_NoConfig(t *testing.T) { + logger, _ := test.NewNullLogger() + logger.SetLevel(logrus.DebugLevel) + + c := service.NewContainer(logger) + c.Register(ID, &Service{}) + + err := c.Init(&testCfg{httpCfg: `{"Enable":true}`}) + assert.Error(t, err) + + s, st := c.Get(ID) + assert.NotNil(t, s) + assert.Equal(t, service.StatusInactive, st) +} + +func Test_Service_Configure_Disable(t *testing.T) { + logger, _ := test.NewNullLogger() + logger.SetLevel(logrus.DebugLevel) + + c := service.NewContainer(logger) + c.Register(ID, &Service{}) + + assert.NoError(t, c.Init(&testCfg{})) + + s, st := c.Get(ID) + assert.NotNil(t, s) + assert.Equal(t, service.StatusInactive, st) +} + +func Test_Service_Configure_Enable(t *testing.T) { + bkoff := backoff.NewExponentialBackOff() + bkoff.MaxElapsedTime = time.Second * 15 + + err := backoff.Retry(func() error { + logger, _ := test.NewNullLogger() + logger.SetLevel(logrus.DebugLevel) + + c := service.NewContainer(logger) + c.Register(ID, &Service{}) + + err := c.Init(&testCfg{httpCfg: `{ + "enable": true, + "address": ":8070", + "maxRequestSize": 1024, + "uploads": { + "dir": ` + tmpDir() + `, + "forbid": [] + }, + "workers":{ + "command": "php ../../tests/http/client.php echo pipes", + "relay": "pipes", + "pool": { + "numWorkers": 1, + "allocateTimeout": 10000000, + "destroyTimeout": 10000000 + } + } + }`}) + if err != nil { + return err + } + + s, st := c.Get(ID) + assert.NotNil(t, s) + assert.Equal(t, service.StatusOK, st) + + return nil + }, bkoff) + + if err != nil { + t.Fatal(err) + } + +} + +func Test_Service_Echo(t *testing.T) { + bkoff := backoff.NewExponentialBackOff() + bkoff.MaxElapsedTime = time.Second * 15 + + err := backoff.Retry(func() error { + logger, _ := test.NewNullLogger() + logger.SetLevel(logrus.DebugLevel) + + c := service.NewContainer(logger) + c.Register(ID, &Service{}) + + err := c.Init(&testCfg{httpCfg: `{ + "enable": true, + "address": ":6536", + "maxRequestSize": 1024, + "uploads": { + "dir": ` + tmpDir() + `, + "forbid": [] + }, + "workers":{ + "command": "php ../../tests/http/client.php echo pipes", + "relay": "pipes", + "pool": { + "numWorkers": 1, + "allocateTimeout": 10000000, + "destroyTimeout": 10000000 + } + } + }`}) + if err != nil { + return err + } + + s, st := c.Get(ID) + assert.NotNil(t, s) + assert.Equal(t, service.StatusOK, st) + + // should do nothing + s.(*Service).Stop() + + go func() { + err := c.Serve() + if err != nil { + t.Errorf("serve error: %v", err) + } + }() + + time.Sleep(time.Millisecond * 100) + + req, err := http.NewRequest("GET", "http://localhost:6536?hello=world", nil) + if err != nil { + c.Stop() + return err + } + + r, err := http.DefaultClient.Do(req) + if err != nil { + c.Stop() + return err + } + b, err := ioutil.ReadAll(r.Body) + if err != nil { + c.Stop() + return err + } + assert.Equal(t, 201, r.StatusCode) + assert.Equal(t, "WORLD", string(b)) + + err = r.Body.Close() + if err != nil { + c.Stop() + return err + } + + c.Stop() + return nil + }, bkoff) + + if err != nil { + t.Fatal(err) + } +} + +func Test_Service_Env(t *testing.T) { + bkoff := backoff.NewExponentialBackOff() + bkoff.MaxElapsedTime = time.Second * 15 + + err := backoff.Retry(func() error { + logger, _ := test.NewNullLogger() + logger.SetLevel(logrus.DebugLevel) + + c := service.NewContainer(logger) + c.Register(env.ID, env.NewService(map[string]string{"rr": "test"})) + c.Register(ID, &Service{}) + + err := c.Init(&testCfg{httpCfg: `{ + "enable": true, + "address": ":10031", + "maxRequestSize": 1024, + "uploads": { + "dir": ` + tmpDir() + `, + "forbid": [] + }, + "workers":{ + "command": "php ../../tests/http/client.php env pipes", + "relay": "pipes", + "pool": { + "numWorkers": 1, + "allocateTimeout": 10000000, + "destroyTimeout": 10000000 + } + } + }`, envCfg: `{"env_key":"ENV_VALUE"}`}) + if err != nil { + return err + } + + s, st := c.Get(ID) + assert.NotNil(t, s) + assert.Equal(t, service.StatusOK, st) + + // should do nothing + s.(*Service).Stop() + + go func() { + err := c.Serve() + if err != nil { + t.Errorf("serve error: %v", err) + } + }() + + time.Sleep(time.Millisecond * 500) + + req, err := http.NewRequest("GET", "http://localhost:10031", nil) + if err != nil { + c.Stop() + return err + } + + r, err := http.DefaultClient.Do(req) + if err != nil { + c.Stop() + return err + } + + b, err := ioutil.ReadAll(r.Body) + if err != nil { + c.Stop() + return err + } + + assert.Equal(t, 200, r.StatusCode) + assert.Equal(t, "ENV_VALUE", string(b)) + + err = r.Body.Close() + if err != nil { + c.Stop() + return err + } + + c.Stop() + return nil + }, bkoff) + + if err != nil { + t.Fatal(err) + } + +} + +func Test_Service_ErrorEcho(t *testing.T) { + bkoff := backoff.NewExponentialBackOff() + bkoff.MaxElapsedTime = time.Second * 15 + + err := backoff.Retry(func() error { + logger, _ := test.NewNullLogger() + logger.SetLevel(logrus.DebugLevel) + + c := service.NewContainer(logger) + c.Register(ID, &Service{}) + + err := c.Init(&testCfg{httpCfg: `{ + "enable": true, + "address": ":6030", + "maxRequestSize": 1024, + "uploads": { + "dir": ` + tmpDir() + `, + "forbid": [] + }, + "workers":{ + "command": "php ../../tests/http/client.php echoerr pipes", + "relay": "pipes", + "pool": { + "numWorkers": 1, + "allocateTimeout": 10000000, + "destroyTimeout": 10000000 + } + } + }`}) + if err != nil { + return err + } + + s, st := c.Get(ID) + assert.NotNil(t, s) + assert.Equal(t, service.StatusOK, st) + + goterr := make(chan interface{}) + s.(*Service).AddListener(func(event int, ctx interface{}) { + if event == roadrunner.EventStderrOutput { + if string(ctx.([]byte)) == "WORLD\n" { + goterr <- nil + } + } + }) + + go func() { + err := c.Serve() + if err != nil { + t.Errorf("serve error: %v", err) + } + }() + + time.Sleep(time.Millisecond * 500) + + req, err := http.NewRequest("GET", "http://localhost:6030?hello=world", nil) + if err != nil { + c.Stop() + return err + } + + r, err := http.DefaultClient.Do(req) + if err != nil { + c.Stop() + return err + } + + b, err := ioutil.ReadAll(r.Body) + if err != nil { + c.Stop() + return err + } + + <-goterr + + assert.Equal(t, 201, r.StatusCode) + assert.Equal(t, "WORLD", string(b)) + err = r.Body.Close() + if err != nil { + c.Stop() + return err + } + + c.Stop() + + return nil + }, bkoff) + + if err != nil { + t.Fatal(err) + } +} + +func Test_Service_Middleware(t *testing.T) { + bkoff := backoff.NewExponentialBackOff() + bkoff.MaxElapsedTime = time.Second * 15 + + err := backoff.Retry(func() error { + logger, _ := test.NewNullLogger() + logger.SetLevel(logrus.DebugLevel) + + c := service.NewContainer(logger) + c.Register(ID, &Service{}) + + err := c.Init(&testCfg{httpCfg: `{ + "enable": true, + "address": ":6032", + "maxRequestSize": 1024, + "uploads": { + "dir": ` + tmpDir() + `, + "forbid": [] + }, + "workers":{ + "command": "php ../../tests/http/client.php echo pipes", + "relay": "pipes", + "pool": { + "numWorkers": 1, + "allocateTimeout": 10000000, + "destroyTimeout": 10000000 + } + } + }`}) + if err != nil { + return err + } + + s, st := c.Get(ID) + assert.NotNil(t, s) + assert.Equal(t, service.StatusOK, st) + + s.(*Service).AddMiddleware(func(f http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/halt" { + w.WriteHeader(500) + _, err := w.Write([]byte("halted")) + if err != nil { + t.Errorf("error writing the data to the http reply: error %v", err) + } + } else { + f(w, r) + } + } + }) + + go func() { + err := c.Serve() + if err != nil { + t.Errorf("serve error: %v", err) + } + }() + time.Sleep(time.Millisecond * 500) + + req, err := http.NewRequest("GET", "http://localhost:6032?hello=world", nil) + if err != nil { + c.Stop() + return err + } + + r, err := http.DefaultClient.Do(req) + if err != nil { + c.Stop() + return err + } + + b, err := ioutil.ReadAll(r.Body) + if err != nil { + c.Stop() + return err + } + + assert.Equal(t, 201, r.StatusCode) + assert.Equal(t, "WORLD", string(b)) + + err = r.Body.Close() + if err != nil { + c.Stop() + return err + } + + req, err = http.NewRequest("GET", "http://localhost:6032/halt", nil) + if err != nil { + c.Stop() + return err + } + + r, err = http.DefaultClient.Do(req) + if err != nil { + c.Stop() + return err + } + b, err = ioutil.ReadAll(r.Body) + if err != nil { + c.Stop() + return err + } + + assert.Equal(t, 500, r.StatusCode) + assert.Equal(t, "halted", string(b)) + + err = r.Body.Close() + if err != nil { + c.Stop() + return err + } + c.Stop() + + return nil + }, bkoff) + + if err != nil { + t.Fatal(err) + } + +} + +func Test_Service_Listener(t *testing.T) { + bkoff := backoff.NewExponentialBackOff() + bkoff.MaxElapsedTime = time.Second * 15 + + err := backoff.Retry(func() error { + logger, _ := test.NewNullLogger() + logger.SetLevel(logrus.DebugLevel) + + c := service.NewContainer(logger) + c.Register(ID, &Service{}) + + err := c.Init(&testCfg{httpCfg: `{ + "enable": true, + "address": ":6033", + "maxRequestSize": 1024, + "uploads": { + "dir": ` + tmpDir() + `, + "forbid": [] + }, + "workers":{ + "command": "php ../../tests/http/client.php echo pipes", + "relay": "pipes", + "pool": { + "numWorkers": 1, + "allocateTimeout": 10000000, + "destroyTimeout": 10000000 + } + } + }`}) + if err != nil { + return err + } + + s, st := c.Get(ID) + assert.NotNil(t, s) + assert.Equal(t, service.StatusOK, st) + + stop := make(chan interface{}) + s.(*Service).AddListener(func(event int, ctx interface{}) { + if event == roadrunner.EventServerStart { + stop <- nil + } + }) + + go func() { + err := c.Serve() + if err != nil { + t.Errorf("serve error: %v", err) + } + }() + time.Sleep(time.Millisecond * 500) + + c.Stop() + assert.True(t, true) + + return nil + }, bkoff) + + if err != nil { + t.Fatal(err) + } +} + +func Test_Service_Error(t *testing.T) { + bkoff := backoff.NewExponentialBackOff() + bkoff.MaxElapsedTime = time.Second * 15 + + err := backoff.Retry(func() error { + logger, _ := test.NewNullLogger() + logger.SetLevel(logrus.DebugLevel) + + c := service.NewContainer(logger) + c.Register(ID, &Service{}) + + err := c.Init(&testCfg{httpCfg: `{ + "enable": true, + "address": ":6034", + "maxRequestSize": 1024, + "uploads": { + "dir": ` + tmpDir() + `, + "forbid": [] + }, + "workers":{ + "command": "php ../../tests/http/client.php echo pipes", + "relay": "---", + "pool": { + "numWorkers": 1, + "allocateTimeout": 10000000, + "destroyTimeout": 10000000 + } + } + }`}) + if err != nil { + return err + } + + // assert error + err = c.Serve() + if err == nil { + return err + } + + return nil + }, bkoff) + + if err != nil { + t.Fatal(err) + } +} + +func Test_Service_Error2(t *testing.T) { + bkoff := backoff.NewExponentialBackOff() + bkoff.MaxElapsedTime = time.Second * 15 + + err := backoff.Retry(func() error { + logger, _ := test.NewNullLogger() + logger.SetLevel(logrus.DebugLevel) + + c := service.NewContainer(logger) + c.Register(ID, &Service{}) + + err := c.Init(&testCfg{httpCfg: `{ + "enable": true, + "address": ":6035", + "maxRequestSize": 1024, + "uploads": { + "dir": ` + tmpDir() + `, + "forbid": [] + }, + "workers":{ + "command": "php ../../tests/http/client.php broken pipes", + "relay": "pipes", + "pool": { + "numWorkers": 1, + "allocateTimeout": 10000000, + "destroyTimeout": 10000000 + } + } + }`}) + if err != nil { + return err + } + + // assert error + err = c.Serve() + if err == nil { + return err + } + + return nil + }, bkoff) + + if err != nil { + t.Fatal(err) + } +} + +func Test_Service_Error3(t *testing.T) { + bkoff := backoff.NewExponentialBackOff() + bkoff.MaxElapsedTime = time.Second * 15 + + err := backoff.Retry(func() error { + logger, _ := test.NewNullLogger() + logger.SetLevel(logrus.DebugLevel) + + c := service.NewContainer(logger) + c.Register(ID, &Service{}) + + err := c.Init(&testCfg{httpCfg: `{ + "enable": true, + "address": ":6036", + "maxRequestSize": 1024, + "uploads": { + "dir": ` + tmpDir() + `, + "forbid": [] + }, + "workers" + "command": "php ../../tests/http/client.php broken pipes", + "relay": "pipes", + "pool": { + "numWorkers": 1, + "allocateTimeout": 10000000, + "destroyTimeout": 10000000 + } + } + }`}) + // assert error + if err == nil { + return err + } + + return nil + }, bkoff) + + if err != nil { + t.Fatal(err) + } + +} + +func Test_Service_Error4(t *testing.T) { + bkoff := backoff.NewExponentialBackOff() + bkoff.MaxElapsedTime = time.Second * 15 + + err := backoff.Retry(func() error { + logger, _ := test.NewNullLogger() + logger.SetLevel(logrus.DebugLevel) + + c := service.NewContainer(logger) + c.Register(ID, &Service{}) + + err := c.Init(&testCfg{httpCfg: `{ + "enable": true, + "address": "----", + "maxRequestSize": 1024, + "uploads": { + "dir": ` + tmpDir() + `, + "forbid": [] + }, + "workers":{ + "command": "php ../../tests/http/client.php broken pipes", + "relay": "pipes", + "pool": { + "numWorkers": 1, + "allocateTimeout": 10000000, + "destroyTimeout": 10000000 + } + } + }`}) + // assert error + if err != nil { + return nil + } + + return err + }, bkoff) + + if err != nil { + t.Fatal(err) + } +} + +func tmpDir() string { + p := os.TempDir() + j := json.ConfigCompatibleWithStandardLibrary + r, _ := j.Marshal(p) + + return string(r) +} |