package tests import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "os" "testing" "time" "gitea.kleinsense.nl/DariusKlein/kleinTodo/common" "gitea.kleinsense.nl/DariusKlein/kleinTodo/server/handler" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestSharedTodoSync(t *testing.T) { // 1. Setup Environment tempDir, err := os.MkdirTemp("", "todo-test-*") require.NoError(t, err) defer os.RemoveAll(tempDir) os.Setenv("XDG_CONFIG_HOME", tempDir) os.Setenv("JWT_SECRET", "test-secret-123") // 2. Initialize Server mux := http.NewServeMux() mux.HandleFunc("POST /register", handler.RegisterHandler) mux.HandleFunc("POST /login", handler.LoginHandler) mux.HandleFunc("POST /sync", handler.SyncHandler) mux.HandleFunc("POST /store", handler.StoreHandler) ts := httptest.NewServer(mux) defer ts.Close() client := ts.Client() // 3. Register two users users := []struct { username, password string token string }{ {"owner", "pass1", ""}, {"shared", "pass2", ""}, } for i, u := range users { regPayload, _ := json.Marshal(common.Credentials{Username: u.username, Password: u.password}) resp, err := client.Post(ts.URL+"/register", "application/json", bytes.NewBuffer(regPayload)) require.NoError(t, err) assert.Equal(t, http.StatusOK, resp.StatusCode) resp, err = client.Post(ts.URL+"/login", "application/json", bytes.NewBuffer(regPayload)) require.NoError(t, err) assert.Equal(t, http.StatusOK, resp.StatusCode) users[i].token = resp.Header.Get(common.AuthHeader) } // 4. Owner creates a shared todo sharedTodo := common.Todo{ Id: uuid.New().String(), Name: "Shared Task", Description: "This is shared", Status: common.NotStarted, Owner: "owner", SharedWith: []string{"shared"}, LastModified: time.Now().UTC(), } syncReq := common.TodoList{Todos: []common.Todo{sharedTodo}} syncPayload, _ := json.Marshal(syncReq) req, _ := http.NewRequest("POST", ts.URL+"/sync", bytes.NewBuffer(syncPayload)) req.Header.Set("Content-Type", "application/json") req.Header.Set(common.AuthHeader, "Bearer "+users[0].token) resp, err := client.Do(req) require.NoError(t, err) assert.Equal(t, http.StatusOK, resp.StatusCode) // 5. Shared user pulls todos emptySyncReq := common.TodoList{Todos: []common.Todo{}} emptySyncPayload, _ := json.Marshal(emptySyncReq) req, _ = http.NewRequest("POST", ts.URL+"/sync", bytes.NewBuffer(emptySyncPayload)) req.Header.Set("Content-Type", "application/json") req.Header.Set(common.AuthHeader, "Bearer "+users[1].token) resp, err = client.Do(req) require.NoError(t, err) assert.Equal(t, http.StatusOK, resp.StatusCode) var syncResp common.SyncResponse err = json.NewDecoder(resp.Body).Decode(&syncResp) require.NoError(t, err) resp.Body.Close() // Shared user should see the todo assert.Len(t, syncResp.SyncedTodos, 1) assert.Equal(t, "Shared Task", syncResp.SyncedTodos[0].Name) assert.Equal(t, "owner", syncResp.SyncedTodos[0].Owner) assert.Contains(t, syncResp.SyncedTodos[0].SharedWith, "shared") // 6. Shared user updates the todo status updatedTodo := syncResp.SyncedTodos[0] updatedTodo.Status = common.Done updatedTodo.LastModified = time.Now().UTC() updateSyncReq := common.TodoList{Todos: []common.Todo{updatedTodo}} updateSyncPayload, _ := json.Marshal(updateSyncReq) req, _ = http.NewRequest("POST", ts.URL+"/sync", bytes.NewBuffer(updateSyncPayload)) req.Header.Set("Content-Type", "application/json") req.Header.Set(common.AuthHeader, "Bearer "+users[1].token) resp, err = client.Do(req) require.NoError(t, err) assert.Equal(t, http.StatusOK, resp.StatusCode) // 7. Owner pulls todos and checks status req, _ = http.NewRequest("POST", ts.URL+"/sync", bytes.NewBuffer(emptySyncPayload)) req.Header.Set("Content-Type", "application/json") req.Header.Set(common.AuthHeader, "Bearer "+users[0].token) resp, err = client.Do(req) require.NoError(t, err) assert.Equal(t, http.StatusOK, resp.StatusCode) err = json.NewDecoder(resp.Body).Decode(&syncResp) require.NoError(t, err) resp.Body.Close() assert.Len(t, syncResp.SyncedTodos, 1) assert.Equal(t, common.Done, syncResp.SyncedTodos[0].Status, "Owner should see status update from shared user") }