From 9de929ea1230b43d0dd45251743ae5fc9f7df6af Mon Sep 17 00:00:00 2001 From: aperezg Date: Sat, 11 May 2019 14:43:20 +0200 Subject: [PATCH] Testing how to read config file and improve route_matchers tests --- internal/config.go | 9 ++-- internal/config_test.go | 55 +++++++++++++++++++++++++ internal/route_matchers_test.go | 34 +++++++++------ internal/server.go | 13 +++++- internal/server_test.go | 15 ++++++- internal/test/testdata/config.yml | 9 ++++ internal/test/testdata/wrong_config.yml | 1 + 7 files changed, 116 insertions(+), 20 deletions(-) create mode 100644 internal/config_test.go create mode 100644 internal/test/testdata/config.yml create mode 100644 internal/test/testdata/wrong_config.yml diff --git a/internal/config.go b/internal/config.go index 5ee3ef3..2b262bb 100644 --- a/internal/config.go +++ b/internal/config.go @@ -18,10 +18,11 @@ type Config struct { // ConfigCORS representation of section CORS of the yaml type ConfigCORS struct { - Methods []string `yaml:"methods"` - Headers []string `yaml:"headers"` - Origins []string `yaml:"origins"` - ExposedHeaders []string `yaml:"exposed_headers"` + Methods []string `yaml:"methods"` + Headers []string `yaml:"headers"` + Origins []string `yaml:"origins"` + ExposedHeaders []string `yaml:"exposed_headers"` + AllowCredentials bool `yaml:"allow_credentials"` } // ReadConfigFile unmarshal content of config file to Config struct diff --git a/internal/config_test.go b/internal/config_test.go new file mode 100644 index 0000000..2ee0328 --- /dev/null +++ b/internal/config_test.go @@ -0,0 +1,55 @@ +package killgrave + +import ( + "reflect" + "testing" + + "github.com/pkg/errors" +) + +func TestReadConfigFile(t *testing.T) { + tests := map[string]struct { + input string + expected Config + err error + }{ + "valid config file": {"test/testdata/config.yml", validConfig(), nil}, + "file not found": {"test/testdata/file.yml", Config{}, errors.New("error")}, + "wrong yaml file": {"test/testdata/wrong_config.yml", Config{}, errors.New("error")}, + } + + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + var got Config + err := ReadConfigFile(tc.input, &got) + + if err != nil && tc.err == nil { + t.Fatalf("not expected any erros and got %v", err) + } + + if err == nil && tc.err != nil { + t.Fatalf("expected an error and got nil") + } + + if !reflect.DeepEqual(tc.expected, got) { + t.Fatalf("expected: %v, got: %v", tc.expected, got) + } + + }) + } +} + +func validConfig() Config { + return Config{ + ImpostersPath: "imposters", + Port: 3000, + Host: "localhost", + CORS: ConfigCORS{ + Methods: []string{"GET"}, + Origins: []string{"*"}, + Headers: []string{"Content-Type"}, + ExposedHeaders: []string{"Cache-Control"}, + AllowCredentials: true, + }, + } +} diff --git a/internal/route_matchers_test.go b/internal/route_matchers_test.go index 21081f4..b883cfe 100644 --- a/internal/route_matchers_test.go +++ b/internal/route_matchers_test.go @@ -7,12 +7,14 @@ import ( "testing" "github.com/gorilla/mux" + "github.com/pkg/errors" ) func TestMatcherBySchema(t *testing.T) { bodyA := ioutil.NopCloser(bytes.NewReader([]byte("{\"type\": \"gopher\"}"))) bodyB := ioutil.NopCloser(bytes.NewReader([]byte("{\"type\": \"cat\"}"))) emptyBody := ioutil.NopCloser(bytes.NewReader([]byte(""))) + wrongBody := ioutil.NopCloser(errReader(0)) schemaGopherFile := "test/testdata/imposters/schemas/type_gopher.json" schemaCatFile := "test/testdata/imposters/schemas/type_cat.json" @@ -46,22 +48,22 @@ func TestMatcherBySchema(t *testing.T) { httpRequestB := &http.Request{Body: bodyB} okResponse := Response{Status: http.StatusOK} - var matcherData = []struct { - name string - fn mux.MatcherFunc - req *http.Request - res bool + var matcherData = map[string]struct { + fn mux.MatcherFunc + req *http.Request + res bool }{ - {"correct request schema", MatcherBySchema(Imposter{Request: requestWithSchema, Response: okResponse}), httpRequestA, true}, - {"imposter without request schema", MatcherBySchema(Imposter{Request: requestWithoutSchema, Response: okResponse}), httpRequestA, true}, - {"malformatted schema file", MatcherBySchema(Imposter{Request: requestWithWrongSchema, Response: okResponse}), httpRequestA, false}, - {"incorrect request schema", MatcherBySchema(Imposter{Request: requestWithSchema, Response: okResponse}), httpRequestB, false}, - {"non-existing schema file", MatcherBySchema(Imposter{Request: requestWithNonExistingSchema, Response: okResponse}), httpRequestB, false}, - {"empty body with required schema file", MatcherBySchema(Imposter{Request: requestWithSchema, Response: okResponse}), &http.Request{Body: emptyBody}, false}, + "correct request schema": {MatcherBySchema(Imposter{Request: requestWithSchema, Response: okResponse}), httpRequestA, true}, + "imposter without request schema": {MatcherBySchema(Imposter{Request: requestWithoutSchema, Response: okResponse}), httpRequestA, true}, + "malformatted schema file": {MatcherBySchema(Imposter{Request: requestWithWrongSchema, Response: okResponse}), httpRequestA, false}, + "incorrect request schema": {MatcherBySchema(Imposter{Request: requestWithSchema, Response: okResponse}), httpRequestB, false}, + "non-existing schema file": {MatcherBySchema(Imposter{Request: requestWithNonExistingSchema, Response: okResponse}), httpRequestB, false}, + "empty body with required schema file": {MatcherBySchema(Imposter{Request: requestWithSchema, Response: okResponse}), &http.Request{Body: emptyBody}, false}, + "invalid request body": {MatcherBySchema(Imposter{Request: requestWithSchema, Response: okResponse}), &http.Request{Body: wrongBody}, false}, } - for _, tt := range matcherData { - t.Run(tt.name, func(t *testing.T) { + for name, tt := range matcherData { + t.Run(name, func(t *testing.T) { res := tt.fn(tt.req, nil) if res != tt.res { t.Fatalf("error while matching by request schema - expected: %t, given: %t", tt.res, res) @@ -70,3 +72,9 @@ func TestMatcherBySchema(t *testing.T) { } } + +type errReader int + +func (errReader) Read(p []byte) (n int, err error) { + return 0, errors.New("test error") +} diff --git a/internal/server.go b/internal/server.go index 2fec971..0dae391 100644 --- a/internal/server.go +++ b/internal/server.go @@ -2,6 +2,7 @@ package killgrave import ( "encoding/json" + "fmt" "io/ioutil" "log" "os" @@ -13,8 +14,9 @@ import ( ) var ( - defaultCORSMethods = []string{"GET", "HEAD", "POST", "PUT", "OPTIONS", "DELETE", "PATCH", "TRACE", "CONNECT"} - defaultCORSHeaders = []string{"X-Requested-With", "Content-Type", "Authorization", "*"} + defaultCORSMethods = []string{"GET", "HEAD", "POST", "PUT", "OPTIONS", "DELETE", "PATCH", "TRACE", "CONNECT"} + defaultCORSHeaders = []string{"X-Requested-With", "Content-Type", "Authorization"} + defaultCORSExposedHeaders = []string{"Cache-Control", "Content-Language", "Content-Type", "Expires", "Last-Modified", "Pragma"} ) // Server definition of mock server @@ -35,6 +37,7 @@ func NewServer(p string, r *mux.Router) *Server { func (s *Server) AccessControl(config ConfigCORS) (h []handlers.CORSOption) { h = append(h, handlers.AllowedMethods(defaultCORSMethods)) h = append(h, handlers.AllowedHeaders(defaultCORSHeaders)) + h = append(h, handlers.ExposedHeaders(defaultCORSExposedHeaders)) if len(config.Methods) > 0 { h = append(h, handlers.AllowedMethods(config.Methods)) @@ -51,6 +54,12 @@ func (s *Server) AccessControl(config ConfigCORS) (h []handlers.CORSOption) { if len(config.ExposedHeaders) > 0 { h = append(h, handlers.ExposedHeaders(config.ExposedHeaders)) } + + fmt.Println(config) + if config.AllowCredentials { + h = append(h, handlers.AllowCredentials()) + } + return } diff --git a/internal/server_test.go b/internal/server_test.go index 2c8a84a..c870954 100644 --- a/internal/server_test.go +++ b/internal/server_test.go @@ -39,7 +39,20 @@ func TestRunServer(t *testing.T) { func TestAccessControl(t *testing.T) { s := NewServer("test/testdata/imposters", mux.NewRouter()) - h := s.AccessControl() + config := Config{ + ImpostersPath: "imposters", + Port: 3000, + Host: "localhost", + CORS: ConfigCORS{ + Methods: []string{"GET"}, + Origins: []string{"*"}, + Headers: []string{"Content-Type"}, + ExposedHeaders: []string{"Cache-Control"}, + AllowCredentials: true, + }, + } + + h := s.AccessControl(config.CORS) if len(h) <= 0 { t.Fatal("Expected any CORS options and got empty") diff --git a/internal/test/testdata/config.yml b/internal/test/testdata/config.yml new file mode 100644 index 0000000..b3bc62d --- /dev/null +++ b/internal/test/testdata/config.yml @@ -0,0 +1,9 @@ +imposters_path: "imposters" +port: 3000 +host: "localhost" +cors: + methods: ["GET"] + headers: ["Content-Type"] + exposed_headers: ["Cache-Control"] + origins: ["*"] + allow_credentials: true diff --git a/internal/test/testdata/wrong_config.yml b/internal/test/testdata/wrong_config.yml new file mode 100644 index 0000000..8276753 --- /dev/null +++ b/internal/test/testdata/wrong_config.yml @@ -0,0 +1 @@ +error