kleinTodo/tests/integration_test.go

145 lines
4.5 KiB
Go
Raw Permalink Normal View History

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 TestIntegrationSync(t *testing.T) {
// 1. Setup Environment
tempDir, err := os.MkdirTemp("", "todo-test-*")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
// Override storage path for BoltStore by setting HOME or XDG_CONFIG_HOME
// BoltStore uses os.UserConfigDir() which looks at XDG_CONFIG_HOME on Linux
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)
ts := httptest.NewServer(mux)
defer ts.Close()
client := ts.Client()
username := "testuser"
password := "testpass"
// 3. Register User
regPayload, _ := json.Marshal(common.Credentials{Username: username, Password: password})
resp, err := client.Post(ts.URL+"/register", "application/json", bytes.NewBuffer(regPayload))
require.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
// 4. Login and Get Token
resp, err = client.Post(ts.URL+"/login", "application/json", bytes.NewBuffer(regPayload))
require.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
token := resp.Header.Get(common.AuthHeader)
require.NotEmpty(t, token)
// 5. Create Local Todos
store, err := common.GetTodoDataStore()
require.NoError(t, err)
defer store.Close()
todo1 := common.Todo{
Id: uuid.New().String(),
Name: "Task 1",
Description: "Desc 1",
Status: common.NotStarted,
Owner: username,
LastModified: time.Now().UTC(),
}
todo2 := common.Todo{
Id: uuid.New().String(),
Name: "Task 2",
Description: "Desc 2",
Status: common.WIP,
Owner: username,
LastModified: time.Now().UTC(),
}
err = todo1.Store(store, username)
require.NoError(t, err)
err = todo2.Store(store, username)
require.NoError(t, err)
// 6. Sync to Server
localTodos := store.GetTodoList(username, true)
syncReq := common.TodoList{Todos: localTodos}
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 "+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()
// Verify both todos are in sync response
assert.Len(t, syncResp.SyncedTodos, 2)
assert.Empty(t, syncResp.MisMatchingTodos)
// 7. Verify Server State (By syncing again with empty local)
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 "+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, 2, "Server should have kept the synced todos")
// 8. Test Pulling from Server (New Client)
// Create another temporary directory for a different client
client2TempDir, err := os.MkdirTemp("", "todo-test-client2-*")
require.NoError(t, err)
defer os.RemoveAll(client2TempDir)
// Since common.GetTodoDataStore() uses sync.Once, we can't easily get a new database in the same process
// BUT for this test, we can just use GetCustomDataStore("todo2.db") if it was public,
// however it seems we can just check if the server returns the data when requested.
req, _ = http.NewRequest("POST", ts.URL+"/sync", bytes.NewBuffer(emptySyncPayload))
req.Header.Set("Content-Type", "application/json")
req.Header.Set(common.AuthHeader, "Bearer "+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, 2, "Server should return the 2 todos for a sync request")
}