diff --git a/docker-compose.yml b/docker-compose.yml index 017118d..685add3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,9 +3,7 @@ services: image: ghcr.io/kwila-cloud/simple-sync:latest container_name: simple-sync ports: - - "8080:8080" - environment: - - PORT=8080 + - "8765:8080" volumes: - ./data:/app/data # explicit local bind for persistent DB file (recommended for development) # Alternative: use a named volume managed by Docker diff --git a/specs/7-data-persistence.md b/specs/7-data-persistence.md index ae9daf1..a21b8b8 100644 --- a/specs/7-data-persistence.md +++ b/specs/7-data-persistence.md @@ -86,4 +86,8 @@ Encryption at rest will be addressed separately (issue #17) using SQLCipher or f - [x] Document backup/restore ### Clean Up -- [ ] Handle remaining TODO comments for issue #7 +- [x] Rename interface methods: `SaveEvents` → `AddEvents` +- [x] Rename interface methods: `CreateApiKey` → `AddApiKey` +- [x] Rename interface methods: `CreateSetupToken` → `AddSetupToken` +- [x] Rename interface methods: `CreateAclRule` → `AddAclRule` +- [x] Update all storage implementations and tests to use new method names (work to be done on branch `7-clean-up`) diff --git a/src/handlers/acl.go b/src/handlers/acl.go index 033e52e..a4d40ee 100644 --- a/src/handlers/acl.go +++ b/src/handlers/acl.go @@ -68,7 +68,7 @@ func (h *Handlers) PostAcl(c *gin.Context) { } // Store the events - if err := h.storage.SaveEvents(events); err != nil { + if err := h.storage.AddEvents(events); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal server error"}) return } diff --git a/src/handlers/events.go b/src/handlers/events.go index 8c7bb16..214391b 100644 --- a/src/handlers/events.go +++ b/src/handlers/events.go @@ -79,8 +79,8 @@ func (h *Handlers) PostEvents(c *gin.Context) { } } - // Save events - if err := h.storage.SaveEvents(events); err != nil { + // Add events + if err := h.storage.AddEvents(events); err != nil { log.Printf("PostEvents: failed to save events: %v", err) c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal server error"}) return diff --git a/src/handlers/user.go b/src/handlers/user.go index 6da8f63..7290271 100644 --- a/src/handlers/user.go +++ b/src/handlers/user.go @@ -60,7 +60,7 @@ func (h *Handlers) PostUserResetKey(c *gin.Context) { ".user.resetKey", "{}", ) - if err := h.storage.SaveEvents([]models.Event{*event}); err != nil { + if err := h.storage.AddEvents([]models.Event{*event}); err != nil { log.Printf("Failed to save reset key event for user %s: %v", userId, err) c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal server error"}) return @@ -123,7 +123,7 @@ func (h *Handlers) PostUserGenerateToken(c *gin.Context) { Action: ".user.generateToken", Payload: "{}", } - if err := h.storage.SaveEvents([]models.Event{event}); err != nil { + if err := h.storage.AddEvents([]models.Event{event}); err != nil { log.Printf("Failed to save generate token event for user %s: %v", userId, err) c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal server error"}) return @@ -162,7 +162,7 @@ func (h *Handlers) PostSetupExchangeToken(c *gin.Context) { Action: ".user.exchangeToken", Payload: "{}", } - if err := h.storage.SaveEvents([]models.Event{event}); err != nil { + if err := h.storage.AddEvents([]models.Event{event}); err != nil { log.Printf("Failed to save exchange token event for user %s: %v", apiKey.User, err) c.JSON(http.StatusInternalServerError, gin.H{"error": "Internal server error"}) return diff --git a/src/services/acl_service.go b/src/services/acl_service.go index f290ab3..8fd8252 100644 --- a/src/services/acl_service.go +++ b/src/services/acl_service.go @@ -113,7 +113,7 @@ func (s *AclService) AddRule(rule models.AclRule) error { s.mutex.Lock() defer s.mutex.Unlock() - err := s.storage.CreateAclRule(&rule) + err := s.storage.AddAclRule(&rule) if err != nil { return err } diff --git a/src/services/auth_service.go b/src/services/auth_service.go index 99a4e1b..81520cb 100644 --- a/src/services/auth_service.go +++ b/src/services/auth_service.go @@ -98,7 +98,7 @@ func (s *AuthService) GenerateApiKey(userID, description string) (*models.ApiKey apiKey := models.NewApiKey(userID, string(keyHash), description) // Store the API key - err = s.storage.CreateApiKey(apiKey) + err = s.storage.AddApiKey(apiKey) if err != nil { return nil, "", errors.New("failed to store API key") } @@ -134,7 +134,7 @@ func (s *AuthService) GenerateSetupToken(userID string) (*models.SetupToken, err setupToken := models.NewSetupToken(token, userID, expiresAt) // Store the setup token - err = s.storage.CreateSetupToken(setupToken) + err = s.storage.AddSetupToken(setupToken) if err != nil { return nil, errors.New("failed to store setup token") } diff --git a/src/storage/interface.go b/src/storage/interface.go index b2a2f8c..771f880 100644 --- a/src/storage/interface.go +++ b/src/storage/interface.go @@ -19,8 +19,7 @@ var ( // Storage defines the interface for data persistence type Storage interface { // Event operations - // TODO(#7): rename to AddEvents - SaveEvents(events []models.Event) error + AddEvents(events []models.Event) error LoadEvents() ([]models.Event, error) // User operations @@ -28,23 +27,20 @@ type Storage interface { GetUserById(id string) (*models.User, error) // API Key operations - // TODO(#7): rename to AddApiKey - CreateApiKey(apiKey *models.ApiKey) error + AddApiKey(apiKey *models.ApiKey) error GetApiKeyByHash(hash string) (*models.ApiKey, error) GetAllApiKeys() ([]*models.ApiKey, error) UpdateApiKey(apiKey *models.ApiKey) error InvalidateUserApiKeys(userID string) error // Setup Token operations - // TODO(#7): rename to AddSetupToken - CreateSetupToken(token *models.SetupToken) error + AddSetupToken(token *models.SetupToken) error GetSetupToken(token string) (*models.SetupToken, error) UpdateSetupToken(token *models.SetupToken) error InvalidateUserSetupTokens(userID string) error // ACL operations - // TODO(#7): rename to AddAclRule - CreateAclRule(rule *models.AclRule) error + AddAclRule(rule *models.AclRule) error GetAclRules() ([]models.AclRule, error) } diff --git a/src/storage/sqlite_storage.go b/src/storage/sqlite_storage.go index 7768f13..33574f2 100644 --- a/src/storage/sqlite_storage.go +++ b/src/storage/sqlite_storage.go @@ -99,7 +99,7 @@ func (s *SQLiteStorage) Close() error { return err } -func (s *SQLiteStorage) SaveEvents(events []models.Event) error { +func (s *SQLiteStorage) AddEvents(events []models.Event) error { if s.db == nil { return ErrInvalidData } @@ -203,7 +203,7 @@ func (s *SQLiteStorage) GetUserById(id string) (*models.User, error) { } return user, nil } -func (s *SQLiteStorage) CreateApiKey(apiKey *models.ApiKey) error { +func (s *SQLiteStorage) AddApiKey(apiKey *models.ApiKey) error { if s.db == nil || apiKey == nil { return ErrInvalidData } @@ -299,7 +299,7 @@ func (s *SQLiteStorage) InvalidateUserApiKeys(userID string) error { _, err := s.db.Exec(`DELETE FROM api_key WHERE user = ?`, userID) return err } -func (s *SQLiteStorage) CreateSetupToken(token *models.SetupToken) error { +func (s *SQLiteStorage) AddSetupToken(token *models.SetupToken) error { if s.db == nil || token == nil { return ErrInvalidData } @@ -350,7 +350,7 @@ func (s *SQLiteStorage) InvalidateUserSetupTokens(userID string) error { _, err := s.db.Exec(`UPDATE setup_token SET used_at = ? WHERE user = ?`, time.Now(), userID) return err } -func (s *SQLiteStorage) CreateAclRule(rule *models.AclRule) error { +func (s *SQLiteStorage) AddAclRule(rule *models.AclRule) error { if s.db == nil || rule == nil { return ErrInvalidData } diff --git a/src/storage/test.go b/src/storage/test.go index a47a767..5d140b7 100644 --- a/src/storage/test.go +++ b/src/storage/test.go @@ -48,7 +48,7 @@ func NewTestStorage(aclRules []models.AclRule) *TestStorage { CreatedAt: now, LastUsedAt: &now, } - storage.CreateApiKey(apiKey) + storage.AddApiKey(apiKey) // Add default user defaultUser, _ := models.NewUser(TestingUserId) @@ -64,7 +64,7 @@ func NewTestStorage(aclRules []models.AclRule) *TestStorage { CreatedAt: now, LastUsedAt: &now, } - storage.CreateApiKey(apiKey) + storage.AddApiKey(apiKey) // Add initial ACL rules as events for _, rule := range aclRules { @@ -81,8 +81,8 @@ func NewTestStorage(aclRules []models.AclRule) *TestStorage { return storage } -// SaveEvents appends new events to the storage -func (m *TestStorage) SaveEvents(events []models.Event) error { +// AddEvents appends new events to the storage +func (m *TestStorage) AddEvents(events []models.Event) error { m.mutex.Lock() defer m.mutex.Unlock() m.events = append(m.events, events...) @@ -131,8 +131,8 @@ func (m *TestStorage) AddUser(user *models.User) error { return nil } -// CreateApiKey stores a new API key -func (m *TestStorage) CreateApiKey(apiKey *models.ApiKey) error { +// AddApiKey stores a new API key +func (m *TestStorage) AddApiKey(apiKey *models.ApiKey) error { m.mutex.Lock() defer m.mutex.Unlock() m.apiKeys[apiKey.UUID] = apiKey @@ -170,8 +170,8 @@ func (m *TestStorage) UpdateApiKey(apiKey *models.ApiKey) error { return nil } -// CreateSetupToken stores a new setup token -func (m *TestStorage) CreateSetupToken(token *models.SetupToken) error { +// AddSetupToken stores a new setup token +func (m *TestStorage) AddSetupToken(token *models.SetupToken) error { m.mutex.Lock() defer m.mutex.Unlock() m.setupTokens[token.Token] = token @@ -222,8 +222,8 @@ func (m *TestStorage) InvalidateUserApiKeys(userID string) error { return nil } -// CreateAclRule stores a new ACL rule -func (m *TestStorage) CreateAclRule(rule *models.AclRule) error { +// AddAclRule stores a new ACL rule +func (m *TestStorage) AddAclRule(rule *models.AclRule) error { m.mutex.Lock() defer m.mutex.Unlock() diff --git a/tests/performance/save_load_performance_test.go b/tests/performance/save_load_performance_test.go index 361db1f..fab6378 100644 --- a/tests/performance/save_load_performance_test.go +++ b/tests/performance/save_load_performance_test.go @@ -9,8 +9,8 @@ import ( "github.com/stretchr/testify/assert" ) -// TestSaveEventsPerformance measures save time for many events -func TestSaveEventsPerformance(t *testing.T) { +// TestAddEventsPerformance measures save time for many events +func TestAddEventsPerformance(t *testing.T) { events := GenerateEvents(1_000_000) s := storage.NewSQLiteStorage() @@ -22,11 +22,11 @@ func TestSaveEventsPerformance(t *testing.T) { defer s.Close() start := time.Now() - if err := s.SaveEvents(events); err != nil { + if err := s.AddEvents(events); err != nil { t.Fatalf("save events failed: %v", err) } d := time.Since(start) - assert.Less(t, d, 8*time.Second, "Save for 1 million events should complete in under 8s") + assert.Less(t, d, 8*time.Second, "Adding 1 million events should complete in under 8s") } // TestLoadEventsPerformance measures load time for many events @@ -42,7 +42,7 @@ func TestLoadEventsPerformance(t *testing.T) { defer s.Close() // Pre-populate the DB (not measured) - if err := s.SaveEvents(events); err != nil { + if err := s.AddEvents(events); err != nil { t.Fatalf("pre-populate save events failed: %v", err) } @@ -51,5 +51,5 @@ func TestLoadEventsPerformance(t *testing.T) { t.Fatalf("load events failed: %v", err) } d := time.Since(start) - assert.Less(t, d, 4*time.Second, "Load for 1 million events should complete in under 4s") + assert.Less(t, d, 4*time.Second, "Loading 1 million events should complete in under 4s") } diff --git a/tests/performance/sqlite_concurrency_test.go b/tests/performance/sqlite_concurrency_test.go index 53eb517..f12db3b 100644 --- a/tests/performance/sqlite_concurrency_test.go +++ b/tests/performance/sqlite_concurrency_test.go @@ -53,7 +53,7 @@ func TestSQLiteStorageConcurrent(t *testing.T) { e := models.NewEvent("concurrent-user", "item", "action", "payload") events = append(events, *e) } - if err := s.SaveEvents(events); err != nil { + if err := s.AddEvents(events); err != nil { errCh <- err return } diff --git a/tests/unit/acl_service_test.go b/tests/unit/acl_service_test.go index 0917214..88c9a1e 100644 --- a/tests/unit/acl_service_test.go +++ b/tests/unit/acl_service_test.go @@ -14,7 +14,6 @@ import ( func TestAclService_LoadsRulesFromStorage(t *testing.T) { store := storage.NewTestStorage(nil) - // Create ACL rules in storage rule1 := models.AclRule{ User: "user1", Item: "item1", @@ -28,9 +27,9 @@ func TestAclService_LoadsRulesFromStorage(t *testing.T) { Type: "deny", } - err := store.CreateAclRule(&rule1) + err := store.AddAclRule(&rule1) assert.NoError(t, err) - err = store.CreateAclRule(&rule2) + err = store.AddAclRule(&rule2) assert.NoError(t, err) // Create ACL service - should load rules from storage @@ -181,7 +180,7 @@ func TestAclService_AddRule_ErrorHandling(t *testing.T) { // failingStorage is a mock storage that always fails type failingStorage struct{} -func (f *failingStorage) SaveEvents(events []models.Event) error { +func (f *failingStorage) AddEvents(events []models.Event) error { return fmt.Errorf("storage error") } @@ -197,7 +196,7 @@ func (f *failingStorage) GetUserById(id string) (*models.User, error) { return nil, fmt.Errorf("storage error") } -func (f *failingStorage) CreateApiKey(apiKey *models.ApiKey) error { +func (f *failingStorage) AddApiKey(apiKey *models.ApiKey) error { return fmt.Errorf("storage error") } @@ -217,7 +216,7 @@ func (f *failingStorage) InvalidateUserApiKeys(userID string) error { return fmt.Errorf("storage error") } -func (f *failingStorage) CreateSetupToken(token *models.SetupToken) error { +func (f *failingStorage) AddSetupToken(token *models.SetupToken) error { return fmt.Errorf("storage error") } @@ -233,7 +232,7 @@ func (f *failingStorage) InvalidateUserSetupTokens(userID string) error { return fmt.Errorf("storage error") } -func (f *failingStorage) CreateAclRule(rule *models.AclRule) error { +func (f *failingStorage) AddAclRule(rule *models.AclRule) error { return fmt.Errorf("storage error") } diff --git a/tests/unit/acl_storage_sqlite_test.go b/tests/unit/acl_storage_sqlite_test.go index a01b489..5ca66e1 100644 --- a/tests/unit/acl_storage_sqlite_test.go +++ b/tests/unit/acl_storage_sqlite_test.go @@ -8,7 +8,7 @@ import ( "simple-sync/src/storage" ) -func TestSQLiteCreateAclRuleAndGetAclRules(t *testing.T) { +func TestSQLiteAddAclRuleAndGetAclRules(t *testing.T) { store := storage.NewSQLiteStorage() if err := store.Initialize(":memory:"); err != nil { t.Fatalf("failed to initialize sqlite storage: %v", err) @@ -23,7 +23,7 @@ func TestSQLiteCreateAclRuleAndGetAclRules(t *testing.T) { } // Create rule - if err := store.CreateAclRule(&rule); err != nil { + if err := store.AddAclRule(&rule); err != nil { t.Fatalf("expected no error creating rule, got %v", err) } @@ -51,7 +51,7 @@ func TestSQLiteCreateAclRuleAndGetAclRules(t *testing.T) { } } -func TestSQLiteCreateAclRuleDuplicate(t *testing.T) { +func TestSQLiteAddAclRuleDuplicate(t *testing.T) { store := storage.NewSQLiteStorage() if err := store.Initialize(":memory:"); err != nil { t.Fatalf("failed to initialize sqlite storage: %v", err) @@ -65,12 +65,12 @@ func TestSQLiteCreateAclRuleDuplicate(t *testing.T) { Type: "allow", } - if err := store.CreateAclRule(&rule); err != nil { + if err := store.AddAclRule(&rule); err != nil { t.Fatalf("expected no error creating rule first time, got %v", err) } // Second insert should result in duplicate key error - if err := store.CreateAclRule(&rule); err == nil { + if err := store.AddAclRule(&rule); err == nil { t.Fatalf("expected duplicate key error, got nil") } else { if !strings.Contains(err.Error(), "duplicate") && err != storage.ErrDuplicateKey { @@ -110,7 +110,7 @@ func TestSQLiteAclRulesPreserveInsertionOrder(t *testing.T) { } for i := range rulesToInsert { - if err := store.CreateAclRule(&rulesToInsert[i]); err != nil { + if err := store.AddAclRule(&rulesToInsert[i]); err != nil { t.Fatalf("failed to create rule %d: %v", i, err) } } diff --git a/tests/unit/acl_storage_test.go b/tests/unit/acl_storage_test.go index e782302..210907d 100644 --- a/tests/unit/acl_storage_test.go +++ b/tests/unit/acl_storage_test.go @@ -8,7 +8,7 @@ import ( "simple-sync/src/storage" ) -func TestCreateAclRule(t *testing.T) { +func TestAddAclRule(t *testing.T) { testStorage := storage.NewTestStorage([]models.AclRule{}) rule := models.AclRule{ @@ -18,7 +18,7 @@ func TestCreateAclRule(t *testing.T) { Type: "allow", } - err := testStorage.CreateAclRule(&rule) + err := testStorage.AddAclRule(&rule) if err != nil { t.Fatalf("Expected no error, got %v", err) } @@ -118,7 +118,7 @@ func TestGetAclRulesEmpty(t *testing.T) { } } -func TestCreateAclRuleAndGetAclRulesIntegration(t *testing.T) { +func TestAddAclRuleAndGetAclRulesIntegration(t *testing.T) { testStorage := storage.NewTestStorage([]models.AclRule{}) // Add multiple rules @@ -144,7 +144,7 @@ func TestCreateAclRuleAndGetAclRulesIntegration(t *testing.T) { } for i := range rules { - err := testStorage.CreateAclRule(&rules[i]) + err := testStorage.AddAclRule(&rules[i]) if err != nil { t.Fatalf("Expected no error creating rule %d, got %v", i, err) } @@ -190,7 +190,7 @@ func TestGetAclRulesWithMalformedRule(t *testing.T) { Action: "read", Type: "allow", } - err := testStorage.CreateAclRule(&validRule) + err := testStorage.AddAclRule(&validRule) if err != nil { t.Fatalf("Expected no error creating valid rule, got %v", err) } @@ -202,7 +202,7 @@ func TestGetAclRulesWithMalformedRule(t *testing.T) { Action: ".acl.addRule", Payload: "{invalid json}", } - err = testStorage.SaveEvents([]models.Event{malformedEvent}) + err = testStorage.AddEvents([]models.Event{malformedEvent}) if err != nil { t.Fatalf("Expected no error saving malformed event, got %v", err) } diff --git a/tests/unit/event_storage_sqlite_test.go b/tests/unit/event_storage_sqlite_test.go index 7e69a89..7887824 100644 --- a/tests/unit/event_storage_sqlite_test.go +++ b/tests/unit/event_storage_sqlite_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestSaveAndLoadEvents(t *testing.T) { +func TestAddAndLoadEvents(t *testing.T) { s := storage.NewSQLiteStorage() if err := s.Initialize(":memory:"); err != nil { t.Fatalf("failed to initialize in-memory sqlite: %v", err) @@ -22,8 +22,8 @@ func TestSaveAndLoadEvents(t *testing.T) { time.Sleep(1 * time.Millisecond) e2 := models.NewEvent("user2", "item2", "act2", "payload2") - if err := s.SaveEvents([]models.Event{*e1, *e2}); err != nil { - t.Fatalf("SaveEvents failed: %v", err) + if err := s.AddEvents([]models.Event{*e1, *e2}); err != nil { + t.Fatalf("AddEvents failed: %v", err) } events, err := s.LoadEvents() @@ -36,7 +36,7 @@ func TestSaveAndLoadEvents(t *testing.T) { assert.Equal(t, e2.UUID, events[1].UUID) } -func TestSaveEventsDuplicateUUID(t *testing.T) { +func TestAddEventsDuplicateUUID(t *testing.T) { s := storage.NewSQLiteStorage() if err := s.Initialize(":memory:"); err != nil { t.Fatalf("failed to initialize in-memory sqlite: %v", err) @@ -44,12 +44,12 @@ func TestSaveEventsDuplicateUUID(t *testing.T) { defer s.Close() e := models.NewEvent("user1", "item1", "act1", "payload1") - if err := s.SaveEvents([]models.Event{*e}); err != nil { - t.Fatalf("first SaveEvents failed: %v", err) + if err := s.AddEvents([]models.Event{*e}); err != nil { + t.Fatalf("first AddEvents failed: %v", err) } // attempt to insert duplicate - if err := s.SaveEvents([]models.Event{*e}); err == nil { - t.Fatalf("expected duplicate SaveEvents to fail") + if err := s.AddEvents([]models.Event{*e}); err == nil { + t.Fatalf("expected duplicate AddEvents to fail") } else { assert.Equal(t, storage.ErrDuplicateKey, err) } diff --git a/tests/unit/sqlite_api_key_storage_test.go b/tests/unit/sqlite_api_key_storage_test.go index ba0752f..c148b85 100644 --- a/tests/unit/sqlite_api_key_storage_test.go +++ b/tests/unit/sqlite_api_key_storage_test.go @@ -27,8 +27,8 @@ func TestCreateAndGetApiKeyByHash(t *testing.T) { } key := models.NewApiKey("user-x", "hash123", "test") - if err := s.CreateApiKey(key); err != nil { - t.Fatalf("CreateApiKey failed: %v", err) + if err := s.AddApiKey(key); err != nil { + t.Fatalf("AddApiKey failed: %v", err) } got, err := s.GetApiKeyByHash("hash123") @@ -50,11 +50,11 @@ func TestGetAllApiKeysAndUpdateInvalidate(t *testing.T) { k1 := models.NewApiKey("user-y", "hash-a", "one") k2 := models.NewApiKey("user-y", "hash-b", "two") - if err := s.CreateApiKey(k1); err != nil { - t.Fatalf("CreateApiKey k1 failed: %v", err) + if err := s.AddApiKey(k1); err != nil { + t.Fatalf("AddApiKey k1 failed: %v", err) } - if err := s.CreateApiKey(k2); err != nil { - t.Fatalf("CreateApiKey k2 failed: %v", err) + if err := s.AddApiKey(k2); err != nil { + t.Fatalf("AddApiKey k2 failed: %v", err) } all, err := s.GetAllApiKeys() diff --git a/tests/unit/sqlite_setup_token_storage_test.go b/tests/unit/sqlite_setup_token_storage_test.go index 1ffecec..29dc79c 100644 --- a/tests/unit/sqlite_setup_token_storage_test.go +++ b/tests/unit/sqlite_setup_token_storage_test.go @@ -21,8 +21,8 @@ func TestCreateGetUpdateInvalidateSetupToken(t *testing.T) { } st := models.NewSetupToken("ABCD-1234", "user-z", time.Now().Add(time.Hour)) - if err := s.CreateSetupToken(st); err != nil { - t.Fatalf("CreateSetupToken failed: %v", err) + if err := s.AddSetupToken(st); err != nil { + t.Fatalf("AddSetupToken failed: %v", err) } got, err := s.GetSetupToken("ABCD-1234")