@opentermsarchive/engine 0.26.1 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/bin/ota-track.js +3 -3
  2. package/bin/ota-validate.js +2 -2
  3. package/bin/ota.js +1 -1
  4. package/config/default.json +1 -1
  5. package/package.json +3 -4
  6. package/scripts/dataset/export/index.js +4 -4
  7. package/scripts/dataset/export/index.test.js +11 -17
  8. package/scripts/declarations/lint/index.mocha.js +1 -1
  9. package/scripts/declarations/utils/index.js +12 -12
  10. package/scripts/declarations/validate/definitions.js +1 -1
  11. package/scripts/declarations/validate/index.mocha.js +30 -34
  12. package/scripts/declarations/validate/service.history.schema.js +11 -11
  13. package/scripts/declarations/validate/service.schema.js +13 -13
  14. package/scripts/history/migrate-services.js +4 -4
  15. package/scripts/history/update-to-full-hash.js +2 -2
  16. package/scripts/import/index.js +14 -14
  17. package/scripts/rewrite/rewrite-snapshots.js +3 -3
  18. package/scripts/rewrite/rewrite-versions.js +14 -14
  19. package/scripts/utils/renamer/README.md +3 -3
  20. package/scripts/utils/renamer/index.js +13 -13
  21. package/src/archivist/errors.js +1 -1
  22. package/src/archivist/extract/exports.js +3 -0
  23. package/src/archivist/{filter → extract}/index.js +23 -27
  24. package/src/archivist/extract/index.test.js +516 -0
  25. package/src/archivist/index.js +101 -140
  26. package/src/archivist/index.test.js +178 -166
  27. package/src/archivist/recorder/index.js +11 -55
  28. package/src/archivist/recorder/index.test.js +310 -356
  29. package/src/archivist/recorder/record.js +18 -7
  30. package/src/archivist/recorder/repositories/git/dataMapper.js +41 -31
  31. package/src/archivist/recorder/repositories/git/index.js +11 -15
  32. package/src/archivist/recorder/repositories/git/index.test.js +1058 -463
  33. package/src/archivist/recorder/repositories/interface.js +8 -6
  34. package/src/archivist/recorder/repositories/mongo/dataMapper.js +21 -14
  35. package/src/archivist/recorder/repositories/mongo/index.js +8 -8
  36. package/src/archivist/recorder/repositories/mongo/index.test.js +898 -479
  37. package/src/archivist/recorder/snapshot.js +5 -0
  38. package/src/archivist/recorder/snapshot.test.js +65 -0
  39. package/src/archivist/recorder/version.js +14 -0
  40. package/src/archivist/recorder/version.test.js +65 -0
  41. package/src/archivist/services/index.js +60 -51
  42. package/src/archivist/services/index.test.js +63 -83
  43. package/src/archivist/services/service.js +26 -22
  44. package/src/archivist/services/service.test.js +46 -68
  45. package/src/archivist/services/{pageDeclaration.js → sourceDocument.js} +11 -9
  46. package/src/archivist/services/{pageDeclaration.test.js → sourceDocument.test.js} +21 -21
  47. package/src/archivist/services/terms.js +26 -0
  48. package/src/archivist/services/{documentDeclaration.test.js → terms.test.js} +15 -15
  49. package/src/exports.js +2 -2
  50. package/src/index.js +16 -13
  51. package/src/logger/index.js +35 -36
  52. package/src/notifier/index.js +8 -8
  53. package/src/tracker/index.js +6 -6
  54. package/src/archivist/filter/exports.js +0 -3
  55. package/src/archivist/filter/index.test.js +0 -564
  56. package/src/archivist/recorder/record.test.js +0 -91
  57. package/src/archivist/services/documentDeclaration.js +0 -26
  58. /package/scripts/utils/renamer/rules/{documentTypes.json → termsTypes.json} +0 -0
  59. /package/scripts/utils/renamer/rules/{documentTypesByService.json → termsTypesByService.json} +0 -0
@@ -6,9 +6,10 @@ import chai from 'chai';
6
6
  import config from 'config';
7
7
  import mime from 'mime';
8
8
 
9
- import Record from '../../record.js';
9
+ import Snapshot from '../../snapshot.js';
10
+ import Version from '../../version.js';
10
11
 
11
- import { DOCUMENT_TYPE_AND_PAGE_ID_SEPARATOR, SNAPSHOT_ID_MARKER } from './dataMapper.js';
12
+ import { TERMS_TYPE_AND_DOCUMENT_ID_SEPARATOR, SNAPSHOT_ID_MARKER, COMMIT_MESSAGE_PREFIXES } from './dataMapper.js';
12
13
  import Git from './git.js';
13
14
 
14
15
  import GitRepository from './index.js';
@@ -16,700 +17,1294 @@ import GitRepository from './index.js';
16
17
  const { expect } = chai;
17
18
 
18
19
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
- const RECORDER_PATH = path.resolve(__dirname, '../../../', config.get('recorder.versions.storage.git.path'));
20
+
21
+ const RECORDER_PATH = path.resolve(__dirname, '../../../../..', config.get('recorder.versions.storage.git.path'));
20
22
 
21
23
  const SERVICE_PROVIDER_ID = 'test_service';
22
- const DOCUMENT_TYPE = 'Terms of Service';
23
- const PAGE_ID = 'community-standards-hate-speech';
24
+ const TERMS_TYPE = 'Terms of Service';
25
+ const DOCUMENT_ID = '126382350847838';
24
26
  const CONTENT = 'ToS fixture data with UTF-8 çhãràčtęrs';
25
- const EXPECTED_FILE_PATH = `${RECORDER_PATH}/${SERVICE_PROVIDER_ID}/${DOCUMENT_TYPE}.html`;
26
- const EXPECTED_FILE_PATH_WITH_PAGE_ID = `${RECORDER_PATH}/${SERVICE_PROVIDER_ID}/${DOCUMENT_TYPE}${DOCUMENT_TYPE_AND_PAGE_ID_SEPARATOR}${PAGE_ID}.html`;
27
- const EXPECTED_PDF_FILE_PATH = EXPECTED_FILE_PATH.replace('html', 'pdf');
27
+
28
+ const BASE_PATH = `${RECORDER_PATH}/${SERVICE_PROVIDER_ID}/${TERMS_TYPE}`;
29
+ const EXPECTED_VERSION_FILE_PATH = `${BASE_PATH}.md`;
30
+ const EXPECTED_SNAPSHOT_FILE_PATH = `${BASE_PATH}.html`;
31
+ const EXPECTED_SNAPSHOT_FILE_PATH_WITH_DOCUMENT_ID = `${BASE_PATH}${TERMS_TYPE_AND_DOCUMENT_ID_SEPARATOR}${DOCUMENT_ID}.html`;
32
+ const EXPECTED_PDF_SNAPSHOT_FILE_PATH = `${BASE_PATH}.pdf`;
33
+
28
34
  const FETCH_DATE = new Date('2000-01-01T12:00:00.000Z');
29
35
  const FETCH_DATE_LATER = new Date('2000-01-02T12:00:00.000Z');
30
36
  const FETCH_DATE_EARLIER = new Date('2000-01-01T06:00:00.000Z');
37
+
31
38
  const SNAPSHOT_ID = '513fadb2ae415c87747047e33287805d59e2dd55';
32
- const MIME_TYPE = 'text/html';
33
- const PDF_CONTENT = fs.readFileSync(path.resolve(__dirname, '../../../../../test/fixtures/terms.pdf'), { encoding: 'utf8' });
34
- const PDF_MIME_TYPE = 'application/pdf';
39
+ const HTML_MIME_TYPE = mime.getType('html');
35
40
 
36
- let git;
41
+ const PDF_MIME_TYPE = mime.getType('pdf');
42
+ const PDF_CONTENT = fs.readFileSync(path.resolve(__dirname, '../../../../../test/fixtures/terms.pdf'), { encoding: 'utf8' });
37
43
 
38
44
  describe('GitRepository', () => {
45
+ let git;
39
46
  let subject;
40
47
 
41
- before(async function () {
42
- this.timeout(5000);
43
- git = new Git({
44
- path: RECORDER_PATH,
45
- author: {
46
- name: config.get('recorder.versions.storage.git.author.name'),
47
- email: config.get('recorder.versions.storage.git.author.email'),
48
- },
49
- });
48
+ context('Version', () => {
49
+ before(async function () {
50
+ this.timeout(5000);
51
+
52
+ git = new Git({
53
+ path: RECORDER_PATH,
54
+ author: {
55
+ name: config.get('recorder.versions.storage.git.author.name'),
56
+ email: config.get('recorder.versions.storage.git.author.email'),
57
+ },
58
+ });
50
59
 
51
- await git.initialize();
60
+ await git.initialize();
52
61
 
53
- subject = new GitRepository({
54
- ...config.get('recorder.versions.storage.git'),
55
- path: RECORDER_PATH,
62
+ subject = new GitRepository({
63
+ ...config.get('recorder.versions.storage.git'),
64
+ path: RECORDER_PATH,
65
+ });
66
+
67
+ return subject.initialize();
56
68
  });
57
69
 
58
- return subject.initialize();
59
- });
70
+ describe('#save', () => {
71
+ let id;
72
+ let commit;
73
+ let isFirstRecord;
74
+ let numberOfRecordsBefore;
75
+ let numberOfRecordsAfter;
60
76
 
61
- describe('#save', () => {
62
- let id;
63
- let commit;
64
- let isFirstRecord;
65
- let numberOfRecordsBefore;
66
- let numberOfRecordsAfter;
77
+ context('when it is the first record', () => {
78
+ before(async () => {
79
+ numberOfRecordsBefore = (await git.log()).length;
67
80
 
68
- context('when it is the first record', () => {
69
- before(async () => {
70
- numberOfRecordsBefore = (await git.log()).length;
81
+ ({ id, isFirstRecord } = await subject.save(new Version({
82
+ serviceId: SERVICE_PROVIDER_ID,
83
+ termsType: TERMS_TYPE,
84
+ content: CONTENT,
85
+ fetchDate: FETCH_DATE,
86
+ snapshotIds: [SNAPSHOT_ID],
87
+ })));
88
+
89
+ numberOfRecordsAfter = (await git.log()).length;
90
+
91
+ ([commit] = await git.log());
92
+ });
93
+
94
+ after(async () => subject.removeAll());
95
+
96
+ it('saves the record', () => {
97
+ expect(numberOfRecordsAfter).to.equal(numberOfRecordsBefore + 1);
98
+ });
99
+
100
+ it('returns the record id', () => {
101
+ expect(commit.hash).to.include(id);
102
+ });
103
+
104
+ it('states that it is the first record', () => {
105
+ expect(isFirstRecord).to.be.true;
106
+ });
107
+
108
+ it('stores the service ID', () => {
109
+ expect(commit.message).to.include(SERVICE_PROVIDER_ID);
110
+ });
111
+
112
+ it('stores the terms type', () => {
113
+ expect(commit.message).to.include(TERMS_TYPE);
114
+ });
115
+
116
+ it('stores information that it is the first record for these specific terms', () => {
117
+ expect(commit.message).to.include(COMMIT_MESSAGE_PREFIXES.startTracking);
118
+ });
119
+
120
+ it('stores the proper content', () => {
121
+ expect(fs.readFileSync(EXPECTED_VERSION_FILE_PATH, { encoding: 'utf8' })).to.equal(CONTENT);
122
+ });
123
+
124
+ it('stores the fetch date', () => {
125
+ expect(new Date(commit.date).getTime()).to.equal(FETCH_DATE.getTime());
126
+ });
127
+
128
+ it('stores the snapshot ID', () => {
129
+ expect(commit.body).to.include(SNAPSHOT_ID);
130
+ });
131
+ });
132
+
133
+ context('when it is not the first record', () => {
134
+ const UPDATED_CONTENT = `${CONTENT} updated`;
135
+
136
+ before(async () => {
137
+ await subject.save(new Version({
138
+ serviceId: SERVICE_PROVIDER_ID,
139
+ termsType: TERMS_TYPE,
140
+ content: CONTENT,
141
+ mimeType: HTML_MIME_TYPE,
142
+ fetchDate: FETCH_DATE,
143
+ }));
144
+
145
+ numberOfRecordsBefore = (await git.log()).length;
146
+
147
+ ({ id, isFirstRecord } = await subject.save(new Version({
148
+ serviceId: SERVICE_PROVIDER_ID,
149
+ termsType: TERMS_TYPE,
150
+ content: UPDATED_CONTENT,
151
+ fetchDate: FETCH_DATE,
152
+ snapshotIds: [SNAPSHOT_ID],
153
+ mimeType: HTML_MIME_TYPE,
154
+ })));
155
+
156
+ numberOfRecordsAfter = (await git.log()).length;
71
157
 
72
- ({ id, isFirstRecord } = await subject.save(new Record({
158
+ ([commit] = await git.log());
159
+ });
160
+
161
+ after(async () => subject.removeAll());
162
+
163
+ it('saves the record', () => {
164
+ expect(numberOfRecordsAfter).to.equal(numberOfRecordsBefore + 1);
165
+ });
166
+
167
+ it('returns the record id', () => {
168
+ expect(commit.hash).to.include(id);
169
+ });
170
+
171
+ it('states that it is not the first record', () => {
172
+ expect(isFirstRecord).to.be.false;
173
+ });
174
+ });
175
+
176
+ context('when the content has not changed', () => {
177
+ before(async () => {
178
+ await subject.save(new Version({
179
+ serviceId: SERVICE_PROVIDER_ID,
180
+ termsType: TERMS_TYPE,
181
+ content: CONTENT,
182
+ fetchDate: FETCH_DATE,
183
+ }));
184
+
185
+ numberOfRecordsBefore = (await git.log()).length;
186
+
187
+ ({ id, isFirstRecord } = await subject.save(new Version({
188
+ serviceId: SERVICE_PROVIDER_ID,
189
+ termsType: TERMS_TYPE,
190
+ content: CONTENT,
191
+ fetchDate: FETCH_DATE,
192
+ })));
193
+
194
+ numberOfRecordsAfter = (await git.log()).length;
195
+ });
196
+
197
+ after(async () => subject.removeAll());
198
+
199
+ it('does not save the record', () => {
200
+ expect(numberOfRecordsAfter).to.equal(numberOfRecordsBefore);
201
+ });
202
+
203
+ it('returns no id', () => {
204
+ expect(id).to.equal(undefined);
205
+ });
206
+ });
207
+
208
+ context('when it is an extracted only version', () => {
209
+ const EXTRACTED_ONLY_CONTENT = `${CONTENT} extracted only`;
210
+
211
+ before(async () => {
212
+ await subject.save(new Version({
213
+ serviceId: SERVICE_PROVIDER_ID,
214
+ termsType: TERMS_TYPE,
215
+ content: CONTENT,
216
+ fetchDate: FETCH_DATE_EARLIER,
217
+ })); // An extracted only version cannot be the first record
218
+
219
+ numberOfRecordsBefore = (await git.log()).length;
220
+
221
+ ({ id, isFirstRecord } = await subject.save(new Version({
222
+ serviceId: SERVICE_PROVIDER_ID,
223
+ termsType: TERMS_TYPE,
224
+ content: EXTRACTED_ONLY_CONTENT,
225
+ fetchDate: FETCH_DATE,
226
+ isExtractOnly: true,
227
+ snapshotIds: [SNAPSHOT_ID],
228
+ })));
229
+
230
+ numberOfRecordsAfter = (await git.log()).length;
231
+
232
+ ([commit] = await git.log());
233
+ });
234
+
235
+ after(async () => subject.removeAll());
236
+
237
+ it('saves the record', () => {
238
+ expect(numberOfRecordsAfter).to.equal(numberOfRecordsBefore + 1);
239
+ });
240
+
241
+ it('returns the record id', () => {
242
+ expect(commit.hash).to.include(id);
243
+ });
244
+
245
+ it('stores information that it is an extracted only version', () => {
246
+ expect(commit.message).to.include(COMMIT_MESSAGE_PREFIXES.extractOnly);
247
+ });
248
+ });
249
+
250
+ context('when one snapshot ID is specified', () => {
251
+ const SNAPSHOT_ID = 'c01533c0e546ef430eea84d23c1b18a2b8420dfb';
252
+ const snapshotIds = [SNAPSHOT_ID];
253
+
254
+ before(async () => {
255
+ ({ id, isFirstRecord } = await subject.save(new Version({
256
+ serviceId: SERVICE_PROVIDER_ID,
257
+ termsType: TERMS_TYPE,
258
+ content: CONTENT,
259
+ fetchDate: FETCH_DATE,
260
+ snapshotIds,
261
+ })));
262
+
263
+ ([commit] = await git.log());
264
+ });
265
+
266
+ after(async () => subject.removeAll());
267
+
268
+ it('stores snapshot ID', () => {
269
+ expect(commit.body).to.include(config.get('recorder.versions.storage.git.snapshotIdentiferTemplate').replace(SNAPSHOT_ID_MARKER, SNAPSHOT_ID));
270
+ });
271
+
272
+ it('stores the service ID', () => {
273
+ expect(commit.message).to.include(SERVICE_PROVIDER_ID);
274
+ });
275
+
276
+ it('stores the terms type', () => {
277
+ expect(commit.message).to.include(TERMS_TYPE);
278
+ });
279
+ });
280
+
281
+ context('when there are many snapshots IDs specified', () => {
282
+ const SNAPSHOT_ID_1 = 'c01533c0e546ef430eea84d23c1b18a2b8420dfb';
283
+ const SNAPSHOT_ID_2 = '0fd16cca9e1a86a2267bd587107c485f06099d7d';
284
+ const snapshotIds = [ SNAPSHOT_ID_1, SNAPSHOT_ID_2 ];
285
+
286
+ before(async () => {
287
+ ({ id, isFirstRecord } = await subject.save(new Version({
288
+ serviceId: SERVICE_PROVIDER_ID,
289
+ termsType: TERMS_TYPE,
290
+ content: CONTENT,
291
+ fetchDate: FETCH_DATE,
292
+ snapshotIds,
293
+ })));
294
+
295
+ ([commit] = await git.log());
296
+ });
297
+
298
+ after(async () => subject.removeAll());
299
+
300
+ it('stores snapshots IDs', () => {
301
+ expect(commit.body).to.include(config.get('recorder.versions.storage.git.snapshotIdentiferTemplate').replace(SNAPSHOT_ID_MARKER, SNAPSHOT_ID_1));
302
+ expect(commit.body).to.include(config.get('recorder.versions.storage.git.snapshotIdentiferTemplate').replace(SNAPSHOT_ID_MARKER, SNAPSHOT_ID_2));
303
+ });
304
+
305
+ it('stores the number of source documents', () => {
306
+ expect(commit.body).to.include(`${snapshotIds.length} source documents`);
307
+ });
308
+
309
+ it('stores the service ID', () => {
310
+ expect(commit.message).to.include(SERVICE_PROVIDER_ID);
311
+ });
312
+
313
+ it('stores the terms type', () => {
314
+ expect(commit.message).to.include(TERMS_TYPE);
315
+ });
316
+ });
317
+ });
318
+
319
+ describe('#findById', () => {
320
+ let record;
321
+ let id;
322
+
323
+ before(async () => {
324
+ ({ id } = await subject.save(new Version({
73
325
  serviceId: SERVICE_PROVIDER_ID,
74
- documentType: DOCUMENT_TYPE,
75
- pageId: PAGE_ID,
326
+ termsType: TERMS_TYPE,
76
327
  content: CONTENT,
77
328
  fetchDate: FETCH_DATE,
78
329
  snapshotIds: [SNAPSHOT_ID],
79
- mimeType: MIME_TYPE,
330
+ mimeType: HTML_MIME_TYPE,
80
331
  })));
81
332
 
82
- numberOfRecordsAfter = (await git.log()).length;
83
-
84
- ([commit] = await git.log());
333
+ (record = await subject.findById(id));
85
334
  });
86
335
 
87
336
  after(async () => subject.removeAll());
88
337
 
89
- it('saves the record', () => {
90
- expect(numberOfRecordsAfter).to.equal(numberOfRecordsBefore + 1);
338
+ it('returns a Version object', () => {
339
+ expect(record).to.be.an.instanceof(Version);
91
340
  });
92
341
 
93
342
  it('returns the record id', () => {
94
- expect(commit.hash).to.include(id);
343
+ expect(record.id).to.include(id);
95
344
  });
96
345
 
97
- it('returns a boolean to know if it is the first record', () => {
98
- expect(isFirstRecord).to.be.true;
346
+ it('states that it is the first record', () => {
347
+ expect(record.isFirstRecord).to.be.true;
99
348
  });
100
349
 
101
- it('stores the service ID', () => {
102
- expect(commit.message).to.include(SERVICE_PROVIDER_ID);
350
+ it('returns the service ID', () => {
351
+ expect(record.serviceId).to.equal(SERVICE_PROVIDER_ID);
103
352
  });
104
353
 
105
- it('stores the terms type', () => {
106
- expect(commit.message).to.include(DOCUMENT_TYPE);
354
+ it('returns the terms type', () => {
355
+ expect(record.termsType).to.equal(TERMS_TYPE);
107
356
  });
108
357
 
109
- it('stores information that it is the first record for this specific document', () => {
110
- expect(commit.message).to.include('Start tracking');
358
+ it('returns the content', async () => {
359
+ expect(record.content).to.equal(CONTENT);
111
360
  });
112
361
 
113
- it('stores the proper content', () => {
114
- expect(fs.readFileSync(EXPECTED_FILE_PATH_WITH_PAGE_ID, { encoding: 'utf8' })).to.equal(CONTENT);
362
+ it('returns the fetch date', () => {
363
+ expect(new Date(record.fetchDate).getTime()).to.equal(FETCH_DATE.getTime());
115
364
  });
116
365
 
117
- context('when provided', () => {
118
- it('stores the fetch date', () => {
119
- expect(new Date(commit.date).getTime()).to.equal(FETCH_DATE.getTime());
120
- });
121
-
122
- it('stores the MIME type', () => {
123
- expect(mime.getType(EXPECTED_FILE_PATH_WITH_PAGE_ID)).to.equal(MIME_TYPE);
124
- });
125
-
126
- it('stores the snapshot ID', () => {
127
- expect(commit.body).to.include(SNAPSHOT_ID);
128
- });
366
+ it('returns the snapshot ID', () => {
367
+ expect(record.snapshotIds).to.deep.equal([SNAPSHOT_ID]);
368
+ });
129
369
 
130
- it('stores the page ID', () => {
131
- expect(commit.body).to.include(PAGE_ID);
370
+ context('when requested record does not exist', () => {
371
+ it('returns null', async () => {
372
+ expect(await subject.findById('inexistantID')).to.equal(null);
132
373
  });
133
374
  });
134
375
  });
135
376
 
136
- context('when it is not the first record', () => {
137
- const UPDATED_CONTENT = `${CONTENT} updated`;
377
+ describe('#findAll', () => {
378
+ let records;
379
+ const expectedIds = [];
138
380
 
139
- before(async () => {
140
- await subject.save(new Record({
381
+ before(async function () {
382
+ this.timeout(5000);
383
+
384
+ const { id: id1 } = await subject.save(new Version({
141
385
  serviceId: SERVICE_PROVIDER_ID,
142
- documentType: DOCUMENT_TYPE,
386
+ termsType: TERMS_TYPE,
143
387
  content: CONTENT,
144
- mimeType: MIME_TYPE,
145
388
  fetchDate: FETCH_DATE,
389
+ snapshotIds: [SNAPSHOT_ID],
146
390
  }));
147
391
 
148
- numberOfRecordsBefore = (await git.log()).length;
392
+ expectedIds.push(id1);
149
393
 
150
- ({ id, isFirstRecord } = await subject.save(new Record({
394
+ const { id: id2 } = await subject.save(new Version({
151
395
  serviceId: SERVICE_PROVIDER_ID,
152
- documentType: DOCUMENT_TYPE,
153
- content: UPDATED_CONTENT,
154
- fetchDate: FETCH_DATE,
396
+ termsType: TERMS_TYPE,
397
+ content: `${CONTENT} - updated`,
398
+ fetchDate: FETCH_DATE_LATER,
155
399
  snapshotIds: [SNAPSHOT_ID],
156
- mimeType: MIME_TYPE,
157
- })));
400
+ }));
158
401
 
159
- numberOfRecordsAfter = (await git.log()).length;
402
+ expectedIds.push(id2);
160
403
 
161
- ([commit] = await git.log());
404
+ const { id: id3 } = await subject.save(new Version({
405
+ serviceId: SERVICE_PROVIDER_ID,
406
+ termsType: TERMS_TYPE,
407
+ content: `${CONTENT} - updated 2`,
408
+ isExtractOnly: true,
409
+ fetchDate: FETCH_DATE_EARLIER,
410
+ snapshotIds: [SNAPSHOT_ID],
411
+ }));
412
+
413
+ expectedIds.push(id3);
414
+
415
+ (records = await subject.findAll());
162
416
  });
163
417
 
164
418
  after(async () => subject.removeAll());
165
419
 
166
- it('saves the record', () => {
167
- expect(numberOfRecordsAfter).to.equal(numberOfRecordsBefore + 1);
420
+ it('returns all records', () => {
421
+ expect(records.length).to.equal(3);
168
422
  });
169
423
 
170
- it('returns the record id', () => {
171
- expect(commit.hash).to.include(id);
424
+ it('returns Version objects', () => {
425
+ for (const record of records) {
426
+ expect(record).to.be.an.instanceof(Version);
427
+ }
172
428
  });
173
429
 
174
- it('returns a boolean to know if it is the first record', () => {
175
- expect(isFirstRecord).to.be.false;
430
+ it('returns records in ascending order', async () => {
431
+ expect(records.map(record => record.fetchDate)).to.deep.equal([ FETCH_DATE_EARLIER, FETCH_DATE, FETCH_DATE_LATER ]);
176
432
  });
177
433
  });
178
434
 
179
- context('when the content has not changed', () => {
180
- before(async () => {
181
- await subject.save(new Record({
182
- serviceId: SERVICE_PROVIDER_ID,
183
- documentType: DOCUMENT_TYPE,
184
- content: CONTENT,
185
- mimeType: MIME_TYPE,
186
- fetchDate: FETCH_DATE,
187
- }));
435
+ describe('#count', () => {
436
+ let count;
188
437
 
189
- numberOfRecordsBefore = (await git.log()).length;
438
+ before(async function () {
439
+ this.timeout(5000);
190
440
 
191
- ({ id, isFirstRecord } = await subject.save(new Record({
441
+ await subject.save(new Version({
192
442
  serviceId: SERVICE_PROVIDER_ID,
193
- documentType: DOCUMENT_TYPE,
443
+ termsType: TERMS_TYPE,
194
444
  content: CONTENT,
195
- mimeType: MIME_TYPE,
196
445
  fetchDate: FETCH_DATE,
197
- })));
446
+ snapshotIds: [SNAPSHOT_ID],
447
+ }));
448
+ await subject.save(new Version({
449
+ serviceId: SERVICE_PROVIDER_ID,
450
+ termsType: TERMS_TYPE,
451
+ content: `${CONTENT} - updated`,
452
+ fetchDate: FETCH_DATE_LATER,
453
+ snapshotIds: [SNAPSHOT_ID],
454
+ }));
455
+ await subject.save(new Version({
456
+ serviceId: SERVICE_PROVIDER_ID,
457
+ termsType: TERMS_TYPE,
458
+ content: `${CONTENT} - updated 2`,
459
+ isExtractOnly: true,
460
+ fetchDate: FETCH_DATE_EARLIER,
461
+ snapshotIds: [SNAPSHOT_ID],
462
+ }));
198
463
 
199
- numberOfRecordsAfter = (await git.log()).length;
464
+ (count = await subject.count());
200
465
  });
201
466
 
202
467
  after(async () => subject.removeAll());
203
468
 
204
- it('does not save the record', () => {
205
- expect(numberOfRecordsAfter).to.equal(numberOfRecordsBefore);
469
+ it('returns the proper count', async () => {
470
+ expect(count).to.equal(3);
206
471
  });
472
+ });
207
473
 
208
- it('returns no id', () => {
209
- expect(id).to.equal(undefined);
474
+ describe('#findLatest', () => {
475
+ context('when there are records for the given service', () => {
476
+ let lastSnapshotId;
477
+ let latestRecord;
478
+
479
+ context('with HTML document', () => {
480
+ const UPDATED_FILE_CONTENT = `${CONTENT} (with additional content to trigger a record)`;
481
+
482
+ before(async () => {
483
+ await subject.save(new Version({
484
+ serviceId: SERVICE_PROVIDER_ID,
485
+ termsType: TERMS_TYPE,
486
+ content: CONTENT,
487
+ fetchDate: FETCH_DATE_EARLIER,
488
+ snapshotIds: [SNAPSHOT_ID],
489
+ }));
490
+
491
+ ({ id: lastSnapshotId } = await subject.save(new Version({
492
+ serviceId: SERVICE_PROVIDER_ID,
493
+ termsType: TERMS_TYPE,
494
+ content: UPDATED_FILE_CONTENT,
495
+ fetchDate: FETCH_DATE,
496
+ snapshotIds: [SNAPSHOT_ID],
497
+ })));
498
+
499
+ latestRecord = await subject.findLatest(SERVICE_PROVIDER_ID, TERMS_TYPE);
500
+ });
501
+
502
+ after(async () => subject.removeAll());
503
+
504
+ it('returns a Version object', () => {
505
+ expect(latestRecord).to.be.an.instanceof(Version);
506
+ });
507
+
508
+ it('returns the latest record id', () => {
509
+ expect(latestRecord.id).to.include(lastSnapshotId);
510
+ });
511
+
512
+ it('returns the latest record content', async () => {
513
+ expect(latestRecord.content.toString('utf8')).to.equal(UPDATED_FILE_CONTENT);
514
+ });
515
+ });
516
+ });
517
+
518
+ context('when there are no records for the given service', () => {
519
+ let latestRecord;
520
+
521
+ before(async () => {
522
+ latestRecord = await subject.findLatest(SERVICE_PROVIDER_ID, TERMS_TYPE);
523
+ });
524
+
525
+ it('returns null', async () => {
526
+ expect(latestRecord).to.equal(null);
527
+ });
210
528
  });
211
529
  });
212
530
 
213
- context('when it is a refilter', () => {
214
- const REFILTERED_CONTENT = `${CONTENT} refiltered`;
531
+ describe('#iterate', () => {
532
+ const expectedIds = [];
533
+ const ids = [];
534
+ const fetchDates = [];
215
535
 
216
536
  before(async () => {
217
- await subject.save(new Record({
537
+ const { id: id1 } = await subject.save(new Version({
218
538
  serviceId: SERVICE_PROVIDER_ID,
219
- documentType: DOCUMENT_TYPE,
539
+ termsType: TERMS_TYPE,
220
540
  content: CONTENT,
221
- mimeType: MIME_TYPE,
222
- fetchDate: FETCH_DATE_EARLIER,
223
- })); // A refilter cannot be the first record
541
+ fetchDate: FETCH_DATE,
542
+ snapshotIds: [SNAPSHOT_ID],
543
+ mimeType: HTML_MIME_TYPE,
544
+ }));
224
545
 
225
- numberOfRecordsBefore = (await git.log()).length;
546
+ expectedIds.push(id1);
226
547
 
227
- ({ id, isFirstRecord } = await subject.save(new Record({
548
+ const { id: id2 } = await subject.save(new Version({
228
549
  serviceId: SERVICE_PROVIDER_ID,
229
- documentType: DOCUMENT_TYPE,
230
- content: REFILTERED_CONTENT,
231
- fetchDate: FETCH_DATE,
232
- isRefilter: true,
550
+ termsType: TERMS_TYPE,
551
+ content: `${CONTENT} - updated`,
552
+ fetchDate: FETCH_DATE_LATER,
233
553
  snapshotIds: [SNAPSHOT_ID],
234
- mimeType: MIME_TYPE,
235
- })));
554
+ mimeType: HTML_MIME_TYPE,
555
+ }));
236
556
 
237
- numberOfRecordsAfter = (await git.log()).length;
557
+ expectedIds.push(id2);
238
558
 
239
- ([commit] = await git.log());
559
+ const { id: id3 } = await subject.save(new Version({
560
+ serviceId: SERVICE_PROVIDER_ID,
561
+ termsType: TERMS_TYPE,
562
+ content: `${CONTENT} - updated 2`,
563
+ isExtractOnly: true,
564
+ fetchDate: FETCH_DATE_EARLIER,
565
+ snapshotIds: [SNAPSHOT_ID],
566
+ mimeType: HTML_MIME_TYPE,
567
+ }));
568
+
569
+ expectedIds.push(id3);
570
+
571
+ for await (const record of subject.iterate()) {
572
+ ids.push(record.id);
573
+ fetchDates.push(record.fetchDate);
574
+ }
240
575
  });
241
576
 
242
577
  after(async () => subject.removeAll());
243
578
 
244
- it('saves the record', () => {
245
- expect(numberOfRecordsAfter).to.equal(numberOfRecordsBefore + 1);
579
+ it('iterates through all records', async () => {
580
+ expect(ids).to.have.members(expectedIds);
246
581
  });
247
582
 
248
- it('returns the record id', () => {
249
- expect(commit.hash).to.include(id);
583
+ it('iterates in ascending order', async () => {
584
+ expect(fetchDates).to.deep.equal([ FETCH_DATE_EARLIER, FETCH_DATE, FETCH_DATE_LATER ]);
250
585
  });
586
+ });
587
+ });
251
588
 
252
- it('stores information that it is a refilter of this specific document', () => {
253
- expect(commit.message).to.include('Refilter');
589
+ context('Snapshot', () => {
590
+ before(async function () {
591
+ this.timeout(5000);
592
+ git = new Git({
593
+ path: RECORDER_PATH,
594
+ author: {
595
+ name: config.get('recorder.snapshots.storage.git.author.name'),
596
+ email: config.get('recorder.snapshots.storage.git.author.email'),
597
+ },
254
598
  });
599
+
600
+ await git.initialize();
601
+
602
+ subject = new GitRepository({
603
+ ...config.get('recorder.snapshots.storage.git'),
604
+ path: RECORDER_PATH,
605
+ });
606
+
607
+ return subject.initialize();
255
608
  });
256
609
 
257
- context('with PDF document', () => {
258
- before(async () => {
259
- numberOfRecordsBefore = (await git.log()).length;
610
+ describe('#save', () => {
611
+ let id;
612
+ let commit;
613
+ let isFirstRecord;
614
+ let numberOfRecordsBefore;
615
+ let numberOfRecordsAfter;
260
616
 
261
- ({ id, isFirstRecord } = await subject.save(new Record({
262
- serviceId: SERVICE_PROVIDER_ID,
263
- documentType: DOCUMENT_TYPE,
264
- content: PDF_CONTENT,
265
- fetchDate: FETCH_DATE,
266
- snapshotIds: [SNAPSHOT_ID],
267
- mimeType: PDF_MIME_TYPE,
268
- })));
617
+ context('when it is the first record', () => {
618
+ before(async () => {
619
+ numberOfRecordsBefore = (await git.log()).length;
620
+
621
+ ({ id, isFirstRecord } = await subject.save(new Snapshot({
622
+ serviceId: SERVICE_PROVIDER_ID,
623
+ termsType: TERMS_TYPE,
624
+ documentId: DOCUMENT_ID,
625
+ content: CONTENT,
626
+ fetchDate: FETCH_DATE,
627
+ mimeType: HTML_MIME_TYPE,
628
+ })));
629
+
630
+ numberOfRecordsAfter = (await git.log()).length;
631
+
632
+ ([commit] = await git.log());
633
+ });
634
+
635
+ after(async () => subject.removeAll());
269
636
 
270
- numberOfRecordsAfter = (await git.log()).length;
637
+ it('saves the record', () => {
638
+ expect(numberOfRecordsAfter).to.equal(numberOfRecordsBefore + 1);
639
+ });
640
+
641
+ it('returns the record id', () => {
642
+ expect(commit.hash).to.include(id);
643
+ });
644
+
645
+ it('states that it is the first record', () => {
646
+ expect(isFirstRecord).to.be.true;
647
+ });
648
+
649
+ it('stores the service ID', () => {
650
+ expect(commit.message).to.include(SERVICE_PROVIDER_ID);
651
+ });
652
+
653
+ it('stores the terms type', () => {
654
+ expect(commit.message).to.include(TERMS_TYPE);
655
+ });
656
+
657
+ it('stores information that it is the first record for these specific terms', () => {
658
+ expect(commit.message).to.include(COMMIT_MESSAGE_PREFIXES.startTracking);
659
+ });
660
+
661
+ it('stores the proper content', () => {
662
+ expect(fs.readFileSync(EXPECTED_SNAPSHOT_FILE_PATH_WITH_DOCUMENT_ID, { encoding: 'utf8' })).to.equal(CONTENT);
663
+ });
271
664
 
272
- ([commit] = await git.log());
665
+ it('stores the fetch date', () => {
666
+ expect(new Date(commit.date).getTime()).to.equal(FETCH_DATE.getTime());
667
+ });
668
+
669
+ it('stores the MIME type', () => {
670
+ expect(mime.getType(EXPECTED_SNAPSHOT_FILE_PATH_WITH_DOCUMENT_ID)).to.equal(HTML_MIME_TYPE);
671
+ });
672
+
673
+ it('stores the document ID', () => {
674
+ expect(commit.body).to.include(DOCUMENT_ID);
675
+ });
273
676
  });
274
677
 
275
- after(async () => subject.removeAll());
678
+ context('when it is not the first record', () => {
679
+ const UPDATED_CONTENT = `${CONTENT} updated`;
680
+
681
+ before(async () => {
682
+ await subject.save(new Snapshot({
683
+ serviceId: SERVICE_PROVIDER_ID,
684
+ termsType: TERMS_TYPE,
685
+ content: CONTENT,
686
+ mimeType: HTML_MIME_TYPE,
687
+ fetchDate: FETCH_DATE,
688
+ }));
689
+
690
+ numberOfRecordsBefore = (await git.log()).length;
691
+
692
+ ({ id, isFirstRecord } = await subject.save(new Snapshot({
693
+ serviceId: SERVICE_PROVIDER_ID,
694
+ termsType: TERMS_TYPE,
695
+ content: UPDATED_CONTENT,
696
+ fetchDate: FETCH_DATE,
697
+ mimeType: HTML_MIME_TYPE,
698
+ })));
699
+
700
+ numberOfRecordsAfter = (await git.log()).length;
701
+
702
+ ([commit] = await git.log());
703
+ });
704
+
705
+ after(async () => subject.removeAll());
706
+
707
+ it('saves the record', () => {
708
+ expect(numberOfRecordsAfter).to.equal(numberOfRecordsBefore + 1);
709
+ });
710
+
711
+ it('returns the record id', () => {
712
+ expect(commit.hash).to.include(id);
713
+ });
276
714
 
277
- it('saves the record', () => {
278
- expect(numberOfRecordsAfter).to.equal(numberOfRecordsBefore + 1);
715
+ it('states that it is not the first record', () => {
716
+ expect(isFirstRecord).to.be.false;
717
+ });
279
718
  });
280
719
 
281
- it('returns the record id', () => {
282
- expect(commit.hash).to.include(id);
720
+ context('when the content has not changed', () => {
721
+ before(async () => {
722
+ await subject.save(new Snapshot({
723
+ serviceId: SERVICE_PROVIDER_ID,
724
+ termsType: TERMS_TYPE,
725
+ content: CONTENT,
726
+ mimeType: HTML_MIME_TYPE,
727
+ fetchDate: FETCH_DATE,
728
+ }));
729
+
730
+ numberOfRecordsBefore = (await git.log()).length;
731
+
732
+ ({ id, isFirstRecord } = await subject.save(new Snapshot({
733
+ serviceId: SERVICE_PROVIDER_ID,
734
+ termsType: TERMS_TYPE,
735
+ content: CONTENT,
736
+ mimeType: HTML_MIME_TYPE,
737
+ fetchDate: FETCH_DATE,
738
+ })));
739
+
740
+ numberOfRecordsAfter = (await git.log()).length;
741
+ });
742
+
743
+ after(async () => subject.removeAll());
744
+
745
+ it('does not save the record', () => {
746
+ expect(numberOfRecordsAfter).to.equal(numberOfRecordsBefore);
747
+ });
748
+
749
+ it('returns no id', () => {
750
+ expect(id).to.equal(undefined);
751
+ });
283
752
  });
284
753
 
285
- it('stores the proper content', () => {
286
- expect(fs.readFileSync(EXPECTED_PDF_FILE_PATH, { encoding: 'utf8' })).to.equal(PDF_CONTENT);
754
+ context('when there are no document ID specified', () => {
755
+ before(async () => {
756
+ numberOfRecordsBefore = (await git.log()).length;
757
+
758
+ ({ id, isFirstRecord } = await subject.save(new Snapshot({
759
+ serviceId: SERVICE_PROVIDER_ID,
760
+ termsType: TERMS_TYPE,
761
+ content: CONTENT,
762
+ fetchDate: FETCH_DATE,
763
+ mimeType: HTML_MIME_TYPE,
764
+ })));
765
+
766
+ numberOfRecordsAfter = (await git.log()).length;
767
+
768
+ ([commit] = await git.log());
769
+ });
770
+
771
+ after(async () => subject.removeAll());
772
+
773
+ it('saves the record', () => {
774
+ expect(numberOfRecordsAfter).to.equal(numberOfRecordsBefore + 1);
775
+ });
776
+
777
+ it('returns the record id', () => {
778
+ expect(commit.hash).to.include(id);
779
+ });
780
+
781
+ it('stores the proper content under the proper file path', () => {
782
+ expect(fs.readFileSync(EXPECTED_SNAPSHOT_FILE_PATH, { encoding: 'utf8' })).to.equal(CONTENT);
783
+ });
287
784
  });
288
785
 
289
- it('stores the MIME type', () => {
290
- expect(mime.getType(EXPECTED_PDF_FILE_PATH)).to.equal(PDF_MIME_TYPE);
786
+ context('with PDF document', () => {
787
+ before(async () => {
788
+ numberOfRecordsBefore = (await git.log()).length;
789
+
790
+ ({ id, isFirstRecord } = await subject.save(new Snapshot({
791
+ serviceId: SERVICE_PROVIDER_ID,
792
+ termsType: TERMS_TYPE,
793
+ content: PDF_CONTENT,
794
+ fetchDate: FETCH_DATE,
795
+ mimeType: PDF_MIME_TYPE,
796
+ })));
797
+
798
+ numberOfRecordsAfter = (await git.log()).length;
799
+
800
+ ([commit] = await git.log());
801
+ });
802
+
803
+ after(async () => subject.removeAll());
804
+
805
+ it('saves the record', () => {
806
+ expect(numberOfRecordsAfter).to.equal(numberOfRecordsBefore + 1);
807
+ });
808
+
809
+ it('returns the record id', () => {
810
+ expect(commit.hash).to.include(id);
811
+ });
812
+
813
+ it('stores the proper content', () => {
814
+ expect(fs.readFileSync(EXPECTED_PDF_SNAPSHOT_FILE_PATH, { encoding: 'utf8' })).to.equal(PDF_CONTENT);
815
+ });
816
+ it('stores the MIME type', () => {
817
+ expect(mime.getType(EXPECTED_PDF_SNAPSHOT_FILE_PATH)).to.equal(PDF_MIME_TYPE);
818
+ });
291
819
  });
292
820
  });
293
821
 
294
- context('when there is no snapshots IDs specified', () => {
822
+ describe('#findById', () => {
823
+ let record;
824
+ let id;
825
+
295
826
  before(async () => {
296
- ({ id, isFirstRecord } = await subject.save(new Record({
827
+ ({ id } = await subject.save(new Snapshot({
297
828
  serviceId: SERVICE_PROVIDER_ID,
298
- documentType: DOCUMENT_TYPE,
299
- pageId: PAGE_ID,
829
+ termsType: TERMS_TYPE,
830
+ documentId: DOCUMENT_ID,
300
831
  content: CONTENT,
301
832
  fetchDate: FETCH_DATE,
302
- mimeType: MIME_TYPE,
833
+ mimeType: HTML_MIME_TYPE,
303
834
  })));
304
835
 
305
- ([commit] = await git.log());
836
+ (record = await subject.findById(id));
306
837
  });
307
838
 
308
839
  after(async () => subject.removeAll());
309
840
 
310
- it('does not store snapshots IDs', () => {
311
- expect(commit.body).to.be.equal(`Page ID ${PAGE_ID}\n`);
841
+ it('returns a Snapshot object', () => {
842
+ expect(record).to.be.an.instanceof(Snapshot);
312
843
  });
313
844
 
314
- it('stores the service ID', () => {
315
- expect(commit.message).to.include(SERVICE_PROVIDER_ID);
845
+ it('returns the record id', () => {
846
+ expect(record.id).to.include(id);
316
847
  });
317
848
 
318
- it('stores the terms type', () => {
319
- expect(commit.message).to.include(DOCUMENT_TYPE);
849
+ it('states that it is the first record', () => {
850
+ expect(record.isFirstRecord).to.be.true;
320
851
  });
321
852
 
322
- it('stores the page ID', () => {
323
- expect(commit.body).to.include(PAGE_ID);
853
+ it('returns the service ID', () => {
854
+ expect(record.serviceId).to.equal(SERVICE_PROVIDER_ID);
324
855
  });
325
- });
326
-
327
- context('when one snapshot ID is specified', () => {
328
- const SNAPSHOT_ID = 'c01533c0e546ef430eea84d23c1b18a2b8420dfb';
329
- const snapshotIds = [SNAPSHOT_ID];
330
-
331
- before(async () => {
332
- ({ id, isFirstRecord } = await subject.save(new Record({
333
- serviceId: SERVICE_PROVIDER_ID,
334
- documentType: DOCUMENT_TYPE,
335
- pageId: PAGE_ID,
336
- content: CONTENT,
337
- fetchDate: FETCH_DATE,
338
- mimeType: MIME_TYPE,
339
- snapshotIds,
340
- })));
341
856
 
342
- ([commit] = await git.log());
857
+ it('returns the terms type', () => {
858
+ expect(record.termsType).to.equal(TERMS_TYPE);
343
859
  });
344
860
 
345
- after(async () => subject.removeAll());
861
+ it('returns the content', async () => {
862
+ expect(record.content).to.equal(CONTENT);
863
+ });
346
864
 
347
- it('stores snapshot ID', () => {
348
- expect(commit.body).to.include(config.get('recorder.versions.storage.git.snapshotIdentiferTemplate').replace(SNAPSHOT_ID_MARKER, SNAPSHOT_ID));
865
+ it('returns the fetch date', () => {
866
+ expect(new Date(record.fetchDate).getTime()).to.equal(FETCH_DATE.getTime());
349
867
  });
350
868
 
351
- it('stores the service ID', () => {
352
- expect(commit.message).to.include(SERVICE_PROVIDER_ID);
869
+ it('returns the MIME type', () => {
870
+ expect(record.mimeType).to.equal(HTML_MIME_TYPE);
353
871
  });
354
872
 
355
- it('stores the terms type', () => {
356
- expect(commit.message).to.include(DOCUMENT_TYPE);
873
+ it('returns the document ID', () => {
874
+ expect(record.documentId).to.equal(DOCUMENT_ID);
357
875
  });
358
876
 
359
- it('stores the page ID', () => {
360
- expect(commit.body).to.include(PAGE_ID);
877
+ context('when requested record does not exist', () => {
878
+ it('returns null', async () => {
879
+ expect(await subject.findById('inexistantID')).to.equal(null);
880
+ });
361
881
  });
362
882
  });
363
883
 
364
- context('when there are many snapshots IDs specified', () => {
365
- const SNAPSHOT_ID_1 = 'c01533c0e546ef430eea84d23c1b18a2b8420dfb';
366
- const SNAPSHOT_ID_2 = '0fd16cca9e1a86a2267bd587107c485f06099d7d';
367
- const snapshotIds = [ SNAPSHOT_ID_1, SNAPSHOT_ID_2 ];
884
+ describe('#findAll', () => {
885
+ let records;
886
+ const expectedIds = [];
368
887
 
369
- before(async () => {
370
- ({ id, isFirstRecord } = await subject.save(new Record({
888
+ before(async function () {
889
+ this.timeout(5000);
890
+
891
+ const { id: id1 } = await subject.save(new Snapshot({
371
892
  serviceId: SERVICE_PROVIDER_ID,
372
- documentType: DOCUMENT_TYPE,
373
- pageId: PAGE_ID,
893
+ termsType: TERMS_TYPE,
374
894
  content: CONTENT,
375
895
  fetchDate: FETCH_DATE,
376
- mimeType: MIME_TYPE,
377
- snapshotIds,
378
- })));
896
+ documentId: DOCUMENT_ID,
897
+ mimeType: HTML_MIME_TYPE,
898
+ }));
899
+
900
+ expectedIds.push(id1);
901
+
902
+ const { id: id2 } = await subject.save(new Snapshot({
903
+ serviceId: SERVICE_PROVIDER_ID,
904
+ termsType: TERMS_TYPE,
905
+ content: `${CONTENT} - updated`,
906
+ fetchDate: FETCH_DATE_LATER,
907
+ mimeType: HTML_MIME_TYPE,
908
+ }));
909
+
910
+ expectedIds.push(id2);
379
911
 
380
- ([commit] = await git.log());
912
+ const { id: id3 } = await subject.save(new Snapshot({
913
+ serviceId: SERVICE_PROVIDER_ID,
914
+ termsType: TERMS_TYPE,
915
+ content: `${CONTENT} - updated 2`,
916
+ isExtractOnly: true,
917
+ fetchDate: FETCH_DATE_EARLIER,
918
+ mimeType: HTML_MIME_TYPE,
919
+ }));
920
+
921
+ expectedIds.push(id3);
922
+
923
+ (records = await subject.findAll());
381
924
  });
382
925
 
383
926
  after(async () => subject.removeAll());
384
927
 
385
- it('stores snapshots IDs', () => {
386
- expect(commit.body).to.include(config.get('recorder.versions.storage.git.snapshotIdentiferTemplate').replace(SNAPSHOT_ID_MARKER, SNAPSHOT_ID_1));
387
- expect(commit.body).to.include(config.get('recorder.versions.storage.git.snapshotIdentiferTemplate').replace(SNAPSHOT_ID_MARKER, SNAPSHOT_ID_2));
928
+ it('returns all records', () => {
929
+ expect(records.length).to.equal(3);
388
930
  });
389
931
 
390
- it('stores number of pages', () => {
391
- expect(commit.body).to.include(`${snapshotIds.length} pages`);
932
+ it('returns Snapshot objects', () => {
933
+ for (const record of records) {
934
+ expect(record).to.be.an.instanceof(Snapshot);
935
+ }
392
936
  });
393
937
 
394
- it('stores the service ID', () => {
395
- expect(commit.message).to.include(SERVICE_PROVIDER_ID);
938
+ it('returns records in ascending order', async () => {
939
+ expect(records.map(record => record.fetchDate)).to.deep.equal([ FETCH_DATE_EARLIER, FETCH_DATE, FETCH_DATE_LATER ]);
396
940
  });
941
+ });
942
+
943
+ describe('#count', () => {
944
+ let count;
945
+
946
+ before(async function () {
947
+ this.timeout(5000);
397
948
 
398
- it('stores the terms type', () => {
399
- expect(commit.message).to.include(DOCUMENT_TYPE);
949
+ await subject.save(new Snapshot({
950
+ serviceId: SERVICE_PROVIDER_ID,
951
+ termsType: TERMS_TYPE,
952
+ content: CONTENT,
953
+ fetchDate: FETCH_DATE,
954
+ mimeType: HTML_MIME_TYPE,
955
+ }));
956
+ await subject.save(new Snapshot({
957
+ serviceId: SERVICE_PROVIDER_ID,
958
+ termsType: TERMS_TYPE,
959
+ content: `${CONTENT} - updated`,
960
+ fetchDate: FETCH_DATE_LATER,
961
+ mimeType: HTML_MIME_TYPE,
962
+ }));
963
+ await subject.save(new Snapshot({
964
+ serviceId: SERVICE_PROVIDER_ID,
965
+ termsType: TERMS_TYPE,
966
+ content: `${CONTENT} - updated 2`,
967
+ isExtractOnly: true,
968
+ fetchDate: FETCH_DATE_EARLIER,
969
+ mimeType: HTML_MIME_TYPE,
970
+ }));
971
+
972
+ (count = await subject.count());
400
973
  });
401
974
 
402
- it('stores the page ID', () => {
403
- expect(commit.body).to.include(PAGE_ID);
975
+ after(async () => subject.removeAll());
976
+
977
+ it('returns the proper count', async () => {
978
+ expect(count).to.equal(3);
404
979
  });
405
980
  });
406
- });
407
981
 
408
- describe('#findById', () => {
409
- let record;
410
- let id;
411
-
412
- before(async () => {
413
- ({ id } = await subject.save(new Record({
414
- serviceId: SERVICE_PROVIDER_ID,
415
- documentType: DOCUMENT_TYPE,
416
- pageId: PAGE_ID,
417
- content: CONTENT,
418
- fetchDate: FETCH_DATE,
419
- snapshotIds: [SNAPSHOT_ID],
420
- mimeType: MIME_TYPE,
421
- })));
422
-
423
- (record = await subject.findById(id));
424
- });
982
+ describe('#findLatest', () => {
983
+ context('when there are records for the given service', () => {
984
+ let lastSnapshotId;
985
+ let latestRecord;
986
+
987
+ context('with HTML document', () => {
988
+ const UPDATED_FILE_CONTENT = `${CONTENT} (with additional content to trigger a record)`;
989
+
990
+ before(async () => {
991
+ await subject.save(new Snapshot({
992
+ serviceId: SERVICE_PROVIDER_ID,
993
+ termsType: TERMS_TYPE,
994
+ content: CONTENT,
995
+ mimeType: HTML_MIME_TYPE,
996
+ fetchDate: FETCH_DATE_EARLIER,
997
+ }));
998
+
999
+ ({ id: lastSnapshotId } = await subject.save(new Snapshot({
1000
+ serviceId: SERVICE_PROVIDER_ID,
1001
+ termsType: TERMS_TYPE,
1002
+ content: UPDATED_FILE_CONTENT,
1003
+ mimeType: HTML_MIME_TYPE,
1004
+ fetchDate: FETCH_DATE,
1005
+ })));
1006
+
1007
+ latestRecord = await subject.findLatest(SERVICE_PROVIDER_ID, TERMS_TYPE);
1008
+ });
1009
+
1010
+ after(async () => subject.removeAll());
1011
+
1012
+ it('returns a Snapshot object', () => {
1013
+ expect(latestRecord).to.be.an.instanceof(Snapshot);
1014
+ });
1015
+
1016
+ it('returns the latest record id', () => {
1017
+ expect(latestRecord.id).to.include(lastSnapshotId);
1018
+ });
1019
+
1020
+ it('returns the latest record content', async () => {
1021
+ expect(latestRecord.content.toString('utf8')).to.equal(UPDATED_FILE_CONTENT);
1022
+ });
1023
+
1024
+ it('returns the latest record mime type', () => {
1025
+ expect(latestRecord.mimeType).to.equal(HTML_MIME_TYPE);
1026
+ });
1027
+ });
425
1028
 
426
- after(async () => subject.removeAll());
1029
+ context('with PDF document', () => {
1030
+ before(async () => {
1031
+ ({ id: lastSnapshotId } = await subject.save(new Snapshot({
1032
+ serviceId: SERVICE_PROVIDER_ID,
1033
+ termsType: TERMS_TYPE,
1034
+ content: PDF_CONTENT,
1035
+ mimeType: PDF_MIME_TYPE,
1036
+ fetchDate: FETCH_DATE,
1037
+ })));
427
1038
 
428
- it('returns the record id', () => {
429
- expect(record.id).to.include(id);
430
- });
1039
+ latestRecord = await subject.findLatest(SERVICE_PROVIDER_ID, TERMS_TYPE);
1040
+ });
431
1041
 
432
- it('returns a boolean to know if it is the first record', () => {
433
- expect(record.isFirstRecord).to.be.true;
434
- });
1042
+ after(async () => subject.removeAll());
435
1043
 
436
- it('returns the service ID', () => {
437
- expect(record.serviceId).to.equal(SERVICE_PROVIDER_ID);
438
- });
1044
+ it('returns the latest record id', () => {
1045
+ expect(latestRecord.id).to.include(lastSnapshotId);
1046
+ });
439
1047
 
440
- it('returns the terms type', () => {
441
- expect(record.documentType).to.equal(DOCUMENT_TYPE);
442
- });
1048
+ it('returns the latest record content', async () => {
1049
+ expect(latestRecord.content.toString('utf8')).to.equal(PDF_CONTENT);
1050
+ });
443
1051
 
444
- it('returns the content', async () => {
445
- expect(record.content).to.equal(CONTENT);
446
- });
1052
+ it('returns the latest record mime type', () => {
1053
+ expect(latestRecord.mimeType).to.equal(PDF_MIME_TYPE);
1054
+ });
1055
+ });
1056
+ });
447
1057
 
448
- it('returns the fetch date', () => {
449
- expect(new Date(record.fetchDate).getTime()).to.equal(FETCH_DATE.getTime());
450
- });
1058
+ context('when there are no records for the given service', () => {
1059
+ let latestRecord;
451
1060
 
452
- it('returns the MIME type', () => {
453
- expect(record.mimeType).to.equal(MIME_TYPE);
454
- });
1061
+ before(async () => {
1062
+ latestRecord = await subject.findLatest(SERVICE_PROVIDER_ID, TERMS_TYPE);
1063
+ });
455
1064
 
456
- it('returns the snapshot ID', () => {
457
- expect(record.snapshotIds).to.deep.equal([SNAPSHOT_ID]);
1065
+ it('returns null', async () => {
1066
+ expect(latestRecord).to.equal(null);
1067
+ });
1068
+ });
458
1069
  });
459
1070
 
460
- it('returns the page ID', () => {
461
- expect(record.pageId).to.equal(PAGE_ID);
462
- });
1071
+ describe('#iterate', () => {
1072
+ const expectedIds = [];
1073
+ const ids = [];
1074
+ const fetchDates = [];
463
1075
 
464
- context('when requested record does not exist', () => {
465
- it('returns null', async () => {
466
- expect(await subject.findById('inexistantID')).to.equal(null);
467
- });
468
- });
469
- });
1076
+ before(async () => {
1077
+ const { id: id1 } = await subject.save(new Snapshot({
1078
+ serviceId: SERVICE_PROVIDER_ID,
1079
+ termsType: TERMS_TYPE,
1080
+ content: CONTENT,
1081
+ fetchDate: FETCH_DATE,
1082
+ mimeType: HTML_MIME_TYPE,
1083
+ }));
470
1084
 
471
- describe('#findAll', () => {
472
- let records;
473
- const expectedIds = [];
1085
+ expectedIds.push(id1);
474
1086
 
475
- before(async function () {
476
- this.timeout(5000);
1087
+ const { id: id2 } = await subject.save(new Snapshot({
1088
+ serviceId: SERVICE_PROVIDER_ID,
1089
+ termsType: TERMS_TYPE,
1090
+ content: `${CONTENT} - updated`,
1091
+ fetchDate: FETCH_DATE_LATER,
1092
+ mimeType: HTML_MIME_TYPE,
1093
+ }));
477
1094
 
478
- const { id: id1 } = await subject.save(new Record({
479
- serviceId: SERVICE_PROVIDER_ID,
480
- documentType: DOCUMENT_TYPE,
481
- content: CONTENT,
482
- fetchDate: FETCH_DATE,
483
- snapshotIds: [SNAPSHOT_ID],
484
- mimeType: MIME_TYPE,
485
- }));
486
-
487
- expectedIds.push(id1);
488
-
489
- const { id: id2 } = await subject.save(new Record({
490
- serviceId: SERVICE_PROVIDER_ID,
491
- documentType: DOCUMENT_TYPE,
492
- content: `${CONTENT} - updated`,
493
- fetchDate: FETCH_DATE_LATER,
494
- snapshotIds: [SNAPSHOT_ID],
495
- mimeType: MIME_TYPE,
496
- }));
497
-
498
- expectedIds.push(id2);
499
-
500
- const { id: id3 } = await subject.save(new Record({
501
- serviceId: SERVICE_PROVIDER_ID,
502
- documentType: DOCUMENT_TYPE,
503
- content: `${CONTENT} - updated 2`,
504
- isRefilter: true,
505
- fetchDate: FETCH_DATE_EARLIER,
506
- snapshotIds: [SNAPSHOT_ID],
507
- mimeType: MIME_TYPE,
508
- }));
509
-
510
- expectedIds.push(id3);
511
-
512
- (records = await subject.findAll());
513
- });
1095
+ expectedIds.push(id2);
514
1096
 
515
- after(async () => subject.removeAll());
1097
+ const { id: id3 } = await subject.save(new Snapshot({
1098
+ serviceId: SERVICE_PROVIDER_ID,
1099
+ termsType: TERMS_TYPE,
1100
+ content: `${CONTENT} - updated 2`,
1101
+ isExtractOnly: true,
1102
+ fetchDate: FETCH_DATE_EARLIER,
1103
+ mimeType: HTML_MIME_TYPE,
1104
+ }));
516
1105
 
517
- it('returns all records', () => {
518
- expect(records.length).to.equal(3);
519
- });
1106
+ expectedIds.push(id3);
520
1107
 
521
- it('returns Record objects', () => {
522
- for (const record of records) {
523
- expect(record).to.be.an.instanceof(Record);
524
- }
525
- });
1108
+ for await (const record of subject.iterate()) {
1109
+ ids.push(record.id);
1110
+ fetchDates.push(record.fetchDate);
1111
+ }
1112
+ });
1113
+
1114
+ after(async () => subject.removeAll());
1115
+
1116
+ it('iterates through all records', async () => {
1117
+ expect(ids).to.have.members(expectedIds);
1118
+ });
526
1119
 
527
- it('returns records in ascending order', async () => {
528
- expect(records.map(record => record.fetchDate)).to.deep.equal([ FETCH_DATE_EARLIER, FETCH_DATE, FETCH_DATE_LATER ]);
1120
+ it('iterates in ascending order', async () => {
1121
+ expect(fetchDates).to.deep.equal([ FETCH_DATE_EARLIER, FETCH_DATE, FETCH_DATE_LATER ]);
1122
+ });
529
1123
  });
530
1124
  });
531
1125
 
532
- describe('#count', () => {
533
- let count;
1126
+ context('backwards compatibility with deprecated commit messages', () => {
1127
+ const expectedIds = [];
1128
+ const expectedDates = [];
1129
+
1130
+ let subject;
1131
+
1132
+ const commits = {
1133
+ deprecatedFirstRecord: {
1134
+ path: 'service/terms-deprecated.md',
1135
+ content: 'content',
1136
+ message: 'Start tracking Service Terms\n\nThis version was recorded after extracting from snapshot https://github.com/ambanum/OpenTermsArchive-snapshots/commit/513fadb2ae415c87747047e33287805d59e2dd55',
1137
+ date: new Date('2023-02-28T01:00:00.000Z'),
1138
+ },
1139
+ deprecatedRefilter: {
1140
+ path: 'service/terms-deprecated.md',
1141
+ content: 'content refiltered',
1142
+ message: 'Refilter Service Terms\n\nThis version was recorded after extracting from snapshot https://github.com/ambanum/OpenTermsArchive-snapshots/commit/513fadb2ae415c87747047e33287805d59e2dd55',
1143
+ date: new Date('2023-02-28T02:00:00.000Z'),
1144
+ },
1145
+ deprecatedUpdate: {
1146
+ path: 'service/terms-deprecated.md',
1147
+ content: 'content updated',
1148
+ message: 'Update Service Terms\n\nThis version was recorded after extracting from snapshot https://github.com/ambanum/OpenTermsArchive-snapshots/commit/513fadb2ae415c87747047e33287805d59e2dd55',
1149
+ date: new Date('2023-02-28T03:00:00.000Z'),
1150
+ },
1151
+ currentFirstRecord: {
1152
+ path: 'service/terms-current.md',
1153
+ content: 'content',
1154
+ message: 'First record of Service Terms\n\nThis version was recorded after extracting from snapshot https://github.com/ambanum/OpenTermsArchive-snapshots/commit/513fadb2ae415c87747047e33287805d59e2dd55',
1155
+ date: new Date('2023-02-28T04:00:00.000Z'),
1156
+ },
1157
+ currentExtractOnly: {
1158
+ path: 'service/terms-current.md',
1159
+ content: 'content extract only',
1160
+ message: 'Apply technical or declaration upgrade on Service Terms\n\nThis version was recorded after extracting from snapshot https://github.com/ambanum/OpenTermsArchive-snapshots/commit/513fadb2ae415c87747047e33287805d59e2dd55',
1161
+ date: new Date('2023-02-28T05:00:00.000Z'),
1162
+ },
1163
+ currentUpdate: {
1164
+ path: 'service/terms-current.md',
1165
+ content: 'content updated',
1166
+ message: 'Record new changes of Service Terms\n\nThis version was recorded after extracting from snapshot https://github.com/ambanum/OpenTermsArchive-snapshots/commit/513fadb2ae415c87747047e33287805d59e2dd55',
1167
+ date: new Date('2023-02-28T06:00:00.000Z'),
1168
+ },
1169
+ };
534
1170
 
535
1171
  before(async function () {
536
1172
  this.timeout(5000);
1173
+ git = new Git({
1174
+ path: RECORDER_PATH,
1175
+ author: {
1176
+ name: config.get('recorder.versions.storage.git.author.name'),
1177
+ email: config.get('recorder.versions.storage.git.author.email'),
1178
+ },
1179
+ });
537
1180
 
538
- await subject.save(new Record({
539
- serviceId: SERVICE_PROVIDER_ID,
540
- documentType: DOCUMENT_TYPE,
541
- content: CONTENT,
542
- fetchDate: FETCH_DATE,
543
- snapshotIds: [SNAPSHOT_ID],
544
- mimeType: MIME_TYPE,
545
- }));
546
- await subject.save(new Record({
547
- serviceId: SERVICE_PROVIDER_ID,
548
- documentType: DOCUMENT_TYPE,
549
- content: `${CONTENT} - updated`,
550
- fetchDate: FETCH_DATE_LATER,
551
- snapshotIds: [SNAPSHOT_ID],
552
- mimeType: MIME_TYPE,
553
- }));
554
- await subject.save(new Record({
555
- serviceId: SERVICE_PROVIDER_ID,
556
- documentType: DOCUMENT_TYPE,
557
- content: `${CONTENT} - updated 2`,
558
- isRefilter: true,
559
- fetchDate: FETCH_DATE_EARLIER,
560
- snapshotIds: [SNAPSHOT_ID],
561
- mimeType: MIME_TYPE,
562
- }));
563
-
564
- (count = await subject.count());
565
- });
1181
+ await git.initialize();
1182
+ subject = new GitRepository({
1183
+ ...config.get('recorder.versions.storage.git'),
1184
+ path: RECORDER_PATH,
1185
+ });
566
1186
 
567
- after(async () => subject.removeAll());
1187
+ await subject.initialize();
568
1188
 
569
- it('returns the proper count', async () => {
570
- expect(count).to.equal(3);
571
- });
572
- });
1189
+ /* eslint-disable no-await-in-loop */
1190
+ for (const commit of Object.values(commits)) {
1191
+ const { path: relativeFilePath, date, content, message } = commit;
1192
+ const filePath = path.join(RECORDER_PATH, relativeFilePath);
573
1193
 
574
- describe('#findLatest', () => {
575
- context('when there are records for the given service', () => {
576
- let lastSnapshotId;
577
- let latestRecord;
1194
+ await GitRepository.writeFile({ filePath, content });
578
1195
 
579
- context('with HTML document', () => {
580
- const UPDATED_FILE_CONTENT = `${CONTENT} (with additional content to trigger a record)`;
1196
+ await git.add(filePath);
1197
+ const sha = await git.commit({ filePath, message, date });
581
1198
 
582
- before(async () => {
583
- await subject.save(new Record({
584
- serviceId: SERVICE_PROVIDER_ID,
585
- documentType: DOCUMENT_TYPE,
586
- content: CONTENT,
587
- mimeType: MIME_TYPE,
588
- fetchDate: FETCH_DATE_EARLIER,
589
- }));
1199
+ commit.id = sha;
1200
+ expectedIds.push(sha);
1201
+ expectedDates.push(date);
1202
+ }
1203
+ /* eslint-enable no-await-in-loop */
1204
+ });
590
1205
 
591
- ({ id: lastSnapshotId } = await subject.save(new Record({
592
- serviceId: SERVICE_PROVIDER_ID,
593
- documentType: DOCUMENT_TYPE,
594
- content: UPDATED_FILE_CONTENT,
595
- mimeType: MIME_TYPE,
596
- fetchDate: FETCH_DATE,
597
- })));
1206
+ after(async () => subject.removeAll());
1207
+
1208
+ describe('Records attributes', () => {
1209
+ describe('#isExtractOnly', () => {
1210
+ context('records with deprecated message', () => {
1211
+ it('returns the proper value', async () => {
1212
+ expect((await subject.findById(commits.deprecatedRefilter.id)).isExtractOnly).to.be.true;
1213
+ });
598
1214
 
599
- latestRecord = await subject.findLatest(SERVICE_PROVIDER_ID, DOCUMENT_TYPE);
1215
+ it('returns the proper value', async () => {
1216
+ expect((await subject.findById(commits.deprecatedFirstRecord.id)).isExtractOnly).to.be.false;
1217
+ });
600
1218
  });
601
1219
 
602
- after(async () => subject.removeAll());
1220
+ context('record with current message', () => {
1221
+ it('returns the proper value', async () => {
1222
+ expect((await subject.findById(commits.currentExtractOnly.id)).isExtractOnly).to.be.true;
1223
+ });
603
1224
 
604
- it('returns the latest record id', () => {
605
- expect(latestRecord.id).to.include(lastSnapshotId);
1225
+ it('returns the proper value', async () => {
1226
+ expect((await subject.findById(commits.currentFirstRecord.id)).isExtractOnly).to.be.false;
1227
+ });
606
1228
  });
1229
+ });
607
1230
 
608
- it('returns the latest record content', async () => {
609
- expect(latestRecord.content.toString('utf8')).to.equal(UPDATED_FILE_CONTENT);
1231
+ describe('#isFirstRecord', () => {
1232
+ context('records with deprecated message', () => {
1233
+ it('returns the proper value', async () => {
1234
+ expect((await subject.findById(commits.deprecatedFirstRecord.id)).isFirstRecord).to.be.true;
1235
+ });
1236
+
1237
+ it('returns the proper value', async () => {
1238
+ expect((await subject.findById(commits.deprecatedRefilter.id)).isFirstRecord).to.be.false;
1239
+ });
610
1240
  });
611
1241
 
612
- it('returns the latest record mime type', () => {
613
- expect(latestRecord.mimeType).to.equal(MIME_TYPE);
1242
+ context('record with current message', () => {
1243
+ it('returns the proper value', async () => {
1244
+ expect((await subject.findById(commits.currentFirstRecord.id)).isFirstRecord).to.be.true;
1245
+ });
1246
+
1247
+ it('returns the proper value', async () => {
1248
+ expect((await subject.findById(commits.currentExtractOnly.id)).isFirstRecord).to.be.false;
1249
+ });
614
1250
  });
615
1251
  });
1252
+ });
616
1253
 
617
- context('with PDF document', () => {
618
- before(async () => {
619
- ({ id: lastSnapshotId } = await subject.save(new Record({
620
- serviceId: SERVICE_PROVIDER_ID,
621
- documentType: DOCUMENT_TYPE,
622
- content: PDF_CONTENT,
623
- mimeType: PDF_MIME_TYPE,
624
- fetchDate: FETCH_DATE,
625
- })));
1254
+ describe('#findAll', () => {
1255
+ let records;
626
1256
 
627
- latestRecord = await subject.findLatest(SERVICE_PROVIDER_ID, DOCUMENT_TYPE);
628
- });
1257
+ before(async function () {
1258
+ this.timeout(5000);
629
1259
 
630
- after(async () => subject.removeAll());
1260
+ (records = await subject.findAll());
1261
+ });
631
1262
 
632
- it('returns the latest record id', () => {
633
- expect(latestRecord.id).to.include(lastSnapshotId);
634
- });
1263
+ it('returns all records', () => {
1264
+ expect(records.map(record => record.id)).to.have.members(expectedIds);
1265
+ });
635
1266
 
636
- it('returns the latest record content', async () => {
637
- expect(latestRecord.content.toString('utf8')).to.equal(PDF_CONTENT);
638
- });
1267
+ it('returns Version objects', () => {
1268
+ for (const record of records) {
1269
+ expect(record).to.be.an.instanceof(Version);
1270
+ }
1271
+ });
639
1272
 
640
- it('returns the latest record mime type', () => {
641
- expect(latestRecord.mimeType).to.equal(PDF_MIME_TYPE);
642
- });
1273
+ it('returns records in ascending order', async () => {
1274
+ expect(records.map(record => record.fetchDate)).to.deep.equal(expectedDates);
643
1275
  });
644
1276
  });
645
1277
 
646
- context('when there are no records for the given service', () => {
647
- let latestRecord;
1278
+ describe('#count', () => {
1279
+ let count;
648
1280
 
649
1281
  before(async () => {
650
- latestRecord = await subject.findLatest(SERVICE_PROVIDER_ID, DOCUMENT_TYPE);
1282
+ (count = await subject.count());
651
1283
  });
652
1284
 
653
- it('returns null', async () => {
654
- expect(latestRecord).to.equal(null);
1285
+ it('returns the proper count', async () => {
1286
+ expect(count).to.equal(expectedIds.length);
655
1287
  });
656
1288
  });
657
- });
658
1289
 
659
- describe('#iterate', () => {
660
- const expectedIds = [];
661
- const ids = [];
662
- const fetchDates = [];
663
-
664
- before(async () => {
665
- const { id: id1 } = await subject.save(new Record({
666
- serviceId: SERVICE_PROVIDER_ID,
667
- documentType: DOCUMENT_TYPE,
668
- content: CONTENT,
669
- fetchDate: FETCH_DATE,
670
- snapshotIds: [SNAPSHOT_ID],
671
- mimeType: MIME_TYPE,
672
- }));
673
-
674
- expectedIds.push(id1);
675
-
676
- const { id: id2 } = await subject.save(new Record({
677
- serviceId: SERVICE_PROVIDER_ID,
678
- documentType: DOCUMENT_TYPE,
679
- content: `${CONTENT} - updated`,
680
- fetchDate: FETCH_DATE_LATER,
681
- snapshotIds: [SNAPSHOT_ID],
682
- mimeType: MIME_TYPE,
683
- }));
684
-
685
- expectedIds.push(id2);
686
-
687
- const { id: id3 } = await subject.save(new Record({
688
- serviceId: SERVICE_PROVIDER_ID,
689
- documentType: DOCUMENT_TYPE,
690
- content: `${CONTENT} - updated 2`,
691
- isRefilter: true,
692
- fetchDate: FETCH_DATE_EARLIER,
693
- snapshotIds: [SNAPSHOT_ID],
694
- mimeType: MIME_TYPE,
695
- }));
696
-
697
- expectedIds.push(id3);
698
-
699
- for await (const record of subject.iterate()) {
700
- ids.push(record.id);
701
- fetchDates.push(record.fetchDate);
702
- }
703
- });
1290
+ describe('#iterate', () => {
1291
+ const ids = [];
1292
+ const fetchDates = [];
704
1293
 
705
- after(async () => subject.removeAll());
1294
+ before(async () => {
1295
+ for await (const record of subject.iterate()) {
1296
+ ids.push(record.id);
1297
+ fetchDates.push(record.fetchDate);
1298
+ }
1299
+ });
706
1300
 
707
- it('iterates through all records', async () => {
708
- expect(ids).to.have.members(expectedIds);
709
- });
1301
+ it('iterates through all records', async () => {
1302
+ expect(ids).to.have.members(expectedIds);
1303
+ });
710
1304
 
711
- it('iterates in ascending order', async () => {
712
- expect(fetchDates).to.deep.equal([ FETCH_DATE_EARLIER, FETCH_DATE, FETCH_DATE_LATER ]);
1305
+ it('iterates in ascending order', async () => {
1306
+ expect(fetchDates).to.deep.equal(expectedDates);
1307
+ });
713
1308
  });
714
1309
  });
715
1310
  });