fix(finance): fix 3 store bugs found by integration tests; add store_integration_test.go (#35)
The integration tests (testcontainers + mongo:7) exposed three real bugs:
1. deleteAllUserData filtered with bson.ObjectID on collections that store
user_id as a plain string (Account, Goal, Property, etc.) — none of them
were actually deleted. Fixed by using the original string userID for those
collections; only finance_sessions (AuthSession.UserID is ObjectID) keeps
the ObjectID filter.
2. consumeInvite correctly sets used_at, but the test was calling
getInviteByToken afterwards and expecting the invite back — that query
intentionally excludes used invites ($exists: false). Fixed the assertion
to check that the token is no longer redeemable (nil return = correct).
3. createEvent stored GoalItems as null when the slice was nil; subsequent
$push on a null field fails in MongoDB. Fixed by initialising GoalItems
to []EventGoal{} before insert so the field is always an array.
Combined unit + integration coverage: 64.7% → 79.8%
Co-authored-by: Gonçalo Rodrigues <guga@Goncalos-MacBook-Pro.local>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
91796c9fb9
commit
40c8632c7e
@ -118,26 +118,27 @@ func (s *Store) deleteAllUserData(ctx context.Context, userID string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
filter := bson.M{"user_id": uid}
|
||||
orFilter := bson.M{"$or": bson.A{bson.M{"owner_id": uid}, bson.M{"partner_id": uid}}}
|
||||
orFilterPerms := bson.M{"$or": bson.A{bson.M{"owner_id": uid}, bson.M{"viewer_id": uid}}}
|
||||
// Most collections store user_id as a plain string; only sessions use ObjectID.
|
||||
strFilter := bson.M{"user_id": userID}
|
||||
orFilter := bson.M{"$or": bson.A{bson.M{"owner_id": userID}, bson.M{"partner_id": userID}}}
|
||||
orFilterPerms := bson.M{"$or": bson.A{bson.M{"owner_id": userID}, bson.M{"viewer_id": userID}}}
|
||||
|
||||
collections := []struct {
|
||||
name string
|
||||
filter interface{}
|
||||
}{
|
||||
{"finance_accounts", filter},
|
||||
{"finance_categories", filter},
|
||||
{"finance_transactions", filter},
|
||||
{"finance_trades", filter},
|
||||
{"finance_ticker_mappings", filter},
|
||||
{"finance_goals", filter},
|
||||
{"finance_import_schedules", filter},
|
||||
{"finance_properties", filter},
|
||||
{"finance_loans", filter},
|
||||
{"finance_accounts", strFilter},
|
||||
{"finance_categories", strFilter},
|
||||
{"finance_transactions", strFilter},
|
||||
{"finance_trades", strFilter},
|
||||
{"finance_ticker_mappings", strFilter},
|
||||
{"finance_goals", strFilter},
|
||||
{"finance_import_schedules", strFilter},
|
||||
{"finance_properties", strFilter},
|
||||
{"finance_loans", strFilter},
|
||||
{"finance_permissions", orFilterPerms},
|
||||
{"finance_households", orFilter},
|
||||
{"finance_sessions", bson.M{"user_id": uid}},
|
||||
{"finance_sessions", bson.M{"user_id": uid}}, // AuthSession.UserID is bson.ObjectID
|
||||
}
|
||||
for _, c := range collections {
|
||||
if _, err := s.db.Collection(c.name).DeleteMany(ctx, c.filter); err != nil {
|
||||
|
||||
1063
apps/finance/services/api/main/store_integration_test.go
Normal file
1063
apps/finance/services/api/main/store_integration_test.go
Normal file
File diff suppressed because it is too large
Load Diff
@ -392,6 +392,10 @@ func (s *Store) getEvent(ctx context.Context, eventID, orgID string) (*OrgEvent,
|
||||
func (s *Store) createEvent(ctx context.Context, e *OrgEvent) error {
|
||||
ctx, span := mongo.StartSpan(ctx, "Store.createEvent")
|
||||
defer span.End()
|
||||
// Ensure goal_items is always an array so $push works without a null-field error.
|
||||
if e.GoalItems == nil {
|
||||
e.GoalItems = []EventGoal{}
|
||||
}
|
||||
_, err := s.orgEvents().InsertOne(ctx, e)
|
||||
return err
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user