Skip to content

Commit 430cc8c

Browse files
committed
test, refactor: Tests for reset-password & change mails structure for easier mocks
1 parent 556f8fa commit 430cc8c

13 files changed

+465
-49
lines changed

Diff for: mails/mails.go renamed to mails/init.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@ import (
99

1010
var (
1111
smtpClient *mail.SMTPClient
12+
Service *service
1213
)
1314

14-
func InitClient() {
15+
func InitService() {
1516
server := mail.NewSMTPClient()
1617
server.Host = env.SmtpHost
1718
port, err := strconv.ParseUint(env.SmtpPort, 10, 32)
@@ -22,9 +23,11 @@ func InitClient() {
2223
server.Username = env.SmtpUsername
2324
server.Password = env.SmtpPassword
2425

25-
client, err := server.Connect()
26+
c, err := server.Connect()
2627
if err != nil {
2728
log.Fatal(err)
2829
}
29-
smtpClient = client
30+
31+
smtpClient = c
32+
Service = GetService(&Client{})
3033
}

Diff for: mails/mails.client.go

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package mails
2+
3+
import (
4+
mail "github.com/xhit/go-simple-mail/v2"
5+
)
6+
7+
type Message struct {
8+
From string
9+
To string
10+
Subject string
11+
Body string
12+
}
13+
14+
type C interface {
15+
Send(*Message) error
16+
}
17+
18+
type Client struct{}
19+
20+
func (c *Client) Send(message *Message) error {
21+
msg := mail.NewMSG()
22+
msg.SetFrom(message.From)
23+
msg.AddTo(message.To)
24+
msg.SetSubject(message.Subject)
25+
msg.SetBody(mail.TextPlain, message.Body)
26+
err := msg.Send(smtpClient)
27+
28+
return err
29+
}

Diff for: mails/mails.client_mock.go

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package mails
2+
3+
import "github.com/stretchr/testify/mock"
4+
5+
type ClientMock struct {
6+
mock.Mock
7+
}
8+
9+
func (m *ClientMock) Send(message *Message) error {
10+
args := m.Called(message)
11+
err := args.Error(0)
12+
return err
13+
}

Diff for: mails/mails.service.go

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package mails
2+
3+
import (
4+
"fmt"
5+
"messagewith-server/env"
6+
)
7+
8+
var (
9+
client C
10+
)
11+
12+
type service struct{}
13+
14+
func GetService(c C) *service {
15+
client = c
16+
return &service{}
17+
}
18+
19+
func (s *service) SendResetPasswordToken(email string, token string) bool {
20+
err := client.Send(&Message{
21+
From: fmt.Sprintf("Messagewith <%v>", env.SmtpEmail),
22+
To: email,
23+
Subject: "Reset your password on Messagewith.app",
24+
Body: fmt.Sprintf("Your reset password token is: %v", token),
25+
})
26+
27+
if err != nil {
28+
return false
29+
}
30+
31+
return true
32+
}

Diff for: mails/reset-password.go

-23
This file was deleted.

Diff for: main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func initDatabaseConnection() {
4242
func main() {
4343
env.InitEnvConstants()
4444
initDatabaseConnection()
45-
mails.InitClient()
45+
mails.InitService()
4646
users.InitService()
4747
sessions.InitService()
4848
auth.InitService()

Diff for: users/init.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import (
66
)
77

88
var (
9-
Service *service
10-
collection *mgm.Collection
9+
Service *service
10+
collection *mgm.Collection
11+
resetPasswordCollection *mgm.Collection
1112
)
1213

1314
func InitService() {
1415
collection = database.GetDB().UseCollection()
15-
Service = GetService(&Repository{})
16+
resetPasswordCollection = database.GetResetPasswordDB().UseCollection()
17+
Service = GetService(&Repository{}, &ResetPasswordRepository{})
1618
}

Diff for: users/reset-password.repository.go

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package users
2+
3+
import (
4+
"context"
5+
"go.mongodb.org/mongo-driver/mongo"
6+
database "messagewith-server/users/database"
7+
)
8+
9+
type RP interface {
10+
FindOne(ctx context.Context, filter interface{}) (*database.ResetPassword, error)
11+
DeleteOne(ctx context.Context, filter interface{}) (*mongo.DeleteResult, error)
12+
Create(document *database.ResetPassword) error
13+
}
14+
15+
type ResetPasswordRepository struct{}
16+
17+
func (r *ResetPasswordRepository) Create(document *database.ResetPassword) error {
18+
err := resetPasswordCollection.Create(document)
19+
20+
return err
21+
}
22+
23+
func (r *ResetPasswordRepository) FindOne(ctx context.Context, filter interface{}) (*database.ResetPassword, error) {
24+
res := &database.ResetPassword{}
25+
err := resetPasswordCollection.FindOne(ctx, filter).Decode(res)
26+
if err != nil {
27+
return nil, err
28+
}
29+
30+
return res, nil
31+
}
32+
33+
func (r *ResetPasswordRepository) DeleteOne(ctx context.Context, filter interface{}) (*mongo.DeleteResult, error) {
34+
res, err := resetPasswordCollection.DeleteOne(ctx, filter)
35+
36+
return res, err
37+
}

Diff for: users/reset-password.repository_mock.go

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
package users
2+
3+
import (
4+
"context"
5+
"github.com/naamancurtis/mongo-go-struct-to-bson/mapper"
6+
"github.com/stretchr/testify/mock"
7+
"go.mongodb.org/mongo-driver/bson/primitive"
8+
"go.mongodb.org/mongo-driver/mongo"
9+
database "messagewith-server/users/database"
10+
"reflect"
11+
)
12+
13+
type ResetPasswordMockRepository struct {
14+
mock.Mock
15+
}
16+
17+
func (m *ResetPasswordMockRepository) FindOne(_ context.Context, filter interface{}) (*database.ResetPassword, error) {
18+
args := m.Called(filter)
19+
result := args.Get(0)
20+
err := args.Get(1).(*error)
21+
22+
return *result.(**database.ResetPassword), *err
23+
}
24+
25+
func GetResetPasswordFindOneRunHandler(mockDB *[]*database.ResetPassword) (**database.ResetPassword, *error, func(args mock.Arguments)) {
26+
var res *database.ResetPassword
27+
var err error
28+
29+
return &res, &err, func(args mock.Arguments) {
30+
res = nil
31+
err = nil
32+
filters := args.Get(0)
33+
34+
resetPasswordType := reflect.TypeOf((*database.ResetPassword)(nil)).String()
35+
filtersType := reflect.TypeOf(filters).String()
36+
if filtersType == resetPasswordType {
37+
for _, item := range *mockDB {
38+
document := filters.(*database.ResetPassword)
39+
if document == item {
40+
res = item
41+
}
42+
}
43+
} else {
44+
filtersMap := filters.(primitive.M)
45+
46+
for _, item := range *mockDB {
47+
bsonItem := mapper.ConvertStructToBSONMap(item, nil)
48+
isEqual := false
49+
50+
for key, filter := range filtersMap {
51+
filterKind := reflect.ValueOf(filter).Kind()
52+
53+
if filterKind == reflect.Ptr {
54+
if bsonItem[key] == *filter.(*string) {
55+
isEqual = true
56+
}
57+
} else {
58+
if bsonItem[key] == filter {
59+
isEqual = true
60+
}
61+
}
62+
}
63+
64+
if isEqual {
65+
res = item
66+
}
67+
}
68+
}
69+
70+
if res == nil {
71+
err = mongo.ErrNoDocuments
72+
}
73+
}
74+
}
75+
76+
func (m *ResetPasswordMockRepository) DeleteOne(_ context.Context, filter interface{}) (*mongo.DeleteResult, error) {
77+
args := m.Called(filter)
78+
result := args.Get(0).(**mongo.DeleteResult)
79+
err := args.Get(1).(*error)
80+
81+
return *result, *err
82+
}
83+
84+
func GetResetPasswordDeleteOneRunHandler(db *[]*database.ResetPassword) (**mongo.DeleteResult, *error, func(args mock.Arguments)) {
85+
var (
86+
res *mongo.DeleteResult
87+
err error
88+
)
89+
90+
return &res, &err, func(args mock.Arguments) {
91+
res = nil
92+
err = nil
93+
filters := args.Get(0)
94+
95+
var foundIndex = -1
96+
97+
resetPasswordType := reflect.TypeOf((*database.ResetPassword)(nil)).String()
98+
filtersType := reflect.TypeOf(filters).String()
99+
if filtersType == resetPasswordType {
100+
for index, item := range *db {
101+
document := filters.(*database.ResetPassword)
102+
if document == item {
103+
foundIndex = index
104+
}
105+
}
106+
} else {
107+
filtersMap := filters.(primitive.M)
108+
109+
for index, item := range *db {
110+
bsonItem := mapper.ConvertStructToBSONMap(item, nil)
111+
isEqual := false
112+
113+
for key, filter := range filtersMap {
114+
filterKind := reflect.ValueOf(filter).Kind()
115+
116+
if filterKind == reflect.Ptr {
117+
if bsonItem[key] == *filter.(*string) {
118+
isEqual = true
119+
}
120+
} else {
121+
if bsonItem[key] == filter {
122+
isEqual = true
123+
}
124+
}
125+
}
126+
127+
if isEqual {
128+
foundIndex = index
129+
}
130+
}
131+
}
132+
133+
if foundIndex == -1 {
134+
err = mongo.ErrNoDocuments
135+
return
136+
}
137+
138+
(*db)[foundIndex] = (*db)[len(*db)-1]
139+
(*db)[len(*db)-1] = nil
140+
*db = (*db)[:len(*db)-1]
141+
142+
res = &mongo.DeleteResult{}
143+
}
144+
}
145+
146+
func (m *ResetPasswordMockRepository) Create(document *database.ResetPassword) error {
147+
args := m.Called(document)
148+
err := args.Get(0)
149+
150+
if err == nil {
151+
return nil
152+
}
153+
154+
return err.(error)
155+
}
156+
157+
func GetResetPasswordCreateRunHandler(db *[]*database.ResetPassword) func(args mock.Arguments) {
158+
return func(args mock.Arguments) {
159+
document := args.Get(0).(*database.ResetPassword)
160+
*db = append(*db, document)
161+
}
162+
}

Diff for: users/users.repository.go

+7
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ package users
22

33
import (
44
"context"
5+
"go.mongodb.org/mongo-driver/bson"
6+
"go.mongodb.org/mongo-driver/mongo"
57
database "messagewith-server/users/database"
68
)
79

810
type R interface {
911
FindOne(ctx context.Context, filter interface{}) (*database.User, error)
1012
Find(ctx context.Context, filter interface{}) ([]*database.User, error)
1113
Create(document *database.User) error
14+
UpdateByID(ctx context.Context, id interface{}, filter interface{}) (*mongo.UpdateResult, error)
1215
}
1316

1417
type Repository struct{}
@@ -43,3 +46,7 @@ func (r *Repository) Create(document *database.User) error {
4346

4447
return err
4548
}
49+
50+
func (r *Repository) UpdateByID(ctx context.Context, id interface{}, update interface{}) (*mongo.UpdateResult, error) {
51+
return collection.UpdateByID(ctx, id, bson.M{"$set": update})
52+
}

0 commit comments

Comments
 (0)