diff --git a/builder.go b/builder.go index fc17243..f737aae 100644 --- a/builder.go +++ b/builder.go @@ -52,9 +52,6 @@ func (b *Builder) Validate(t validator.Type) error { // the service associated with the request has not been found at this stage. // This stage is perfect for logging or generic request management. func (b *Builder) With(mw func(http.Handler) http.Handler) { - if b.conf == nil { - b.conf = &config.Server{} - } if b.middlewares == nil { b.middlewares = make([]func(http.Handler) http.Handler, 0) } @@ -69,9 +66,6 @@ func (b *Builder) With(mw func(http.Handler) http.Handler) { // data that can be access with api.GetRequest(), api.GetResponseWriter(), // api.GetAuth(), etc methods. func (b *Builder) WithContext(mw func(http.Handler) http.Handler) { - if b.conf == nil { - b.conf = &config.Server{} - } if b.ctxMiddlewares == nil { b.ctxMiddlewares = make([]func(http.Handler) http.Handler, 0) } @@ -85,14 +79,14 @@ func (b *Builder) Setup(r io.Reader) error { b.conf = &config.Server{} } if b.conf.Services != nil { - panic(errAlreadySetup) + return errAlreadySetup } return b.conf.Parse(r) } // Bind a dynamic handler to a REST service (method and pattern) func (b *Builder) Bind(method, path string, fn interface{}) error { - if b.conf.Services == nil { + if b.conf == nil || b.conf.Services == nil { return errNotSetup } diff --git a/builder_test.go b/builder_test.go index fbbebe0..235901e 100644 --- a/builder_test.go +++ b/builder_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/xdrm-io/aicra/api" + "github.com/xdrm-io/aicra/internal/dynfunc" "github.com/xdrm-io/aicra/validator" ) @@ -34,6 +35,8 @@ func addBuiltinTypes(b *Builder) error { } func TestAddType(t *testing.T) { + t.Parallel() + builder := &Builder{} err := builder.Validate(validator.BoolType{}) if err != nil { @@ -49,7 +52,180 @@ func TestAddType(t *testing.T) { } } +func TestSetupNoType(t *testing.T) { + t.Parallel() + + builder := &Builder{} + err := builder.Setup(strings.NewReader("[]")) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } +} +func TestSetupTwice(t *testing.T) { + t.Parallel() + + builder := &Builder{} + err := builder.Setup(strings.NewReader("[]")) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + // double Setup() must fail + err = builder.Setup(strings.NewReader("[]")) + if err != errAlreadySetup { + t.Fatalf("expected error %v, got %v", errAlreadySetup, err) + } +} + +func TestBindBeforeSetup(t *testing.T) { + t.Parallel() + + builder := &Builder{} + // binding before Setup() must fail + err := builder.Bind(http.MethodGet, "/path", func() {}) + if err != errNotSetup { + t.Fatalf("expected error %v, got %v", errNotSetup, err) + } +} + +func TestBindUnknownService(t *testing.T) { + t.Parallel() + + builder := &Builder{} + err := builder.Setup(strings.NewReader("[]")) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + err = builder.Bind(http.MethodGet, "/path", func() {}) + if !errors.Is(err, errUnknownService) { + t.Fatalf("expected error %v, got %v", errUnknownService, err) + } +} +func TestBindInvalidHandler(t *testing.T) { + t.Parallel() + + builder := &Builder{} + err := builder.Setup(strings.NewReader(`[ + { + "method": "GET", + "path": "/path", + "scope": [[]], + "info": "info", + "in": {}, + "out": {} + } + ]`)) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + err = builder.Bind(http.MethodGet, "/path", func() {}) + + if err == nil { + t.Fatalf("expected an error") + } + + if !errors.Is(err, dynfunc.ErrMissingHandlerContextArgument) { + t.Fatalf("expected a dynfunc.Err got %v", err) + } +} +func TestBindGet(t *testing.T) { + t.Parallel() + + builder := &Builder{} + err := builder.Setup(strings.NewReader(`[ + { + "method": "GET", + "path": "/path", + "scope": [[]], + "info": "info", + "in": {}, + "out": {} + }, + { + "method": "POST", + "path": "/path", + "scope": [[]], + "info": "info", + "in": {}, + "out": {} + }, + { + "method": "PUT", + "path": "/path", + "scope": [[]], + "info": "info", + "in": {}, + "out": {} + }, + { + "method": "DELETE", + "path": "/path", + "scope": [[]], + "info": "info", + "in": {}, + "out": {} + } + ]`)) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + err = builder.Get("/path", func(context.Context) (*struct{}, api.Err) { return nil, api.ErrSuccess }) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + err = builder.Post("/path", func(context.Context) (*struct{}, api.Err) { return nil, api.ErrSuccess }) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + err = builder.Put("/path", func(context.Context) (*struct{}, api.Err) { return nil, api.ErrSuccess }) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + err = builder.Delete("/path", func(context.Context) (*struct{}, api.Err) { return nil, api.ErrSuccess }) + if err != nil { + t.Fatalf("unexpected error %v", err) + } +} + +func TestUnhandledService(t *testing.T) { + t.Parallel() + + builder := &Builder{} + err := builder.Setup(strings.NewReader(`[ + { + "method": "GET", + "path": "/path", + "scope": [[]], + "info": "info", + "in": {}, + "out": {} + }, + { + "method": "POST", + "path": "/path", + "scope": [[]], + "info": "info", + "in": {}, + "out": {} + } + ]`)) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + + err = builder.Get("/path", func(context.Context) (*struct{}, api.Err) { return nil, api.ErrSuccess }) + if err != nil { + t.Fatalf("unexpected error %v", err) + } + + _, err = builder.Build() + if !errors.Is(err, errMissingHandler) { + t.Fatalf("expected a %v error, got %v", errMissingHandler, err) + } +} func TestBind(t *testing.T) { + t.Parallel() + tcases := []struct { Name string Config string