package projects import ( "net/http" "net/http/httptest" "strings" "testing" "github.com/gin-gonic/gin" ) func newTestRouter(t *testing.T) (*gin.Engine, *fakeProv) { t.Helper() gin.SetMode(gin.TestMode) svc, prov, _ := newTestService(t) h := NewHandler(svc) r := gin.New() r.POST("/projects", h.Create) r.GET("/projects", h.List) r.GET("/projects/:id", h.Get) r.DELETE("/projects/:id", h.Delete) r.POST("/projects/:id/extend", h.Extend) return r, prov } func do(r *gin.Engine, method, path, body string) *httptest.ResponseRecorder { req := httptest.NewRequest(method, path, strings.NewReader(body)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() r.ServeHTTP(w, req) return w } const goodBody = `{"client_name":"Dupont","months":%s,"admin_username":"admin","admin_password":"un-mot-de-passe-solide"}` func body(months string) string { return strings.Replace(goodBody, "%s", months, 1) } func TestHandlerCreate_MonthsBounds(t *testing.T) { r, _ := newTestRouter(t) for _, months := range []string{"0", "13", "-1", `"x"`} { if w := do(r, "POST", "/projects", body(months)); w.Code != http.StatusBadRequest { t.Errorf("months=%s : HTTP %d, attendu 400", months, w.Code) } } for _, months := range []string{"1", "12"} { w := do(r, "POST", "/projects", body(months)) if w.Code != http.StatusAccepted { t.Errorf("months=%s : HTTP %d, attendu 202 (%s)", months, w.Code, w.Body) } } } func TestHandlerCreate_NeverEchoesAdminPassword(t *testing.T) { r, prov := newTestRouter(t) w := do(r, "POST", "/projects", body("2")) if w.Code != http.StatusAccepted { t.Fatalf("HTTP %d: %s", w.Code, w.Body) } <-prov.provisioned if strings.Contains(w.Body.String(), "un-mot-de-passe-solide") { t.Error("le mot de passe admin figure dans la réponse") } if list := do(r, "GET", "/projects", ""); strings.Contains(list.Body.String(), "un-mot-de-passe-solide") { t.Error("le mot de passe admin figure dans la liste") } } func TestHandlerCreate_RejectsWeakPasswordAndBadAdminName(t *testing.T) { r, _ := newTestRouter(t) for name, payload := range map[string]string{ "mot de passe court": `{"client_name":"D","months":1,"admin_username":"admin","admin_password":"court"}`, "admin non alphanum": `{"client_name":"D","months":1,"admin_username":"ad min","admin_password":"un-mot-de-passe-solide"}`, "client manquant": `{"months":1,"admin_username":"admin","admin_password":"un-mot-de-passe-solide"}`, "trop d'admins": `{"client_name":"D","months":1,"admin_username":"admin","admin_password":"un-mot-de-passe-solide","admin_number":21}`, } { if w := do(r, "POST", "/projects", payload); w.Code != http.StatusBadRequest { t.Errorf("%s : HTTP %d, attendu 400", name, w.Code) } } } func TestHandlerExtend_BoundsAndNotFound(t *testing.T) { r, _ := newTestRouter(t) if w := do(r, "POST", "/projects/inconnu/extend", `{"months":2}`); w.Code != http.StatusNotFound { t.Errorf("projet inconnu : HTTP %d, attendu 404", w.Code) } if w := do(r, "POST", "/projects/inconnu/extend", `{"months":13}`); w.Code != http.StatusBadRequest { t.Errorf("13 mois : HTTP %d, attendu 400", w.Code) } if w := do(r, "POST", "/projects/inconnu/extend", `{}`); w.Code != http.StatusBadRequest { t.Errorf("sans durée : HTTP %d, attendu 400", w.Code) } }