diff --git a/cmd/mcvs-stub-server/main.go b/cmd/mcvs-stub-server/main.go new file mode 100644 index 0000000..dbd55bb --- /dev/null +++ b/cmd/mcvs-stub-server/main.go @@ -0,0 +1,93 @@ +package main + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + "sync" +) + +func main() { + h := newHandler() + http.HandleFunc("/reset", h.reset) + http.HandleFunc("/configure", h.configure) + http.HandleFunc("/", h.catchAll) + err := http.ListenAndServe(":8080", nil) + if err != nil { + log.Fatal(err) + } +} + +type handler struct { + mu sync.RWMutex + endpoints map[string]any +} + +func newHandler() *handler { + return &handler{ + endpoints: map[string]any{}, + } +} + +func (h *handler) reset(w http.ResponseWriter, r *http.Request) { + h.endpoints = map[string]any{} + w.WriteHeader(http.StatusOK) +} + +// EndpointConfigurationRequest is the request body for the /configure endpoint. +type EndpointConfigurationRequest struct { + Path string `json:"path"` + Response any `json:"response"` +} + +func (h *handler) configure(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + http.Error(w, "Invalid request method", http.StatusMethodNotAllowed) + return + } + + request := EndpointConfigurationRequest{} + if err := json.NewDecoder(r.Body).Decode(&request); err != nil { + http.Error(w, "Invalid request body", http.StatusBadRequest) + return + } + + if request.Path == "" { + http.Error(w, "Path is required", http.StatusBadRequest) + return + } + + if request.Response == nil { + http.Error(w, "Response is required", http.StatusBadRequest) + return + } + fmt.Println("HIIII", request.Response) + h.mu.Lock() + h.endpoints[request.Path] = request.Response + h.mu.Unlock() + + w.WriteHeader(http.StatusOK) +} + +func (h *handler) catchAll(w http.ResponseWriter, r *http.Request) { + h.mu.RLock() + response, exists := h.endpoints[r.URL.Path] + h.mu.RUnlock() + + if !exists { + http.NotFound(w, r) + return + } + + b, err := json.Marshal(response) + if err != nil { + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + + _, err = w.Write(b) + if err != nil { + log.Default().Println("Failed to write response:", err) + } +} diff --git a/cmd/mcvs-stub-server/main_test.go b/cmd/mcvs-stub-server/main_test.go new file mode 100644 index 0000000..e1764b9 --- /dev/null +++ b/cmd/mcvs-stub-server/main_test.go @@ -0,0 +1,93 @@ +package main + +import ( + "bytes" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestResetHandler(t *testing.T) { + // given + handler := newHandler() + handler.endpoints["/test"] = "test" + assert.Len(t, handler.endpoints, 1) + + // when + httptestRecorder := httptest.NewRecorder() + httptestRequest := httptest.NewRequest("GET", "/reset", nil) + + // then + handler.reset(httptestRecorder, httptestRequest) + assert.Len(t, handler.endpoints, 0) + assert.Equal(t, http.StatusOK, httptestRecorder.Code) +} + +func TestConfigureHandler(t *testing.T) { + // given + handler := newHandler() + assert.Len(t, handler.endpoints, 0) + + // when + httptestRecorder := httptest.NewRecorder() + httptestRequest := httptest.NewRequest("POST", "/configure", bytes.NewBuffer([]byte(`{"path": "/test", "response": {"foo": "bar"}}`))) + + // then + handler.configure(httptestRecorder, httptestRequest) + assert.Len(t, handler.endpoints, 1) + b, err := json.Marshal(handler.endpoints["/test"]) + assert.NoError(t, err) + assert.Equal(t, []byte(`{"foo":"bar"}`), b) + assert.Equal(t, http.StatusOK, httptestRecorder.Code) +} + +func TestConfigureHandlerInvalidMethod(t *testing.T) { + // given + handler := newHandler() + + // when + httptestRecorder := httptest.NewRecorder() + httptestRequest := httptest.NewRequest("GET", "/configure", nil) + + // then + handler.configure(httptestRecorder, httptestRequest) + assert.Equal(t, http.StatusMethodNotAllowed, httptestRecorder.Code) +} + +func TestCatchAllHandler(t *testing.T) { + // given + handler := newHandler() + + response := struct { + Foo string `json:"foo"` + }{ + Foo: "bar", + } + + handler.endpoints["/test"] = response + + // when + httptestRecorder := httptest.NewRecorder() + httptestRequest := httptest.NewRequest("GET", "/test", nil) + + // then + handler.catchAll(httptestRecorder, httptestRequest) + assert.Equal(t, []byte(`{"foo":"bar"}`), httptestRecorder.Body.Bytes()) + assert.Equal(t, http.StatusOK, httptestRecorder.Code) +} + +func TestCatchAllHandlerNotFound(t *testing.T) { + // given + handler := newHandler() + + // when + httptestRecorder := httptest.NewRecorder() + httptestRequest := httptest.NewRequest("GET", "/test", nil) + + // then + handler.catchAll(httptestRecorder, httptestRequest) + assert.Equal(t, http.StatusNotFound, httptestRecorder.Code) +} diff --git a/go.mod b/go.mod index aaa1e74..a94a6c4 100644 --- a/go.mod +++ b/go.mod @@ -2,16 +2,22 @@ module schubergphilis/mcvs-integrationtest-services go 1.23.3 -require github.com/labstack/echo/v4 v4.12.0 +require ( + github.com/labstack/echo/v4 v4.12.0 + github.com/stretchr/testify v1.8.4 +) require ( + github.com/davecgh/go-spew v1.1.1 // indirect github.com/labstack/gommon v0.4.2 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect golang.org/x/crypto v0.22.0 // indirect golang.org/x/net v0.24.0 // indirect golang.org/x/sys v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 527b9c0..a66bd93 100644 --- a/go.sum +++ b/go.sum @@ -27,5 +27,7 @@ golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=