Skip to content

Commit 75acd16

Browse files
FEATURE (backups): Add tests for succesful and failed backup notification sending
1 parent 3ad4adb commit 75acd16

File tree

17 files changed

+401
-45
lines changed

17 files changed

+401
-45
lines changed

backend/go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ require (
102102
github.com/rogpeppe/go-internal v1.14.1 // indirect
103103
github.com/rs/xid v1.6.0 // indirect
104104
github.com/sirupsen/logrus v1.9.3 // indirect
105+
github.com/stretchr/objx v0.5.2 // indirect
105106
github.com/tinylib/msgp v1.3.0 // indirect
106107
github.com/tklauser/go-sysconf v0.3.15 // indirect
107108
github.com/tklauser/numcpus v0.10.0 // indirect

backend/internal/features/backups/di.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ var backupService = &BackupService{
1616
storages.GetStorageService(),
1717
backupRepository,
1818
notifiers.GetNotifierService(),
19+
notifiers.GetNotifierService(),
1920
usecases.GetCreateBackupUsecase(),
2021
logger.GetLogger(),
2122
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package backups
2+
3+
import (
4+
"postgresus-backend/internal/features/databases"
5+
"postgresus-backend/internal/features/notifiers"
6+
"postgresus-backend/internal/features/storages"
7+
8+
"github.com/google/uuid"
9+
)
10+
11+
type NotificationSender interface {
12+
SendNotification(
13+
notifier *notifiers.Notifier,
14+
title string,
15+
message string,
16+
)
17+
}
18+
19+
type CreateBackupUsecase interface {
20+
Execute(
21+
backupID uuid.UUID,
22+
database *databases.Database,
23+
storage *storages.Storage,
24+
backupProgressListener func(
25+
completedMBs float64,
26+
),
27+
) error
28+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package backups
2+
3+
import (
4+
"postgresus-backend/internal/features/notifiers"
5+
6+
"github.com/stretchr/testify/mock"
7+
)
8+
9+
type MockNotificationSender struct {
10+
mock.Mock
11+
}
12+
13+
func (m *MockNotificationSender) SendNotification(
14+
notifier *notifiers.Notifier,
15+
title string,
16+
message string,
17+
) {
18+
m.Called(notifier, title, message)
19+
}

backend/internal/features/backups/service.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"errors"
55
"fmt"
66
"log/slog"
7-
"postgresus-backend/internal/features/backups/usecases"
87
"postgresus-backend/internal/features/databases"
98
"postgresus-backend/internal/features/notifiers"
109
"postgresus-backend/internal/features/storages"
@@ -16,12 +15,13 @@ import (
1615
)
1716

1817
type BackupService struct {
19-
databaseService *databases.DatabaseService
20-
storageService *storages.StorageService
21-
backupRepository *BackupRepository
22-
notifierService *notifiers.NotifierService
18+
databaseService *databases.DatabaseService
19+
storageService *storages.StorageService
20+
backupRepository *BackupRepository
21+
notifierService *notifiers.NotifierService
22+
notificationSender NotificationSender
2323

24-
createBackupUseCase *usecases.CreateBackupUsecase
24+
createBackupUseCase CreateBackupUsecase
2525

2626
logger *slog.Logger
2727
}
@@ -308,7 +308,7 @@ func (s *BackupService) SendBackupNotification(
308308
)
309309
}
310310

311-
s.notifierService.SendNotification(
311+
s.notificationSender.SendNotification(
312312
&notifier,
313313
title,
314314
message,
Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
package backups
2+
3+
import (
4+
"errors"
5+
"postgresus-backend/internal/features/databases"
6+
"postgresus-backend/internal/features/notifiers"
7+
"postgresus-backend/internal/features/storages"
8+
"postgresus-backend/internal/features/users"
9+
"postgresus-backend/internal/util/logger"
10+
"strings"
11+
"testing"
12+
13+
"github.com/google/uuid"
14+
"github.com/stretchr/testify/assert"
15+
"github.com/stretchr/testify/mock"
16+
)
17+
18+
func Test_BackupExecuted_NotificationSent(t *testing.T) {
19+
user := users.GetTestUser()
20+
storage := storages.CreateTestStorage(user.UserID)
21+
notifier := notifiers.CreateTestNotifier(user.UserID)
22+
database := databases.CreateTestDatabase(user.UserID, storage, notifier)
23+
24+
t.Run("BackupFailed_FailNotificationSent", func(t *testing.T) {
25+
mockNotificationSender := &MockNotificationSender{}
26+
backupService := &BackupService{
27+
databases.GetDatabaseService(),
28+
storages.GetStorageService(),
29+
backupRepository,
30+
notifiers.GetNotifierService(),
31+
mockNotificationSender,
32+
&CreateFailedBackupUsecase{},
33+
logger.GetLogger(),
34+
}
35+
36+
// Set up expectations
37+
mockNotificationSender.On("SendNotification",
38+
mock.Anything,
39+
mock.MatchedBy(func(title string) bool {
40+
return strings.Contains(title, "❌ Backup failed")
41+
}),
42+
mock.MatchedBy(func(message string) bool {
43+
return strings.Contains(message, "backup failed")
44+
}),
45+
).Once()
46+
47+
backupService.MakeBackup(database.ID)
48+
49+
// Verify all expectations were met
50+
mockNotificationSender.AssertExpectations(t)
51+
})
52+
53+
t.Run("BackupSuccess_SuccessNotificationSent", func(t *testing.T) {
54+
mockNotificationSender := &MockNotificationSender{}
55+
56+
// Set up expectations
57+
mockNotificationSender.On("SendNotification",
58+
mock.Anything,
59+
mock.MatchedBy(func(title string) bool {
60+
return strings.Contains(title, "✅ Backup completed")
61+
}),
62+
mock.MatchedBy(func(message string) bool {
63+
return strings.Contains(message, "Backup completed successfully")
64+
}),
65+
).Once()
66+
67+
backupService := &BackupService{
68+
databases.GetDatabaseService(),
69+
storages.GetStorageService(),
70+
backupRepository,
71+
notifiers.GetNotifierService(),
72+
mockNotificationSender,
73+
&CreateSuccessBackupUsecase{},
74+
logger.GetLogger(),
75+
}
76+
77+
backupService.MakeBackup(database.ID)
78+
79+
// Verify all expectations were met
80+
mockNotificationSender.AssertExpectations(t)
81+
})
82+
83+
t.Run("BackupSuccess_VerifyNotificationContent", func(t *testing.T) {
84+
mockNotificationSender := &MockNotificationSender{}
85+
backupService := &BackupService{
86+
databases.GetDatabaseService(),
87+
storages.GetStorageService(),
88+
backupRepository,
89+
notifiers.GetNotifierService(),
90+
mockNotificationSender,
91+
&CreateSuccessBackupUsecase{},
92+
logger.GetLogger(),
93+
}
94+
95+
// capture arguments
96+
var capturedNotifier *notifiers.Notifier
97+
var capturedTitle string
98+
var capturedMessage string
99+
100+
mockNotificationSender.On("SendNotification",
101+
mock.Anything,
102+
mock.AnythingOfType("string"),
103+
mock.AnythingOfType("string"),
104+
).Run(func(args mock.Arguments) {
105+
capturedNotifier = args.Get(0).(*notifiers.Notifier)
106+
capturedTitle = args.Get(1).(string)
107+
capturedMessage = args.Get(2).(string)
108+
}).Once()
109+
110+
backupService.MakeBackup(database.ID)
111+
112+
// Verify expectations were met
113+
mockNotificationSender.AssertExpectations(t)
114+
115+
// Additional detailed assertions
116+
assert.Contains(t, capturedTitle, "✅ Backup completed")
117+
assert.Contains(t, capturedTitle, database.Name)
118+
assert.Contains(t, capturedMessage, "Backup completed successfully")
119+
assert.Contains(t, capturedMessage, "10.00 MB")
120+
assert.Equal(t, notifier.ID, capturedNotifier.ID)
121+
})
122+
}
123+
124+
type CreateFailedBackupUsecase struct {
125+
}
126+
127+
func (uc *CreateFailedBackupUsecase) Execute(
128+
backupID uuid.UUID,
129+
database *databases.Database,
130+
storage *storages.Storage,
131+
backupProgressListener func(
132+
completedMBs float64,
133+
),
134+
) error {
135+
backupProgressListener(10) // Assume we completed 10MB
136+
return errors.New("backup failed")
137+
}
138+
139+
type CreateSuccessBackupUsecase struct {
140+
}
141+
142+
func (uc *CreateSuccessBackupUsecase) Execute(
143+
backupID uuid.UUID,
144+
database *databases.Database,
145+
storage *storages.Storage,
146+
backupProgressListener func(
147+
completedMBs float64,
148+
),
149+
) error {
150+
backupProgressListener(10) // Assume we completed 10MB
151+
return nil
152+
}

backend/internal/features/databases/repository.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010

1111
type DatabaseRepository struct{}
1212

13-
func (r *DatabaseRepository) Save(database *Database) error {
13+
func (r *DatabaseRepository) Save(database *Database) (*Database, error) {
1414
db := storage.GetDb()
1515

1616
isNew := database.ID == uuid.Nil
@@ -20,7 +20,7 @@ func (r *DatabaseRepository) Save(database *Database) error {
2020

2121
database.StorageID = database.Storage.ID
2222

23-
return db.Transaction(func(tx *gorm.DB) error {
23+
err := db.Transaction(func(tx *gorm.DB) error {
2424
if database.BackupInterval != nil {
2525
if database.BackupInterval.ID == uuid.Nil {
2626
if err := tx.Create(database.BackupInterval).Error; err != nil {
@@ -82,6 +82,12 @@ func (r *DatabaseRepository) Save(database *Database) error {
8282

8383
return nil
8484
})
85+
86+
if err != nil {
87+
return nil, err
88+
}
89+
90+
return database, nil
8591
}
8692

8793
func (r *DatabaseRepository) FindByID(id uuid.UUID) (*Database, error) {

backend/internal/features/databases/service.go

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@ func (s *DatabaseService) CreateDatabase(
3131
return err
3232
}
3333

34-
return s.dbRepository.Save(database)
34+
_, err := s.dbRepository.Save(database)
35+
if err != nil {
36+
return err
37+
}
38+
39+
return nil
3540
}
3641

3742
func (s *DatabaseService) UpdateDatabase(
@@ -71,7 +76,12 @@ func (s *DatabaseService) UpdateDatabase(
7176
}
7277
}
7378

74-
return s.dbRepository.Save(database)
79+
_, err = s.dbRepository.Save(database)
80+
if err != nil {
81+
return err
82+
}
83+
84+
return nil
7585
}
7686

7787
func (s *DatabaseService) DeleteDatabase(
@@ -142,7 +152,12 @@ func (s *DatabaseService) TestDatabaseConnection(
142152

143153
database.LastBackupErrorMessage = nil
144154

145-
return s.dbRepository.Save(database)
155+
_, err = s.dbRepository.Save(database)
156+
if err != nil {
157+
return err
158+
}
159+
160+
return nil
146161
}
147162

148163
func (s *DatabaseService) TestDatabaseConnectionDirect(
@@ -168,7 +183,12 @@ func (s *DatabaseService) SetBackupError(databaseID uuid.UUID, errorMessage stri
168183
}
169184

170185
database.LastBackupErrorMessage = &errorMessage
171-
return s.dbRepository.Save(database)
186+
_, err = s.dbRepository.Save(database)
187+
if err != nil {
188+
return err
189+
}
190+
191+
return nil
172192
}
173193

174194
func (s *DatabaseService) SetLastBackupTime(databaseID uuid.UUID, backupTime time.Time) error {
@@ -179,5 +199,10 @@ func (s *DatabaseService) SetLastBackupTime(databaseID uuid.UUID, backupTime tim
179199

180200
database.LastBackupTime = &backupTime
181201
database.LastBackupErrorMessage = nil // Clear any previous error
182-
return s.dbRepository.Save(database)
202+
_, err = s.dbRepository.Save(database)
203+
if err != nil {
204+
return err
205+
}
206+
207+
return nil
183208
}

0 commit comments

Comments
 (0)