all repos

onasty @ 040e38372994521cfeb76c57c76998be53bf6a17

a one-time notes service

onasty/e2e/apiv1_auth_test.go (view raw)

Smirnov Oleksandr Smirnov Oleksandr
ss2316544@gmail.com
refactor: fix annoyances (#97)..., 1 year ago
1
package e2e_test
2
3
import (
4
	"net/http"
5
6
	"github.com/gofrs/uuid/v5"
7
	"github.com/olexsmir/onasty/internal/models"
8
)
9
10
type apiv1AuthSignUpRequest struct {
11
	Username string `json:"username"`
12
	Email    string `json:"email"`
13
	Password string `json:"password"`
14
}
15
16
func (e *AppTestSuite) TestAuthV1_SignUP() {
17
	username := "test" + e.uuid()
18
	email := e.uuid() + "test@test.com"
19
	password := "password"
20
21
	httpResp := e.httpRequest(
22
		http.MethodPost,
23
		"/api/v1/auth/signup",
24
		e.jsonify(apiv1AuthSignUpRequest{
25
			Username: username,
26
			Email:    email,
27
			Password: password,
28
		}),
29
	)
30
31
	dbUser := e.getUserByUsername(username)
32
	hashedPasswd, err := e.hasher.Hash(password)
33
	e.require.NoError(err)
34
35
	e.Equal(http.StatusCreated, httpResp.Code)
36
	e.Equal(dbUser.Email, email)
37
	e.Equal(dbUser.Password, hashedPasswd)
38
}
39
40
func (e *AppTestSuite) TestAuthV1_SignUP_badrequest() {
41
	tests := []struct {
42
		name     string
43
		username string
44
		email    string
45
		password string
46
	}{
47
		{name: "all fields empty", email: "", password: "", username: ""},
48
		{
49
			name:     "non valid email",
50
			username: "testing",
51
			email:    "email",
52
			password: "password",
53
		},
54
		{
55
			name:     "non valid password",
56
			email:    "test@test.com",
57
			password: "12345",
58
			username: "test",
59
		},
60
	}
61
	for _, t := range tests {
62
		httpResp := e.httpRequest(
63
			http.MethodPost,
64
			"/api/v1/auth/signup",
65
			e.jsonify(apiv1AuthSignUpRequest{
66
				Username: t.username,
67
				Email:    t.email,
68
				Password: t.password,
69
			}),
70
		)
71
72
		e.Equal(http.StatusBadRequest, httpResp.Code)
73
	}
74
}
75
76
type (
77
	apiv1AuthSignInRequest struct {
78
		Email    string `json:"email"`
79
		Password string `json:"password"`
80
	}
81
	apiv1AuthSignInResponse struct {
82
		AccessToken  string `json:"access_token"`
83
		RefreshToken string `json:"refresh_token"`
84
	}
85
)
86
87
func (e *AppTestSuite) TestAuthV1_VerifyEmail() {
88
	email := e.uuid() + "email@email.com"
89
	password := "qwerty"
90
91
	httpResp := e.httpRequest(
92
		http.MethodPost,
93
		"/api/v1/auth/signup",
94
		e.jsonify(apiv1AuthSignUpRequest{
95
			Username: e.uuid(),
96
			Email:    email,
97
			Password: password,
98
		}),
99
	)
100
101
	e.Equal(http.StatusCreated, httpResp.Code)
102
103
	user := e.getLastUserByEmail(email)
104
	token := e.getVerificationTokenByUserID(user.ID)
105
	httpResp = e.httpRequest(http.MethodGet, "/api/v1/auth/verify/"+token.Token, nil)
106
	e.Equal(http.StatusOK, httpResp.Code)
107
108
	user = e.getLastUserByEmail(email)
109
	e.Equal(user.Activated, true)
110
}
111
112
func (e *AppTestSuite) TestAuthV1_ResendVerificationEmail() {
113
	email, password := e.uuid()+"email@email.com", e.uuid()
114
115
	// create test user
116
	signUpHTTPResp := e.httpRequest(
117
		http.MethodPost,
118
		"/api/v1/auth/signup",
119
		e.jsonify(apiv1AuthSignUpRequest{
120
			Username: e.uuid(),
121
			Email:    email,
122
			Password: password,
123
		}),
124
	)
125
126
	e.Equal(http.StatusCreated, signUpHTTPResp.Code)
127
128
	// handle sending of the email
129
	httpResp := e.httpRequest(
130
		http.MethodPost,
131
		"/api/v1/auth/resend-verification-email",
132
		e.jsonify(apiv1AuthSignInRequest{
133
			Email:    email,
134
			Password: password,
135
		}),
136
	)
137
138
	e.Equal(http.StatusOK, httpResp.Code)
139
}
140
141
func (e *AppTestSuite) TestAuthV1_ResendVerificationEmail_wrong() {
142
	email, password := e.uuid()+"@"+e.uuid()+".com", "password"
143
	e.insertUser(e.uuid(), email, password, true)
144
145
	tests := []struct {
146
		name         string
147
		email        string
148
		password     string
149
		expectedCode int
150
	}{
151
		{
152
			name:         "activated account",
153
			email:        email,
154
			password:     password,
155
			expectedCode: http.StatusBadRequest,
156
		},
157
		{
158
			name:         "wrong credentials",
159
			email:        email,
160
			password:     e.uuid(),
161
			expectedCode: http.StatusUnauthorized,
162
		},
163
	}
164
165
	for _, t := range tests {
166
		httpResp := e.httpRequest(
167
			http.MethodPost,
168
			"/api/v1/auth/resend-verification-email",
169
			e.jsonify(apiv1AuthSignInRequest{
170
				Email:    t.email,
171
				Password: t.password,
172
			}))
173
174
		e.Equal(httpResp.Code, t.expectedCode)
175
176
		// TODO: no email should be sent
177
	}
178
}
179
180
func (e *AppTestSuite) TestAuthV1_SignIn() {
181
	email := e.uuid() + "email@email.com"
182
	password := "qwerty"
183
184
	uid := e.insertUser("test", email, password, true)
185
186
	httpResp := e.httpRequest(
187
		http.MethodPost,
188
		"/api/v1/auth/signin",
189
		e.jsonify(apiv1AuthSignInRequest{
190
			Email:    email,
191
			Password: password,
192
		}),
193
	)
194
195
	var body apiv1AuthSignInResponse
196
	e.readBodyAndUnjsonify(httpResp.Body, &body)
197
198
	session := e.getLastSessionByUserID(uid)
199
	parsedToken := e.parseJwtToken(body.AccessToken)
200
201
	e.Equal(http.StatusOK, httpResp.Code)
202
	e.Equal(body.RefreshToken, session.RefreshToken)
203
	e.Equal(parsedToken.UserID, uid.String())
204
}
205
206
func (e *AppTestSuite) TestAuthV1_SignIn_wrong() {
207
	password := "password"
208
	email := e.uuid() + "@test.com"
209
	e.insertUser(e.uuid(), email, "password", true)
210
211
	unactivatedEmail := e.uuid() + "@test.com"
212
	e.insertUser(e.uuid(), unactivatedEmail, password, false)
213
214
	//exhaustruct:ignore
215
	tests := []struct {
216
		name         string
217
		email        string
218
		password     string
219
		expectedCode int
220
221
		expectMsg   bool
222
		expectedMsg string
223
	}{
224
		{
225
			name:         "inactivated user",
226
			email:        unactivatedEmail,
227
			password:     password,
228
			expectedCode: http.StatusBadRequest,
229
			expectMsg:    true,
230
			expectedMsg:  models.ErrUserIsNotActivated.Error(),
231
		},
232
		{
233
			name:         "wrong email",
234
			email:        "wrong@email.com",
235
			password:     password,
236
			expectedCode: http.StatusBadRequest,
237
		},
238
		{
239
			name:         "wrong password",
240
			email:        email,
241
			password:     "wrong-wrong",
242
			expectedCode: http.StatusUnauthorized,
243
		},
244
	}
245
246
	for _, t := range tests {
247
		httpResp := e.httpRequest(
248
			http.MethodPost,
249
			"/api/v1/auth/signin",
250
			e.jsonify(apiv1AuthSignInRequest{
251
				Email:    t.email,
252
				Password: t.password,
253
			}),
254
		)
255
256
		if t.expectMsg {
257
			var body errorResponse
258
			e.readBodyAndUnjsonify(httpResp.Body, &body)
259
260
			e.Equal(body.Message, t.expectedMsg)
261
		}
262
263
		e.Equal(t.expectedCode, httpResp.Code)
264
	}
265
}
266
267
type apiv1AuthRefreshTokensRequest struct {
268
	RefreshToken string `json:"refresh_token"`
269
}
270
271
func (e *AppTestSuite) TestAuthV1_RefreshTokens() {
272
	uid, toks := e.createAndSingIn(e.uuid()+"@test.com", e.uuid(), "password")
273
	httpResp := e.httpRequest(
274
		http.MethodPost,
275
		"/api/v1/auth/refresh-tokens",
276
		e.jsonify(apiv1AuthRefreshTokensRequest{
277
			RefreshToken: toks.RefreshToken,
278
		}),
279
	)
280
281
	var body apiv1AuthSignInResponse
282
	e.readBodyAndUnjsonify(httpResp.Body, &body)
283
284
	sessionDB := e.getLastSessionByUserID(uid)
285
	e.Equal(e.parseJwtToken(body.AccessToken).UserID, uid.String())
286
287
	e.Equal(httpResp.Code, http.StatusOK)
288
	e.NotEqual(toks.RefreshToken, body.RefreshToken)
289
	e.Equal(body.RefreshToken, sessionDB.RefreshToken)
290
}
291
292
func (e *AppTestSuite) TestAuthV1_RefreshTokens_wrong() {
293
	// requests a new token pair with a wrong refresh token
294
295
	httpResp := e.httpRequest(
296
		http.MethodPost,
297
		"/api/v1/auth/refresh-tokens",
298
		e.jsonify(apiv1AuthRefreshTokensRequest{
299
			RefreshToken: e.uuid(),
300
		}),
301
	)
302
303
	e.Equal(httpResp.Code, http.StatusBadRequest)
304
}
305
306
func (e *AppTestSuite) TestAuthV1_Logout() {
307
	uid, toks := e.createAndSingIn(e.uuid()+"@test.com", e.uuid(), "password")
308
309
	sessionDB := e.getLastSessionByUserID(uid)
310
	e.NotEmpty(sessionDB.RefreshToken)
311
312
	httpResp := e.httpRequest(http.MethodPost, "/api/v1/auth/logout", nil, toks.AccessToken)
313
	e.Equal(httpResp.Code, http.StatusNoContent)
314
315
	sessionDB = e.getLastSessionByUserID(uid)
316
	e.Empty(sessionDB.RefreshToken)
317
}
318
319
type apiv1AtuhChangePasswordRequest struct {
320
	CurrentPassword string `json:"current_password"`
321
	NewPassword     string `json:"new_password"`
322
}
323
324
func (e *AppTestSuite) TestAuthV1_ChangePassword() {
325
	password := e.uuid()
326
	newPassword := e.uuid()
327
	username := e.uuid()
328
	_, toks := e.createAndSingIn(e.uuid()+"@test.com", username, password)
329
330
	httpResp := e.httpRequest(
331
		http.MethodPost,
332
		"/api/v1/auth/change-password",
333
		e.jsonify(apiv1AtuhChangePasswordRequest{
334
			CurrentPassword: password,
335
			NewPassword:     newPassword,
336
		}),
337
		toks.AccessToken,
338
	)
339
340
	e.Equal(httpResp.Code, http.StatusOK)
341
342
	userDB := e.getUserByUsername(username)
343
	e.Equal(userDB.Username, username)
344
	e.NoError(e.hasher.Compare(userDB.Password, newPassword))
345
}
346
347
// createAndSingIn creates an activated username, logs them in,
348
// and returns their userID along with access and refresh tokens.
349
func (e *AppTestSuite) createAndSingIn(
350
	email, username, password string,
351
) (uuid.UUID, apiv1AuthSignInResponse) {
352
	uid := e.insertUser(username, email, password, true)
353
	httpResp := e.httpRequest(
354
		http.MethodPost,
355
		"/api/v1/auth/signin",
356
		e.jsonify(apiv1AuthSignInRequest{
357
			Email:    email,
358
			Password: password,
359
		}),
360
	)
361
362
	e.Equal(httpResp.Code, http.StatusOK)
363
364
	var body apiv1AuthSignInResponse
365
	e.readBodyAndUnjsonify(httpResp.Body, &body)
366
367
	return uid, body
368
}