package server import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "path/filepath" "testing" "time" "task/internal/sqlite" ) func TestUpdateTimeStartEnd(t *testing.T) { db, err := sqlite.Open(filepath.Join(t.TempDir(), "t.db"), []byte("secret")) if err != nil { t.Fatal(err) } defer db.Close() if _, err := db.CreateUser("admin", "pass", true); err != nil { t.Fatal(err) } srv := New(db) handler := srv.Handler() loginBody, _ := json.Marshal(map[string]string{"username": "admin", "password": "pass"}) req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/login", bytes.NewReader(loginBody)) req.Header.Set("Content-Type", "application/json") rec := httptest.NewRecorder() handler.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("login %d %s", rec.Code, rec.Body.String()) } cookie := rec.Result().Cookies()[0] createBody, _ := json.Marshal(map[string]string{"name": "Demo"}) req = httptest.NewRequest(http.MethodPost, "/api/v1/projects", bytes.NewReader(createBody)) req.Header.Set("Content-Type", "application/json") req.AddCookie(cookie) rec = httptest.NewRecorder() handler.ServeHTTP(rec, req) if rec.Code != http.StatusCreated { t.Fatalf("create project %d %s", rec.Code, rec.Body.String()) } var proj map[string]any _ = json.Unmarshal(rec.Body.Bytes(), &proj) pid, _ := proj["id"].(string) ticketBody, _ := json.Marshal(map[string]string{"title": "Work"}) req = httptest.NewRequest(http.MethodPost, "/api/v1/projects/"+pid+"/tickets", bytes.NewReader(ticketBody)) req.Header.Set("Content-Type", "application/json") req.AddCookie(cookie) rec = httptest.NewRecorder() handler.ServeHTTP(rec, req) if rec.Code != http.StatusCreated { t.Fatalf("create ticket %d %s", rec.Code, rec.Body.String()) } var ticket map[string]any _ = json.Unmarshal(rec.Body.Bytes(), &ticket) tid, _ := ticket["id"].(string) timeBody, _ := json.Marshal(map[string]any{ "ticketId": tid, "durationNs": int64(30 * time.Minute), "source": "manual", }) req = httptest.NewRequest(http.MethodPost, "/api/v1/projects/"+pid+"/time", bytes.NewReader(timeBody)) req.Header.Set("Content-Type", "application/json") req.AddCookie(cookie) rec = httptest.NewRecorder() handler.ServeHTTP(rec, req) if rec.Code != http.StatusCreated { t.Fatalf("create time %d %s", rec.Code, rec.Body.String()) } var entry map[string]any _ = json.Unmarshal(rec.Body.Bytes(), &entry) eid, _ := entry["id"].(string) if eid == "" { t.Fatal("no entry id") } start := time.Date(2024, 6, 1, 9, 0, 0, 0, time.UTC) end := start.Add(90 * time.Minute) patchBody, _ := json.Marshal(map[string]any{ "start": start, "end": end, }) req = httptest.NewRequest(http.MethodPatch, "/api/v1/projects/"+pid+"/time/"+eid, bytes.NewReader(patchBody)) req.Header.Set("Content-Type", "application/json") req.AddCookie(cookie) rec = httptest.NewRecorder() handler.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("patch start/end %d %s", rec.Code, rec.Body.String()) } _ = json.Unmarshal(rec.Body.Bytes(), &entry) dur, _ := entry["duration"].(float64) if time.Duration(dur) != 90*time.Minute { t.Fatalf("duration want 90m got %v", time.Duration(dur)) } // duration-only still works patchBody, _ = json.Marshal(map[string]any{"durationNs": int64(45 * time.Minute)}) req = httptest.NewRequest(http.MethodPatch, "/api/v1/projects/"+pid+"/time/"+eid, bytes.NewReader(patchBody)) req.Header.Set("Content-Type", "application/json") req.AddCookie(cookie) rec = httptest.NewRecorder() handler.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("patch duration %d %s", rec.Code, rec.Body.String()) } _ = json.Unmarshal(rec.Body.Bytes(), &entry) dur, _ = entry["duration"].(float64) if time.Duration(dur) != 45*time.Minute { t.Fatalf("duration want 45m got %v", time.Duration(dur)) } // invalid range badEnd := start.Add(-time.Minute) patchBody, _ = json.Marshal(map[string]any{"start": start, "end": badEnd}) req = httptest.NewRequest(http.MethodPatch, "/api/v1/projects/"+pid+"/time/"+eid, bytes.NewReader(patchBody)) req.Header.Set("Content-Type", "application/json") req.AddCookie(cookie) rec = httptest.NewRecorder() handler.ServeHTTP(rec, req) if rec.Code != http.StatusBadRequest { t.Fatalf("invalid range want 400 got %d %s", rec.Code, rec.Body.String()) } }