summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/rr/cmd/root.go2
-rw-r--r--php-src/tests/http/echo.php2
-rw-r--r--service/container.go4
-rw-r--r--service/container_test.go18
-rw-r--r--service/http/config_test.go2
-rw-r--r--service/http/handler_test.go2
-rw-r--r--service/http/request.go6
-rw-r--r--service/http/service.go9
-rw-r--r--service/http/service_test.go159
9 files changed, 185 insertions, 19 deletions
diff --git a/cmd/rr/cmd/root.go b/cmd/rr/cmd/root.go
index e31eb332..bea42747 100644
--- a/cmd/rr/cmd/root.go
+++ b/cmd/rr/cmd/root.go
@@ -88,7 +88,7 @@ func init() {
}
if cfg := initConfig(cfgFile, []string{"."}, ".rr"); cfg != nil {
- if err := Container.Configure(cfg); err != nil {
+ if err := Container.Init(cfg); err != nil {
utils.Printf("<red+hb>Error:</reset> <red>%s</reset>\n", err)
os.Exit(1)
}
diff --git a/php-src/tests/http/echo.php b/php-src/tests/http/echo.php
index eeccc7e5..7004ada0 100644
--- a/php-src/tests/http/echo.php
+++ b/php-src/tests/http/echo.php
@@ -6,5 +6,5 @@ use \Psr\Http\Message\ResponseInterface;
function handleRequest(ServerRequestInterface $req, ResponseInterface $resp): ResponseInterface
{
$resp->getBody()->write(strtoupper($req->getQueryParams()['hello']));
- return $resp;
+ return $resp->withStatus(201);
} \ No newline at end of file
diff --git a/service/container.go b/service/container.go
index 7c7633e7..ce9146bc 100644
--- a/service/container.go
+++ b/service/container.go
@@ -23,7 +23,7 @@ type Container interface {
Register(name string, service Service)
// Reconfigure configures all underlying services with given configuration.
- Configure(cfg Config) error
+ Init(cfg Config) error
// Check if svc has been registered.
Has(service string) bool
@@ -96,7 +96,7 @@ func (c *container) Get(target string) (svc Service, status int) {
}
// Init configures all underlying services with given configuration.
-func (c *container) Configure(cfg Config) error {
+func (c *container) Init(cfg Config) error {
for _, e := range c.services {
if e.getStatus() >= StatusConfigured {
return fmt.Errorf("service [%s] has already been configured", e.name)
diff --git a/service/container_test.go b/service/container_test.go
index 58dd9dde..3c2f8761 100644
--- a/service/container_test.go
+++ b/service/container_test.go
@@ -140,7 +140,7 @@ func TestContainer_Configure(t *testing.T) {
c.Register("test", svc)
assert.Equal(t, 1, len(hook.Entries))
- assert.NoError(t, c.Configure(&testCfg{`{"test":"something"}`}))
+ assert.NoError(t, c.Init(&testCfg{`{"test":"something"}`}))
s, st := c.Get("test")
assert.IsType(t, &testService{}, s)
@@ -157,7 +157,7 @@ func TestContainer_ConfigureNull(t *testing.T) {
c.Register("test", svc)
assert.Equal(t, 1, len(hook.Entries))
- assert.NoError(t, c.Configure(&testCfg{`{"another":"something"}`}))
+ assert.NoError(t, c.Init(&testCfg{`{"another":"something"}`}))
assert.Equal(t, 2, len(hook.Entries))
s, st := c.Get("test")
@@ -175,7 +175,7 @@ func TestContainer_ConfigureDisabled(t *testing.T) {
c.Register("test", svc)
assert.Equal(t, 1, len(hook.Entries))
- assert.NoError(t, c.Configure(&testCfg{`{"test":"something"}`}))
+ assert.NoError(t, c.Init(&testCfg{`{"test":"something"}`}))
assert.Equal(t, 1, len(hook.Entries))
s, st := c.Get("test")
@@ -196,7 +196,7 @@ func TestContainer_ConfigureError(t *testing.T) {
c.Register("test", svc)
assert.Equal(t, 1, len(hook.Entries))
- err := c.Configure(&testCfg{`{"test":"something"}`})
+ err := c.Init(&testCfg{`{"test":"something"}`})
assert.Error(t, err)
assert.Contains(t, err.Error(), "configure error")
assert.Contains(t, err.Error(), "test")
@@ -216,8 +216,8 @@ func TestContainer_ConfigureTwice(t *testing.T) {
c.Register("test", svc)
assert.Equal(t, 1, len(hook.Entries))
- assert.NoError(t, c.Configure(&testCfg{`{"test":"something"}`}))
- assert.Error(t, c.Configure(&testCfg{`{"test":"something"}`}))
+ assert.NoError(t, c.Init(&testCfg{`{"test":"something"}`}))
+ assert.Error(t, c.Init(&testCfg{`{"test":"something"}`}))
}
func TestContainer_ServeEmptyContainer(t *testing.T) {
@@ -246,7 +246,7 @@ func TestContainer_Serve(t *testing.T) {
c := NewContainer(logger)
c.Register("test", svc)
assert.Equal(t, 1, len(hook.Entries))
- assert.NoError(t, c.Configure(&testCfg{`{"test":"something"}`}))
+ assert.NoError(t, c.Init(&testCfg{`{"test":"something"}`}))
go func() {
assert.NoError(t, c.Serve())
@@ -278,7 +278,7 @@ func TestContainer_ServeError(t *testing.T) {
c := NewContainer(logger)
c.Register("test", svc)
assert.Equal(t, 1, len(hook.Entries))
- assert.NoError(t, c.Configure(&testCfg{`{"test":"something"}`}))
+ assert.NoError(t, c.Init(&testCfg{`{"test":"something"}`}))
err := c.Serve()
assert.Error(t, err)
@@ -310,7 +310,7 @@ func TestContainer_ServeErrorMultiple(t *testing.T) {
c.Register("test2", svc2)
c.Register("test", svc)
assert.Equal(t, 2, len(hook.Entries))
- assert.NoError(t, c.Configure(&testCfg{`{"test":"something", "test2":"something-else"}`}))
+ assert.NoError(t, c.Init(&testCfg{`{"test":"something", "test2":"something-else"}`}))
err := c.Serve()
assert.Error(t, err)
diff --git a/service/http/config_test.go b/service/http/config_test.go
index 18e8ab3e..b806b79b 100644
--- a/service/http/config_test.go
+++ b/service/http/config_test.go
@@ -64,7 +64,7 @@ func Test_Config_NoWorkers(t *testing.T) {
assert.Error(t, cfg.Valid())
}
-func Test_Confi_InvalidAddress(t *testing.T) {
+func Test_Config_InvalidAddress(t *testing.T) {
cfg := &Config{
Enable: true,
Address: "",
diff --git a/service/http/handler_test.go b/service/http/handler_test.go
index 0e236df0..98379117 100644
--- a/service/http/handler_test.go
+++ b/service/http/handler_test.go
@@ -58,7 +58,7 @@ func TestServer_Echo(t *testing.T) {
body, r, err := get("http://localhost:8077/?hello=world")
assert.NoError(t, err)
- assert.Equal(t, 200, r.StatusCode)
+ assert.Equal(t, 201, r.StatusCode)
assert.Equal(t, "WORLD", body)
}
diff --git a/service/http/request.go b/service/http/request.go
index 80998b11..e02d3cdb 100644
--- a/service/http/request.go
+++ b/service/http/request.go
@@ -12,7 +12,7 @@ import (
const (
defaultMaxMemory = 32 << 20 // 32 MB
contentNone = iota + 900
- contentUndefined
+ contentStream
contentMultipart
contentFormData
)
@@ -66,7 +66,7 @@ func NewRequest(r *http.Request, cfg *UploadsConfig) (req *Request, err error) {
case contentNone:
return req, nil
- case contentUndefined:
+ case contentStream:
req.body, err = ioutil.ReadAll(r.Body)
return req, err
@@ -142,7 +142,7 @@ func (r *Request) contentType() int {
return contentMultipart
}
- return contentUndefined
+ return contentStream
}
// uri fetches full uri from request in a form of string (including https scheme if TLS connection is enabled).
diff --git a/service/http/service.go b/service/http/service.go
index 881c862d..2b30cd1c 100644
--- a/service/http/service.go
+++ b/service/http/service.go
@@ -6,6 +6,7 @@ import (
"context"
"github.com/spiral/roadrunner"
"github.com/spiral/roadrunner/service/rpc"
+ "sync"
)
// Name contains default svc name.
@@ -18,8 +19,10 @@ type middleware func(w http.ResponseWriter, r *http.Request) bool
type Service struct {
cfg *Config
lsns []func(event int, ctx interface{})
- rr *roadrunner.Server
mdws []middleware
+
+ mu sync.Mutex
+ rr *roadrunner.Server
srv *Handler
http *http.Server
}
@@ -63,6 +66,7 @@ func (s *Service) Init(cfg service.Config, c service.Container) (bool, error) {
// Serve serves the svc.
func (s *Service) Serve() error {
+ s.mu.Lock()
rr := roadrunner.NewServer(s.cfg.Workers)
s.rr = rr
@@ -77,6 +81,7 @@ func (s *Service) Serve() error {
} else {
s.http.Handler = s
}
+ s.mu.Unlock()
if err := rr.Start(); err != nil {
return err
@@ -92,6 +97,8 @@ func (s *Service) Serve() error {
// Stop stops the svc.
func (s *Service) Stop() {
+ s.mu.Lock()
+ defer s.mu.Unlock()
if s.http == nil {
return
}
diff --git a/service/http/service_test.go b/service/http/service_test.go
new file mode 100644
index 00000000..08dc8a5b
--- /dev/null
+++ b/service/http/service_test.go
@@ -0,0 +1,159 @@
+package http
+
+import (
+ "testing"
+ "github.com/spiral/roadrunner/service"
+ "github.com/sirupsen/logrus/hooks/test"
+ "github.com/sirupsen/logrus"
+ "encoding/json"
+ "github.com/stretchr/testify/assert"
+ "os"
+ "time"
+ "net/http"
+ "io/ioutil"
+)
+
+type testCfg struct{ httpCfg string }
+
+func (cfg *testCfg) Get(name string) service.Config {
+ if name == Name {
+ return &testCfg{cfg.httpCfg}
+ }
+ return nil
+}
+func (cfg *testCfg) Unmarshal(out interface{}) error {
+ json.Unmarshal([]byte(cfg.httpCfg), out)
+ return nil
+}
+
+func Test_Service_NoConfig(t *testing.T) {
+ logger, _ := test.NewNullLogger()
+ logger.SetLevel(logrus.DebugLevel)
+
+ c := service.NewContainer(logger)
+ c.Register(Name, &Service{})
+
+ assert.NoError(t, c.Init(&testCfg{`{}`}))
+
+ s, st := c.Get(Name)
+ assert.NotNil(t, s)
+ assert.Equal(t, service.StatusRegistered, st)
+}
+
+func Test_Service_Configure_Disable(t *testing.T) {
+ logger, _ := test.NewNullLogger()
+ logger.SetLevel(logrus.DebugLevel)
+
+ c := service.NewContainer(logger)
+ c.Register(Name, &Service{})
+
+ assert.NoError(t, c.Init(&testCfg{`{
+ "enable": false,
+ "address": ":8070",
+ "maxRequest": 1024,
+ "uploads": {
+ "dir": ` + tmpDir() + `,
+ "forbid": []
+ },
+ "workers":{
+ "command": "php ../../php-src/tests/http/client.php echo pipes",
+ "relay": "pipes",
+ "pool": {
+ "numWorkers": 1,
+ "allocateTimeout": 10000000,
+ "destroyTimeout": 10000000
+ }
+ }
+ }`}))
+
+ s, st := c.Get(Name)
+ assert.NotNil(t, s)
+ assert.Equal(t, service.StatusRegistered, st)
+}
+
+func Test_Service_Configure_Enable(t *testing.T) {
+ logger, _ := test.NewNullLogger()
+ logger.SetLevel(logrus.DebugLevel)
+
+ c := service.NewContainer(logger)
+ c.Register(Name, &Service{})
+
+ assert.NoError(t, c.Init(&testCfg{`{
+ "enable": true,
+ "address": ":8070",
+ "maxRequest": 1024,
+ "uploads": {
+ "dir": ` + tmpDir() + `,
+ "forbid": []
+ },
+ "workers":{
+ "command": "php ../../php-src/tests/http/client.php echo pipes",
+ "relay": "pipes",
+ "pool": {
+ "numWorkers": 1,
+ "allocateTimeout": 10000000,
+ "destroyTimeout": 10000000
+ }
+ }
+ }`}))
+
+ s, st := c.Get(Name)
+ assert.NotNil(t, s)
+ assert.Equal(t, service.StatusConfigured, st)
+}
+
+func Test_Service_Echo(t *testing.T) {
+ logger, _ := test.NewNullLogger()
+ logger.SetLevel(logrus.DebugLevel)
+
+ c := service.NewContainer(logger)
+ c.Register(Name, &Service{})
+
+ assert.NoError(t, c.Init(&testCfg{`{
+ "enable": true,
+ "address": ":8070",
+ "maxRequest": 1024,
+ "uploads": {
+ "dir": ` + tmpDir() + `,
+ "forbid": []
+ },
+ "workers":{
+ "command": "php ../../php-src/tests/http/client.php echo pipes",
+ "relay": "pipes",
+ "pool": {
+ "numWorkers": 1,
+ "allocateTimeout": 10000000,
+ "destroyTimeout": 10000000
+ }
+ }
+ }`}))
+
+ s, st := c.Get(Name)
+ assert.NotNil(t, s)
+ assert.Equal(t, service.StatusConfigured, st)
+
+ go func() { c.Serve() }()
+ time.Sleep(time.Millisecond * 10)
+ defer c.Stop()
+
+ req, err := http.NewRequest("GET", "http://localhost:8070?hello=world", nil)
+ assert.NoError(t, err)
+
+ r, err := http.DefaultClient.Do(req)
+ assert.NoError(t, err)
+ defer r.Body.Close()
+
+ b, err := ioutil.ReadAll(r.Body)
+ assert.NoError(t, err)
+
+ assert.NoError(t, err)
+ assert.Equal(t, 201, r.StatusCode)
+ assert.Equal(t, "WORLD", string(b))
+}
+
+func tmpDir() string {
+ p := os.TempDir()
+ r, _ := json.Marshal(p)
+
+ return string(r)
+}