all repos

onasty @ 004414e

a one-time notes service

onasty/e2e/apiv1_notes_authorized_test.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
refactor: use e.randomEmail() everywhere i need an email (#200)..., 9 months ago
1
package e2e_test
2
3
import (
4
	"net/http"
5
	"slices"
6
	"time"
7
)
8
9
func (e *AppTestSuite) TestNoteV1_Create_authorized() {
10
	uid, toks := e.createAndSingIn(e.randomEmail(), e.uuid())
11
	httpResp := e.httpRequest(
12
		http.MethodPost,
13
		"/api/v1/note",
14
		e.jsonify(apiv1NoteCreateRequest{ //nolint:exhaustruct
15
			Content: "sample content for the test",
16
		}),
17
		toks.AccessToken,
18
	)
19
20
	var body apiv1NoteCreateResponse
21
	e.readBodyAndUnjsonify(httpResp.Body, &body)
22
23
	dbNote := e.getNoteBySlug(body.Slug)
24
	dbNoteAuthor := e.getLastNoteAuthorsRecordByAuthorID(uid)
25
26
	e.Equal(http.StatusCreated, httpResp.Code)
27
	e.Equal(dbNote.ID.String(), dbNoteAuthor.noteID.String())
28
}
29
30
func (e *AppTestSuite) TestNoteV1_Delete() {
31
	_, toks := e.createAndSingIn(e.randomEmail(), e.uuid())
32
	httpResp := e.httpRequest(
33
		http.MethodPost,
34
		"/api/v1/note",
35
		e.jsonify(apiv1NoteCreateRequest{ //nolint:exhaustruct
36
			Content: "sample content for the test",
37
		}),
38
		toks.AccessToken,
39
	)
40
41
	e.Equal(httpResp.Code, http.StatusCreated)
42
43
	var body apiv1NoteCreateResponse
44
	e.readBodyAndUnjsonify(httpResp.Body, &body)
45
46
	dbNote := e.getNoteBySlug(body.Slug)
47
	e.NotEmpty(dbNote)
48
49
	httpResp = e.httpRequest(
50
		http.MethodDelete,
51
		"/api/v1/note/"+body.Slug,
52
		nil,
53
		toks.AccessToken,
54
	)
55
	e.Equal(httpResp.Code, http.StatusNoContent)
56
57
	dbNote = e.getNoteBySlug(body.Slug)
58
	e.Empty(dbNote)
59
}
60
61
type apiV1NotePatchRequest struct {
62
	ExpiresAt            time.Time `json:"expires_at"`
63
	KeepBeforeExpiration bool      `json:"keep_before_expiration"`
64
}
65
66
func (e *AppTestSuite) TestNoteV1_updateExpirationTime() {
67
	_, toks := e.createAndSingIn(e.randomEmail(), e.uuid())
68
	httpResp := e.httpRequest(
69
		http.MethodPost,
70
		"/api/v1/note",
71
		e.jsonify(apiv1NoteCreateRequest{ //nolint:exhaustruct
72
			Content:              "sample content for the test",
73
			ExpiresAt:            time.Now().Add(time.Minute),
74
			KeepBeforeExpiration: false,
75
		}),
76
		toks.AccessToken,
77
	)
78
79
	e.Equal(httpResp.Code, http.StatusCreated)
80
81
	var body apiv1NoteCreateResponse
82
	e.readBodyAndUnjsonify(httpResp.Body, &body)
83
84
	patchTime := time.Now().Add(time.Hour)
85
	httpResp = e.httpRequest(
86
		http.MethodPatch,
87
		"/api/v1/note/"+body.Slug+"/expires",
88
		e.jsonify(apiV1NotePatchRequest{
89
			ExpiresAt:            patchTime,
90
			KeepBeforeExpiration: true,
91
		}),
92
		toks.AccessToken,
93
	)
94
95
	e.Equal(httpResp.Code, http.StatusOK)
96
97
	dbNote := e.getNoteBySlug(body.Slug)
98
	e.Equal(true, dbNote.KeepBeforeExpiration)
99
	e.Equal(patchTime.Unix(), dbNote.ExpiresAt.Unix())
100
}
101
102
func (e *AppTestSuite) TestNoteV1_updateExpirationTime_notFound() {
103
	_, toks := e.createAndSingIn(e.randomEmail(), e.uuid())
104
	httpResp := e.httpRequest(
105
		http.MethodPatch,
106
		"/api/v1/note/"+e.uuid(),
107
		e.jsonify(apiV1NotePatchRequest{
108
			ExpiresAt:            time.Now().Add(time.Hour),
109
			KeepBeforeExpiration: true,
110
		}),
111
		toks.AccessToken,
112
	)
113
114
	e.Equal(httpResp.Code, http.StatusNotFound)
115
}
116
117
type apiV1NoteSetPasswordRequest struct {
118
	Password string `json:"password"`
119
}
120
121
func (e *AppTestSuite) TestNoteV1_UpdatePassword() {
122
	_, toks := e.createAndSingIn(e.randomEmail(), e.uuid())
123
	httpResp := e.httpRequest(
124
		http.MethodPost,
125
		"/api/v1/note",
126
		e.jsonify(apiv1NoteCreateRequest{ //nolint:exhaustruct
127
			Content: "content",
128
		}),
129
		toks.AccessToken,
130
	)
131
132
	e.Equal(httpResp.Code, http.StatusCreated)
133
134
	var body apiv1NoteCreateResponse
135
	e.readBodyAndUnjsonify(httpResp.Body, &body)
136
137
	dbNoteOriginal := e.getNoteBySlug(body.Slug)
138
	e.Empty(dbNoteOriginal.Password)
139
140
	passwd := "new-password"
141
	httpResp = e.httpRequest(
142
		http.MethodPatch,
143
		"/api/v1/note/"+body.Slug+"/password",
144
		e.jsonify(apiV1NoteSetPasswordRequest{
145
			Password: passwd,
146
		}),
147
		toks.AccessToken,
148
	)
149
150
	e.Equal(httpResp.Code, http.StatusOK)
151
152
	dbNote := e.getNoteBySlug(body.Slug)
153
	e.NotEmpty(dbNote.Password)
154
155
	err := e.hasher.Compare(dbNote.Password, passwd)
156
	e.require.NoError(err)
157
}
158
159
func (e *AppTestSuite) TestNoteV1_UpdatePassword_notFound() {
160
	_, toks := e.createAndSingIn(e.randomEmail(), e.uuid())
161
	httpResp := e.httpRequest(
162
		http.MethodPatch,
163
		"/api/v1/note/"+e.uuid()+"/password",
164
		e.jsonify(apiV1NoteSetPasswordRequest{
165
			Password: "passwd",
166
		}),
167
		toks.AccessToken,
168
	)
169
170
	e.Equal(httpResp.Code, http.StatusNotFound)
171
}
172
173
func (e *AppTestSuite) TestNoteV1_UpdatePassword_passwordNotProvided() {
174
	_, toks := e.createAndSingIn(e.randomEmail(), e.uuid())
175
	httpResp := e.httpRequest(
176
		http.MethodPost,
177
		"/api/v1/note",
178
		e.jsonify(apiv1NoteCreateRequest{ //nolint:exhaustruct
179
			Content: "content",
180
		}),
181
		toks.AccessToken,
182
	)
183
184
	e.Equal(httpResp.Code, http.StatusCreated)
185
186
	var body apiv1NoteCreateResponse
187
	e.readBodyAndUnjsonify(httpResp.Body, &body)
188
189
	dbNoteOriginal := e.getNoteBySlug(body.Slug)
190
	e.Empty(dbNoteOriginal.Password)
191
192
	httpResp = e.httpRequest(
193
		http.MethodPatch,
194
		"/api/v1/note/"+body.Slug+"/password",
195
		e.jsonify(apiV1NoteSetPasswordRequest{
196
			Password: "",
197
		}),
198
		toks.AccessToken,
199
	)
200
201
	e.Equal(httpResp.Code, http.StatusBadRequest)
202
}
203
204
type apiv1NoteGetAllResponse struct {
205
	Content              string    `json:"content"`
206
	Slug                 string    `json:"slug"`
207
	KeepBeforeExpiration bool      `json:"keep_before_expiration"`
208
	HasPassword          bool      `json:"has_password"`
209
	CreatedAt            time.Time `json:"created_at"`
210
	ExpiresAt            time.Time `json:"expires_at"`
211
	ReadAt               time.Time `json:"read_at"`
212
}
213
214
func (e *AppTestSuite) TestNoteV1_GetAll() {
215
	notesInfo := []struct {
216
		slug    string
217
		content string
218
		read    bool
219
	}{
220
		{slug: e.uuid(), content: e.uuid(), read: true},
221
		{slug: e.uuid(), content: e.uuid(), read: true},
222
		{slug: e.uuid(), content: e.uuid(), read: false},
223
		{slug: e.uuid(), content: e.uuid(), read: false},
224
		{slug: e.uuid(), content: e.uuid(), read: false},
225
	}
226
227
	_, toks := e.createAndSingIn(e.randomEmail(), e.uuid())
228
229
	// create notes
230
	for _, ni := range notesInfo {
231
		httpResp := e.httpRequest(
232
			http.MethodPost,
233
			"/api/v1/note",
234
			e.jsonify(apiv1NoteCreateRequest{ //nolint:exhaustruct
235
				Content: ni.content,
236
				Slug:    ni.slug,
237
			}),
238
			toks.AccessToken)
239
240
		e.Equal(http.StatusCreated, httpResp.Code)
241
	}
242
243
	// read notes
244
	for _, ni := range notesInfo {
245
		if ni.read {
246
			httpResp := e.httpRequest(http.MethodGet, "/api/v1/note/"+ni.slug, nil)
247
			e.Equal(http.StatusOK, httpResp.Code)
248
		}
249
	}
250
251
	httpResp := e.httpRequest(http.MethodGet, "/api/v1/note", nil, toks.AccessToken)
252
253
	var body []apiv1NoteGetAllResponse
254
	e.readBodyAndUnjsonify(httpResp.Body, &body)
255
256
	e.Equal(http.StatusOK, httpResp.Code)
257
	e.Len(body, len(notesInfo))
258
}
259
260
func (e *AppTestSuite) TestNoteV1_GetAllRead_inaccesibleForAnUnauthorized() {
261
	httpResp := e.httpRequest(http.MethodGet, "/api/v1/note/read", nil)
262
	e.Equal(httpResp.Code, http.StatusUnauthorized)
263
}
264
265
func (e *AppTestSuite) TestNoteV1_GetAllRead() {
266
	notesInfo := []struct {
267
		slug    string
268
		content string
269
	}{
270
		{slug: e.uuid(), content: e.uuid()},
271
		{slug: e.uuid(), content: e.uuid()},
272
		{slug: e.uuid(), content: e.uuid()},
273
		{slug: e.uuid(), content: e.uuid()},
274
	}
275
276
	_, toks := e.createAndSingIn(e.randomEmail(), e.uuid())
277
278
	// create few notes
279
	for _, ni := range notesInfo {
280
		httpResp := e.httpRequest(
281
			http.MethodPost,
282
			"/api/v1/note",
283
			e.jsonify(apiv1NoteCreateRequest{ //nolint:exhaustruct
284
				Content: ni.content,
285
				Slug:    ni.slug,
286
			}),
287
			toks.AccessToken)
288
289
		e.Equal(http.StatusCreated, httpResp.Code)
290
	}
291
292
	// read those notes
293
	for _, ni := range notesInfo {
294
		httpResp := e.httpRequest(http.MethodGet, "/api/v1/note/"+ni.slug, nil)
295
		e.Equal(http.StatusOK, httpResp.Code)
296
	}
297
298
	// check if all notes are returned
299
	httpResp := e.httpRequest(http.MethodGet, "/api/v1/note/read", nil, toks.AccessToken)
300
301
	var body []apiv1NoteGetAllResponse
302
	e.readBodyAndUnjsonify(httpResp.Body, &body)
303
304
	e.Equal(http.StatusOK, httpResp.Code)
305
	e.require.Len(body, len(notesInfo))
306
}
307
308
func (e *AppTestSuite) TestNoteV1_GetAllUnread_inaccesibleForAnUnauthorized() {
309
	httpResp := e.httpRequest(http.MethodGet, "/api/v1/note/unread", nil)
310
	e.Equal(httpResp.Code, http.StatusUnauthorized)
311
}
312
313
func (e *AppTestSuite) TestNoteV1_GetAllUnread() {
314
	type notesTestData struct {
315
		slug    string
316
		content string
317
		read    bool
318
	}
319
320
	notesInfo := []notesTestData{
321
		{slug: e.uuid(), content: e.uuid(), read: true},
322
		{slug: e.uuid(), content: e.uuid(), read: true},
323
		{slug: e.uuid(), content: e.uuid(), read: true},
324
		{slug: e.uuid(), content: e.uuid(), read: false},
325
		{slug: e.uuid(), content: e.uuid(), read: false},
326
		{slug: e.uuid(), content: e.uuid(), read: false},
327
		{slug: e.uuid(), content: e.uuid(), read: false},
328
		{slug: e.uuid(), content: e.uuid(), read: false},
329
	}
330
	unreadNotesTotal := len(
331
		slices.DeleteFunc(
332
			slices.Clone(notesInfo),
333
			func(n notesTestData) bool { return n.read }),
334
	)
335
336
	_, toks := e.createAndSingIn(e.randomEmail(), e.uuid())
337
338
	// create notes
339
	for _, ni := range notesInfo {
340
		httpResp := e.httpRequest(
341
			http.MethodPost,
342
			"/api/v1/note",
343
			e.jsonify(apiv1NoteCreateRequest{ //nolint:exhaustruct
344
				Content: ni.content,
345
				Slug:    ni.slug,
346
			}),
347
			toks.AccessToken)
348
349
		e.Equal(http.StatusCreated, httpResp.Code)
350
	}
351
352
	// read notes
353
	for _, ni := range notesInfo {
354
		if ni.read {
355
			httpResp := e.httpRequest(http.MethodGet, "/api/v1/note/"+ni.slug, nil)
356
			e.Equal(http.StatusOK, httpResp.Code)
357
		}
358
	}
359
360
	httpResp := e.httpRequest(http.MethodGet, "/api/v1/note/unread", nil, toks.AccessToken)
361
362
	var body []apiv1NoteGetAllResponse
363
	e.readBodyAndUnjsonify(httpResp.Body, &body)
364
365
	e.Equal(http.StatusOK, httpResp.Code)
366
	e.Len(body, unreadNotesTotal)
367
}