Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion specs/7-data-persistence.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`)
2 changes: 1 addition & 1 deletion src/handlers/acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions src/handlers/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions src/handlers/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/services/acl_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions src/services/auth_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand Down Expand Up @@ -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")
}
Expand Down
12 changes: 4 additions & 8 deletions src/storage/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,32 +19,28 @@ 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
AddUser(user *models.User) error
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)
}

Expand Down
8 changes: 4 additions & 4 deletions src/storage/sqlite_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down
20 changes: 10 additions & 10 deletions src/storage/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 {
Expand All @@ -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...)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()

Expand Down
12 changes: 6 additions & 6 deletions tests/performance/save_load_performance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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
Expand All @@ -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)
}

Expand All @@ -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")
}
2 changes: 1 addition & 1 deletion tests/performance/sqlite_concurrency_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
13 changes: 6 additions & 7 deletions tests/unit/acl_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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
Expand Down Expand Up @@ -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")
}

Expand All @@ -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")
}

Expand All @@ -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")
}

Expand All @@ -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")
}

Expand Down
12 changes: 6 additions & 6 deletions tests/unit/acl_storage_sqlite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
}

Expand Down Expand Up @@ -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)
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
}
}
Expand Down
Loading