diff --git a/cookbook/crud/server.go b/cookbook/crud/server.go index 0647427c..8c7ed369 100644 --- a/cookbook/crud/server.go +++ b/cookbook/crud/server.go @@ -56,8 +56,12 @@ func updateUser(c *echo.Context) error { return err } id, _ := strconv.Atoi(c.Param("id")) - users[id].Name = u.Name - return c.JSON(http.StatusOK, users[id]) + existingUser, ok := users[id] + if !ok { + return echo.NewHTTPError(http.StatusNotFound, "user not found") + } + existingUser.Name = u.Name + return c.JSON(http.StatusOK, existingUser) } func deleteUser(c *echo.Context) error { diff --git a/cookbook/crud/server_test.go b/cookbook/crud/server_test.go new file mode 100644 index 00000000..a3601c60 --- /dev/null +++ b/cookbook/crud/server_test.go @@ -0,0 +1,69 @@ +package main + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/labstack/echo/v5" + "github.com/labstack/echo/v5/middleware" +) + +func newTestServer() *echo.Echo { + lock.Lock() + users = map[int]*user{} + seq = 1 + lock.Unlock() + + e := echo.New() + e.Use(middleware.RequestLogger()) + e.Use(middleware.Recover()) + e.GET("/users", getAllUsers) + e.POST("/users", createUser) + e.GET("/users/:id", getUser) + e.PUT("/users/:id", updateUser) + e.DELETE("/users/:id", deleteUser) + return e +} + +func TestUpdateUserNotFound(t *testing.T) { + e := newTestServer() + req := httptest.NewRequest(http.MethodPut, "/users/9999", strings.NewReader(`{"name":"x"}`)) + req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) + rec := httptest.NewRecorder() + + e.ServeHTTP(rec, req) + + if rec.Code != http.StatusNotFound { + t.Fatalf("expected status %d, got %d: %s", http.StatusNotFound, rec.Code, rec.Body.String()) + } +} + +func TestUpdateUser(t *testing.T) { + e := newTestServer() + createReq := httptest.NewRequest(http.MethodPost, "/users", strings.NewReader(`{"name":"before"}`)) + createReq.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) + createRec := httptest.NewRecorder() + e.ServeHTTP(createRec, createReq) + if createRec.Code != http.StatusCreated { + t.Fatalf("expected create status %d, got %d: %s", http.StatusCreated, createRec.Code, createRec.Body.String()) + } + + updateReq := httptest.NewRequest(http.MethodPut, "/users/1", strings.NewReader(`{"name":"after"}`)) + updateReq.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) + updateRec := httptest.NewRecorder() + e.ServeHTTP(updateRec, updateReq) + if updateRec.Code != http.StatusOK { + t.Fatalf("expected update status %d, got %d: %s", http.StatusOK, updateRec.Code, updateRec.Body.String()) + } + + var updated user + if err := json.Unmarshal(updateRec.Body.Bytes(), &updated); err != nil { + t.Fatalf("decode updated user: %v", err) + } + if updated.Name != "after" { + t.Fatalf("expected updated name %q, got %q", "after", updated.Name) + } +}