package http import ( "bytes" "encoding/json" "io" stdhttp "net/http" "strings" "testing" "gitea.dcglab.co.uk/steve/restic-manager/internal/store" ) func TestAPIUsersList(t *testing.T) { t.Parallel() srv, ts, _ := rawTestServerWithUI(t) adminID := makeUser(t, srv, "admin1", store.RoleAdmin) makeUser(t, srv, "op1", store.RoleOperator) cookie := loginAs(t, srv, adminID) req, _ := stdhttp.NewRequest("GET", ts.URL+"/api/users", nil) req.AddCookie(cookie) res, err := stdhttp.DefaultClient.Do(req) if err != nil { t.Fatalf("GET: %v", err) } defer res.Body.Close() if res.StatusCode != stdhttp.StatusOK { body, _ := io.ReadAll(res.Body) t.Fatalf("status: got %d body=%s", res.StatusCode, body) } var got listUsersResponse _ = json.NewDecoder(res.Body).Decode(&got) if len(got.Users) != 2 { t.Errorf("count: got %d want 2", len(got.Users)) } } func TestAPIUserCreate(t *testing.T) { t.Parallel() srv, ts, _ := rawTestServerWithUI(t) adminID := makeUser(t, srv, "admin1", store.RoleAdmin) cookie := loginAs(t, srv, adminID) body, _ := json.Marshal(map[string]any{ "username": "Bob", "email": "bob@example.com", "role": "operator", }) req, _ := stdhttp.NewRequest("POST", ts.URL+"/api/users", bytes.NewReader(body)) req.AddCookie(cookie) req.Header.Set("Content-Type", "application/json") res, err := stdhttp.DefaultClient.Do(req) if err != nil { t.Fatalf("POST: %v", err) } defer res.Body.Close() if res.StatusCode != stdhttp.StatusCreated { body, _ := io.ReadAll(res.Body) t.Fatalf("status: got %d body=%s", res.StatusCode, body) } var got struct { ID string `json:"id"` SetupURL string `json:"setup_url"` } _ = json.NewDecoder(res.Body).Decode(&got) if got.ID == "" || got.SetupURL == "" { t.Errorf("missing fields: %+v", got) } if !strings.Contains(got.SetupURL, "/setup?token=") { t.Errorf("setup_url shape: %q", got.SetupURL) } // Verify lowercase-normalised. u, err := srv.deps.Store.GetUserByUsername(t.Context(), "bob") if err != nil { t.Fatalf("get: %v", err) } if u.Username != "bob" { t.Errorf("username: got %q want bob", u.Username) } if !u.MustChangePassword { t.Error("must_change_password not set") } } func TestAPIUserCreateRejectsDuplicateEnabled(t *testing.T) { t.Parallel() srv, ts, _ := rawTestServerWithUI(t) adminID := makeUser(t, srv, "admin1", store.RoleAdmin) makeUser(t, srv, "alice", store.RoleOperator) cookie := loginAs(t, srv, adminID) body, _ := json.Marshal(map[string]any{ "username": "ALICE", "role": "operator", }) req, _ := stdhttp.NewRequest("POST", ts.URL+"/api/users", bytes.NewReader(body)) req.AddCookie(cookie) req.Header.Set("Content-Type", "application/json") res, err := stdhttp.DefaultClient.Do(req) if err != nil { t.Fatalf("POST: %v", err) } defer res.Body.Close() if res.StatusCode != stdhttp.StatusConflict { t.Errorf("status: got %d want 409", res.StatusCode) } }