google-drive-mock 1.1.6 → 1.2.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.
- package/AGENTS.md +4 -1
- package/CLAUDE.md +17 -0
- package/dist/index.js +2 -1
- package/dist/mappers.d.ts +5 -0
- package/dist/mappers.js +15 -0
- package/dist/routes/v2.js +16 -8
- package/dist/routes/v3.js +30 -9
- package/dist/store.js +2 -2
- package/package.json +4 -4
- package/scripts/check-token.ts +107 -38
- package/scripts/run-loop.sh +18 -0
- package/src/index.ts +2 -1
- package/src/mappers.ts +15 -0
- package/src/routes/v2.ts +16 -8
- package/src/routes/v3.ts +35 -10
- package/src/store.ts +2 -2
- package/test/advanced_changes.test.ts +76 -29
- package/test/advanced_ordering.test.ts +2 -1
- package/test/basics.test.ts +34 -58
- package/test/batch_and_query.test.ts +28 -62
- package/test/batch_insert_download.test.ts +2 -1
- package/test/check_empty.test.ts +60 -0
- package/test/complex_query.test.ts +2 -1
- package/test/concurrent_fetch.test.ts +2 -1
- package/test/config.ts +164 -7
- package/test/dates_and_sorting.test.ts +2 -1
- package/test/etag.test.ts +8 -4
- package/test/features.test.ts +2 -1
- package/test/folder_query.test.ts +2 -1
- package/test/folder_search.test.ts +2 -1
- package/test/iterate_changes.test.ts +153 -68
- package/test/latency.test.ts +2 -1
- package/test/mime_types.test.ts +2 -1
- package/test/missing_fields.test.ts +2 -1
- package/test/multipart_behavior.test.ts +2 -1
- package/test/parallel_update.test.ts +2 -1
- package/test/parity_media_download.test.ts +2 -1
- package/test/routines.test.ts +15 -12
- package/test/upload.test.ts +2 -1
- package/test/url_parameters.test.ts +2 -1
- package/test/v2_basics.test.ts +22 -13
- package/test/v2_content.test.ts +2 -1
- package/test/v2_missing_ops.test.ts +75 -75
- package/test/v2_routes.test.ts +31 -21
- package/test/v2_upload.test.ts +17 -9
- package/test/v3_parity.test.ts +56 -20
- package/test_etag_headers.ts +92 -0
- package/vitest.config.ts +7 -1
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { describe, expect, beforeAll } from 'vitest';
|
|
3
|
+
import { it } from './config';;
|
|
2
4
|
import {
|
|
3
5
|
getTestConfig,
|
|
4
6
|
TestConfig
|
|
@@ -78,51 +80,65 @@ describe('Iterate Changes Queries', () => {
|
|
|
78
80
|
// Use file1's modifiedTime as the baseline (X)
|
|
79
81
|
const timeX = file1.modifiedTime;
|
|
80
82
|
|
|
81
|
-
// Query: modifiedTime > X, orderBy modifiedTime asc, name asc
|
|
82
|
-
// User asked for: Sorted by write data and id. with limit
|
|
83
|
+
// Query: modifiedTime > X, orderBy modifiedTime asc, name asc
|
|
83
84
|
const q = `modifiedTime > '${timeX}' and '${parentId}' in parents and trashed = false`;
|
|
84
85
|
const orderBy = 'modifiedTime asc, name asc';
|
|
85
|
-
|
|
86
|
+
|
|
87
|
+
// Poll until the search index is fully updated and returns both expected files
|
|
88
|
+
let data2: any;
|
|
89
|
+
const url2 = `${config.baseUrl}/drive/v3/files?q=${encodeURIComponent(q)}&orderBy=${encodeURIComponent(orderBy)}&pageSize=2`;
|
|
90
|
+
for (let attempt = 1; attempt <= 15; attempt++) {
|
|
91
|
+
const res2 = await fetch(url2, { headers });
|
|
92
|
+
expect(res2.status).toBe(200);
|
|
93
|
+
data2 = await res2.json();
|
|
94
|
+
const ids = (data2.files || []).map((f: any) => f.id);
|
|
95
|
+
if (ids.includes(file2.id) && ids.includes(file3.id)) {
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
expect(data2.files.length).toBe(2);
|
|
102
|
+
expect(data2.files[0].id).toBe(file2.id);
|
|
103
|
+
expect(data2.files[1].id).toBe(file3.id);
|
|
86
104
|
|
|
87
105
|
// First page
|
|
106
|
+
const pageSize = 1;
|
|
88
107
|
const url1 = `${config.baseUrl}/drive/v3/files?q=${encodeURIComponent(q)}&orderBy=${encodeURIComponent(orderBy)}&pageSize=${pageSize}`;
|
|
89
108
|
const res1 = await fetch(url1, { headers });
|
|
90
|
-
if (res1.status !== 200) {
|
|
91
|
-
const txt = await res1.text();
|
|
92
|
-
console.error('Error 1:', txt);
|
|
93
|
-
}
|
|
94
109
|
expect(res1.status).toBe(200);
|
|
95
110
|
const data1 = await res1.json();
|
|
96
111
|
|
|
97
112
|
expect(data1.files.length).toBe(1);
|
|
98
113
|
expect(data1.files[0].id).toBe(file2.id);
|
|
99
|
-
|
|
100
|
-
// If we want to simulate iteration, we would use nextPageToken or just offset logic if we supported it,
|
|
101
|
-
// but here we just test that the query works and LIMIT works.
|
|
102
|
-
|
|
103
|
-
// Verify we can get the next one if we increase limit
|
|
104
|
-
const url2 = `${config.baseUrl}/drive/v3/files?q=${encodeURIComponent(q)}&orderBy=${encodeURIComponent(orderBy)}&pageSize=2`;
|
|
105
|
-
const res2 = await fetch(url2, { headers });
|
|
106
|
-
const data2 = await res2.json();
|
|
107
|
-
expect(data2.files.length).toBe(2);
|
|
108
|
-
expect(data2.files[0].id).toBe(file2.id);
|
|
109
|
-
expect(data2.files[1].id).toBe(file3.id);
|
|
110
114
|
}, 60000);
|
|
111
115
|
|
|
112
116
|
it('should find all files where write time was equal to X, sorted by name, with limit', async () => {
|
|
117
|
+
// Create a parent folder
|
|
118
|
+
const parentRes = await fetch(`${config.baseUrl}/drive/v3/files`, {
|
|
119
|
+
method: 'POST',
|
|
120
|
+
headers: { ...headers, 'Content-Type': 'application/json' },
|
|
121
|
+
body: JSON.stringify({
|
|
122
|
+
name: 'ParentFolder_EqualTime_' + randomString(),
|
|
123
|
+
mimeType: 'application/vnd.google-apps.folder'
|
|
124
|
+
})
|
|
125
|
+
});
|
|
126
|
+
expect(parentRes.status).toBe(200);
|
|
127
|
+
const parentId = (await parentRes.json()).id;
|
|
128
|
+
|
|
113
129
|
// Create 3 files effectively at the "same" time.
|
|
114
130
|
// To do this reliably on Real API, we create one, get its time, and then PATCH the others to have that same time (if possible).
|
|
115
131
|
// However, Drive API might not allow arbitrary modifiedTime patching easily without setModifiedDate=true param or similar.
|
|
116
132
|
// Actually, V3 supports modifying modifiedTime.
|
|
117
133
|
|
|
118
|
-
const file1 = await createFileWithContent('file_B_middle', randomString(), config);
|
|
134
|
+
const file1 = await createFileWithContent('file_B_middle', randomString(), config, parentId);
|
|
119
135
|
// Get the time from file1 to use as target
|
|
120
136
|
const timeXRes = await fetch(`${config.baseUrl}/drive/v3/files/${file1.id}?fields=modifiedTime`, { headers });
|
|
121
137
|
const timeX = (await timeXRes.json()).modifiedTime;
|
|
122
138
|
|
|
123
139
|
// Create two more files
|
|
124
|
-
const file2 = await createFileWithContent('file_A_first', randomString(), config);
|
|
125
|
-
const file3 = await createFileWithContent('file_C_last', randomString(), config);
|
|
140
|
+
const file2 = await createFileWithContent('file_A_first', randomString(), config, parentId);
|
|
141
|
+
const file3 = await createFileWithContent('file_C_last', randomString(), config, parentId);
|
|
126
142
|
|
|
127
143
|
// Patch file2 and file3 to have the SAME modifiedTime as file1
|
|
128
144
|
// We need to wait a bit to ensure they would naturally have different times if we didn't patch,
|
|
@@ -133,16 +149,24 @@ describe('Iterate Changes Queries', () => {
|
|
|
133
149
|
await fetch(`${config.baseUrl}/drive/v3/files/${file2.id}`, { method: 'PATCH', headers: { ...headers, 'Content-Type': 'application/json' }, body: patchBody });
|
|
134
150
|
await fetch(`${config.baseUrl}/drive/v3/files/${file3.id}`, { method: 'PATCH', headers: { ...headers, 'Content-Type': 'application/json' }, body: patchBody });
|
|
135
151
|
|
|
136
|
-
const q = `modifiedTime = '${timeX}' and trashed = false`;
|
|
152
|
+
const q = `modifiedTime = '${timeX}' and '${parentId}' in parents and trashed = false`;
|
|
137
153
|
const orderBy = 'name asc';
|
|
138
154
|
const pageSize = 10;
|
|
139
155
|
|
|
156
|
+
let data: any;
|
|
140
157
|
const url = `${config.baseUrl}/drive/v3/files?q=${encodeURIComponent(q)}&orderBy=${encodeURIComponent(orderBy)}&pageSize=${pageSize}&fields=files(id,name,modifiedTime)`;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
158
|
+
|
|
159
|
+
for (let attempt = 1; attempt <= 15; attempt++) {
|
|
160
|
+
const res = await fetch(url, { headers });
|
|
161
|
+
expect(res.status).toBe(200);
|
|
162
|
+
data = await res.json();
|
|
163
|
+
const relevantFiles = (data.files || []).filter((f: DriveFile) => [file1.id, file2.id, file3.id].includes(f.id));
|
|
164
|
+
if (relevantFiles.length === 3) {
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
168
|
+
}
|
|
144
169
|
|
|
145
|
-
// Should find all 3 files
|
|
146
170
|
const relevantFiles = data.files.filter((f: DriveFile) => [file1.id, file2.id, file3.id].includes(f.id));
|
|
147
171
|
expect(relevantFiles.length).toBe(3);
|
|
148
172
|
|
|
@@ -206,10 +230,19 @@ describe('Iterate Changes Queries', () => {
|
|
|
206
230
|
const q = `modifiedTime = '${timeX}' and '${parentId}' in parents and trashed = false`;
|
|
207
231
|
const orderBy = 'name asc';
|
|
208
232
|
|
|
233
|
+
let data: any;
|
|
209
234
|
const url = `${config.baseUrl}/drive/v3/files?q=${encodeURIComponent(q)}&orderBy=${encodeURIComponent(orderBy)}&fields=files(id,name,modifiedTime,parents)`;
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
235
|
+
|
|
236
|
+
for (let attempt = 1; attempt <= 15; attempt++) {
|
|
237
|
+
const res = await fetch(url, { headers });
|
|
238
|
+
expect(res.status).toBe(200);
|
|
239
|
+
data = await res.json();
|
|
240
|
+
const ids = (data.files || []).map((f: DriveFile) => f.id);
|
|
241
|
+
if (ids.includes(file1.id) && ids.includes(file2.id) && ids.includes(file3.id)) {
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
245
|
+
}
|
|
213
246
|
|
|
214
247
|
// 4. Verify results
|
|
215
248
|
// Should find file1, file2, file3
|
|
@@ -229,21 +262,33 @@ describe('Iterate Changes Queries', () => {
|
|
|
229
262
|
}, 60000);
|
|
230
263
|
|
|
231
264
|
it('should find files where write time >= X, sorted by modifiedTime and name', async () => {
|
|
265
|
+
// Create a parent folder
|
|
266
|
+
const parentRes = await fetch(`${config.baseUrl}/drive/v3/files`, {
|
|
267
|
+
method: 'POST',
|
|
268
|
+
headers: { ...headers, 'Content-Type': 'application/json' },
|
|
269
|
+
body: JSON.stringify({
|
|
270
|
+
name: 'ParentFolder_GreaterOrEqual_' + randomString(),
|
|
271
|
+
mimeType: 'application/vnd.google-apps.folder'
|
|
272
|
+
})
|
|
273
|
+
});
|
|
274
|
+
expect(parentRes.status).toBe(200);
|
|
275
|
+
const parentId = (await parentRes.json()).id;
|
|
276
|
+
|
|
232
277
|
// 1. Create file OLD (should be excluded)
|
|
233
|
-
const fileOld = await createFileWithContent('file_A_Old', randomString(), config);
|
|
278
|
+
const fileOld = await createFileWithContent('file_A_Old', randomString(), config, parentId);
|
|
234
279
|
|
|
235
280
|
// Wait to ensure distinct time
|
|
236
281
|
await new Promise(r => setTimeout(r, 1500));
|
|
237
282
|
|
|
238
283
|
// 2. Create ISO-time target files (Equal Time)
|
|
239
284
|
// We create one, get its time, then create another and patch it to match.
|
|
240
|
-
const fileMiddle1 = await createFileWithContent('file_B_Middle1', randomString(), config);
|
|
285
|
+
const fileMiddle1 = await createFileWithContent('file_B_Middle1', randomString(), config, parentId);
|
|
241
286
|
// Get target time
|
|
242
287
|
const timeXRes = await fetch(`${config.baseUrl}/drive/v3/files/${fileMiddle1.id}?fields=modifiedTime`, { headers });
|
|
243
288
|
const timeX = (await timeXRes.json()).modifiedTime;
|
|
244
289
|
|
|
245
290
|
// Create second middle file
|
|
246
|
-
const fileMiddle2 = await createFileWithContent('file_B_Middle2', randomString(), config);
|
|
291
|
+
const fileMiddle2 = await createFileWithContent('file_B_Middle2', randomString(), config, parentId);
|
|
247
292
|
|
|
248
293
|
// Patch fileMiddle2 to match fileMiddle1 time
|
|
249
294
|
await new Promise(r => setTimeout(r, 1100)); // Wait before patching to ensure it would be different otherwise
|
|
@@ -254,20 +299,26 @@ describe('Iterate Changes Queries', () => {
|
|
|
254
299
|
await new Promise(r => setTimeout(r, 1500));
|
|
255
300
|
|
|
256
301
|
// 3. Create file New (should be included, greater match logic)
|
|
257
|
-
const fileNew = await createFileWithContent('file_C_New', randomString(), config);
|
|
302
|
+
const fileNew = await createFileWithContent('file_C_New', randomString(), config, parentId);
|
|
258
303
|
|
|
259
304
|
// 4. Query: modifiedTime >= timeX
|
|
260
305
|
// Sort by modifiedTime asc, name asc
|
|
261
|
-
const q = `modifiedTime >= '${timeX}' and trashed = false`;
|
|
306
|
+
const q = `modifiedTime >= '${timeX}' and '${parentId}' in parents and trashed = false`;
|
|
262
307
|
const orderBy = 'modifiedTime asc, name asc';
|
|
263
308
|
|
|
309
|
+
let data: any;
|
|
264
310
|
const url = `${config.baseUrl}/drive/v3/files?q=${encodeURIComponent(q)}&orderBy=${encodeURIComponent(orderBy)}&fields=files(id,name,modifiedTime)`;
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
311
|
+
|
|
312
|
+
for (let attempt = 1; attempt <= 15; attempt++) {
|
|
313
|
+
const res = await fetch(url, { headers });
|
|
314
|
+
expect(res.status).toBe(200);
|
|
315
|
+
data = await res.json();
|
|
316
|
+
const relevantFiles = (data.files || []).filter((f: DriveFile) => [fileMiddle1.id, fileMiddle2.id, fileNew.id].includes(f.id));
|
|
317
|
+
if (relevantFiles.length === 3) {
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
268
321
|
}
|
|
269
|
-
expect(res.status).toBe(200);
|
|
270
|
-
const data = await res.json();
|
|
271
322
|
|
|
272
323
|
// 5. Verify results
|
|
273
324
|
const resultIds = data.files.map((f: DriveFile) => f.id);
|
|
@@ -576,10 +627,19 @@ describe('Iterate Changes Queries', () => {
|
|
|
576
627
|
const q = `modifiedTime > '${timeX}' and '${parentId}' in parents and trashed = false`;
|
|
577
628
|
const orderBy = 'modifiedTime asc, name asc';
|
|
578
629
|
|
|
630
|
+
let data: any;
|
|
579
631
|
const url = `${config.baseUrl}/drive/v3/files?q=${encodeURIComponent(q)}&orderBy=${encodeURIComponent(orderBy)}&fields=files(id,name,parents,modifiedTime)`;
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
632
|
+
|
|
633
|
+
for (let attempt = 1; attempt <= 15; attempt++) {
|
|
634
|
+
const res = await fetch(url, { headers });
|
|
635
|
+
expect(res.status).toBe(200);
|
|
636
|
+
data = await res.json();
|
|
637
|
+
const matchingFiles = (data.files || []).filter((f: DriveFile) => f.id === file2.id);
|
|
638
|
+
if (matchingFiles.length === 1) {
|
|
639
|
+
break;
|
|
640
|
+
}
|
|
641
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
642
|
+
}
|
|
583
643
|
|
|
584
644
|
const matchingFiles = data.files.filter((f: DriveFile) => f.id === file2.id);
|
|
585
645
|
const nonMatchingFile1 = data.files.filter((f: DriveFile) => f.id === file1.id);
|
|
@@ -598,22 +658,39 @@ describe('Iterate Changes Queries', () => {
|
|
|
598
658
|
}, 60000);
|
|
599
659
|
|
|
600
660
|
it('should paginate through files using nextPageToken', async () => {
|
|
661
|
+
// Create a parent folder
|
|
662
|
+
const parentRes = await fetch(`${config.baseUrl}/drive/v3/files`, {
|
|
663
|
+
method: 'POST',
|
|
664
|
+
headers: { ...headers, 'Content-Type': 'application/json' },
|
|
665
|
+
body: JSON.stringify({
|
|
666
|
+
name: 'ParentFolder_PaginationToken_' + randomString(),
|
|
667
|
+
mimeType: 'application/vnd.google-apps.folder'
|
|
668
|
+
})
|
|
669
|
+
});
|
|
670
|
+
expect(parentRes.status).toBe(200);
|
|
671
|
+
const parentId = (await parentRes.json()).id;
|
|
672
|
+
|
|
601
673
|
// Create files
|
|
602
674
|
const totalFiles = 6;
|
|
603
675
|
const baseName = 'PaginatedFile_' + randomString();
|
|
604
676
|
for (let i = 0; i < totalFiles; i++) {
|
|
605
|
-
await createFileWithContent(`${baseName}_${i}`, `content_${i}`, config);
|
|
677
|
+
await createFileWithContent(`${baseName}_${i}`, `content_${i}`, config, parentId);
|
|
606
678
|
// Small delay to ensure order if we sort by time, but we'll sort by name to be deterministic
|
|
607
679
|
}
|
|
608
680
|
|
|
609
|
-
const q = `name contains '${baseName}' and trashed = false`;
|
|
681
|
+
const q = `'${parentId}' in parents and name contains '${baseName}' and trashed = false`;
|
|
610
682
|
const orderBy = 'name asc';
|
|
611
683
|
const pageSize = 2;
|
|
612
684
|
const collectedFiles: DriveFile[] = [];
|
|
613
685
|
let pageToken: string | undefined;
|
|
686
|
+
let pageCount = 0;
|
|
614
687
|
|
|
615
688
|
// Iterate pages until no token
|
|
616
689
|
do {
|
|
690
|
+
pageCount++;
|
|
691
|
+
if (pageCount > 50) {
|
|
692
|
+
throw new Error('Too many pages retrieved (infinite loop safety limit)');
|
|
693
|
+
}
|
|
617
694
|
const url: string = `${config.baseUrl}/drive/v3/files?q=${encodeURIComponent(q)}&orderBy=${encodeURIComponent(orderBy)}&pageSize=${pageSize}` + (pageToken ? `&pageToken=${pageToken}` : '');
|
|
618
695
|
const res = await fetch(url, { headers });
|
|
619
696
|
|
|
@@ -795,17 +872,23 @@ describe('Iterate Changes Queries', () => {
|
|
|
795
872
|
}
|
|
796
873
|
}
|
|
797
874
|
|
|
798
|
-
// Wait for
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
875
|
+
// Wait for indexing with retries
|
|
876
|
+
let refTime: string | undefined;
|
|
877
|
+
console.log('Waiting for indexing...');
|
|
878
|
+
for (let attempt = 0; attempt < 15; attempt++) {
|
|
879
|
+
const listOne = await fetch(`${config.baseUrl}/drive/v3/files?q='${parentId}' in parents&pageSize=${totalFiles}&fields=files(modifiedTime)`, { headers });
|
|
880
|
+
if (listOne.status === 200) {
|
|
881
|
+
const oneData = await listOne.json();
|
|
882
|
+
if (oneData.files && oneData.files.length === totalFiles) {
|
|
883
|
+
refTime = oneData.files[0].modifiedTime;
|
|
884
|
+
break;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
888
|
+
}
|
|
889
|
+
if (!refTime) {
|
|
890
|
+
throw new Error('All files not indexed in parent check!');
|
|
807
891
|
}
|
|
808
|
-
const refTime = oneData.files[0].modifiedTime;
|
|
809
892
|
console.log('Reference File Time:', refTime);
|
|
810
893
|
|
|
811
894
|
// Filter: modifiedTime > refTime - 1 hour (to safely include all)
|
|
@@ -877,21 +960,23 @@ describe('Iterate Changes Queries', () => {
|
|
|
877
960
|
expect(res.status).toBe(200);
|
|
878
961
|
}
|
|
879
962
|
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
963
|
+
// Wait for indexing with retries (v2)
|
|
964
|
+
let refTime: string | undefined;
|
|
965
|
+
console.log('Waiting for indexing (v2)...');
|
|
966
|
+
for (let attempt = 0; attempt < 15; attempt++) {
|
|
967
|
+
const listOne = await fetch(`${config.baseUrl}/drive/v2/files?q='${parentId}' in parents&maxResults=${totalFiles}`, { headers });
|
|
968
|
+
if (listOne.status === 200) {
|
|
969
|
+
const oneData = await listOne.json();
|
|
970
|
+
if (oneData.items && oneData.items.length === totalFiles) {
|
|
971
|
+
refTime = oneData.items[0].modifiedDate;
|
|
972
|
+
break;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
888
976
|
}
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
if (!oneData.items || oneData.items.length === 0) {
|
|
892
|
-
throw new Error('No files found in parent check v2!');
|
|
977
|
+
if (!refTime) {
|
|
978
|
+
throw new Error('All files not indexed in parent check v2!');
|
|
893
979
|
}
|
|
894
|
-
const refTime = oneData.items[0].modifiedDate;
|
|
895
980
|
console.log('Reference File Time v2:', refTime);
|
|
896
981
|
|
|
897
982
|
// Filter: modifiedDate > refTime - 1 hour
|
package/test/latency.test.ts
CHANGED
package/test/mime_types.test.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { describe,
|
|
1
|
+
import { describe, expect, beforeAll, afterAll } from 'vitest';
|
|
2
|
+
import { it } from './config';;
|
|
2
3
|
import { getTestConfig, TestConfig } from './config';
|
|
3
4
|
|
|
4
5
|
describe('Missing Fields Support (Size & MD5)', () => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
import { describe,
|
|
2
|
+
import { describe, expect, beforeAll, afterAll } from 'vitest';
|
|
3
|
+
import { it } from './config';;
|
|
3
4
|
import { getTestConfig, TestConfig } from './config';
|
|
4
5
|
|
|
5
6
|
describe('Multipart Upload Behavior (Conflicts, Overwrites, Replacements)', () => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
import { describe,
|
|
2
|
+
import { describe, expect, beforeAll, afterAll } from 'vitest';
|
|
3
|
+
import { it } from './config';;
|
|
3
4
|
import { getTestConfig, TestConfig } from './config';
|
|
4
5
|
|
|
5
6
|
describe('Parallel Content Update Test', () => {
|
package/test/routines.test.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { describe,
|
|
2
|
+
import { describe, expect, afterAll, beforeAll, vi } from 'vitest';
|
|
3
|
+
import { it } from './config';;
|
|
3
4
|
import { waitUntil } from 'async-test-util';
|
|
4
5
|
import { getTestConfig, TestConfig } from './config';
|
|
5
6
|
|
|
@@ -68,8 +69,9 @@ describe('Complex Routines', () => {
|
|
|
68
69
|
|
|
69
70
|
it('Lifecycle: Create -> Update -> Read -> Delete', async () => {
|
|
70
71
|
// 1. Create
|
|
72
|
+
const title = 'Lifecycle File ' + Math.random().toString(36).substring(7);
|
|
71
73
|
const newFile = {
|
|
72
|
-
name:
|
|
74
|
+
name: title,
|
|
73
75
|
mimeType: 'text/plain',
|
|
74
76
|
parents: [config.testFolderId]
|
|
75
77
|
};
|
|
@@ -78,14 +80,15 @@ describe('Complex Routines', () => {
|
|
|
78
80
|
const fileId = createRes.body.id;
|
|
79
81
|
|
|
80
82
|
// 2. Update
|
|
81
|
-
const
|
|
83
|
+
const updatedTitle = 'Lifecycle Updated ' + Math.random().toString(36).substring(7);
|
|
84
|
+
const updateRes = await req('PATCH', `/drive/v3/files/${fileId}`, { name: updatedTitle });
|
|
82
85
|
expect(updateRes.status).toBe(200);
|
|
83
|
-
expect(updateRes.body.name).toBe(
|
|
86
|
+
expect(updateRes.body.name).toBe(updatedTitle);
|
|
84
87
|
|
|
85
88
|
// 3. Read
|
|
86
89
|
const readRes = await req('GET', `/drive/v3/files/${fileId}`);
|
|
87
90
|
expect(readRes.status).toBe(200);
|
|
88
|
-
expect(readRes.body.name).toBe(
|
|
91
|
+
expect(readRes.body.name).toBe(updatedTitle);
|
|
89
92
|
|
|
90
93
|
// 4. Delete
|
|
91
94
|
const deleteRes = await req('DELETE', `/drive/v3/files/${fileId}`);
|
|
@@ -97,7 +100,7 @@ describe('Complex Routines', () => {
|
|
|
97
100
|
});
|
|
98
101
|
|
|
99
102
|
it('Transaction Simulation: Lock -> Wait -> Release', async () => {
|
|
100
|
-
const LOCK_FILE = 'transactions-lock-' +
|
|
103
|
+
const LOCK_FILE = 'transactions-lock-' + Math.random().toString(36).substring(7) + '.txt';
|
|
101
104
|
|
|
102
105
|
// Client A: Acquire Lock
|
|
103
106
|
const createLock = await req('POST', '/drive/v3/files', {
|
|
@@ -113,7 +116,7 @@ describe('Complex Routines', () => {
|
|
|
113
116
|
await Promise.all([
|
|
114
117
|
// Client B
|
|
115
118
|
waitUntil(async () => {
|
|
116
|
-
const check = await req('GET',
|
|
119
|
+
const check = await req('GET', `/drive/v3/files?q=${encodeURIComponent(`name = '${LOCK_FILE}' and trashed = false`)}`, null);
|
|
117
120
|
// Actually to filter we can iterate body.files
|
|
118
121
|
|
|
119
122
|
const files = check.body.files || [];
|
|
@@ -166,11 +169,11 @@ describe('Complex Routines', () => {
|
|
|
166
169
|
});
|
|
167
170
|
|
|
168
171
|
it('Routine: Concurrent Create (Duplicates Allowed)', async () => {
|
|
169
|
-
const UNIQUE_FILE = 'unique.txt';
|
|
172
|
+
const UNIQUE_FILE = 'unique-' + Math.random().toString(36).substring(7) + '.txt';
|
|
170
173
|
|
|
171
174
|
// 1. Clean
|
|
172
|
-
const check1 = await req('GET',
|
|
173
|
-
const existingFiles = check1.body.files.filter((f: any) => f.name === UNIQUE_FILE);
|
|
175
|
+
const check1 = await req('GET', `/drive/v3/files?q=${encodeURIComponent(`name = '${UNIQUE_FILE}' and trashed = false`)}`);
|
|
176
|
+
const existingFiles = (check1.body.files || []).filter((f: any) => f.name === UNIQUE_FILE);
|
|
174
177
|
for (const file of existingFiles) {
|
|
175
178
|
await req('DELETE', `/drive/v3/files/${file.id}`);
|
|
176
179
|
}
|
|
@@ -196,8 +199,8 @@ describe('Complex Routines', () => {
|
|
|
196
199
|
expect(statuses).toEqual([200, 200]);
|
|
197
200
|
|
|
198
201
|
// Verify duplicates exist
|
|
199
|
-
const check3 = await req('GET',
|
|
200
|
-
const files = check3.body.files.filter((f: any) => f.name === UNIQUE_FILE);
|
|
202
|
+
const check3 = await req('GET', `/drive/v3/files?q=${encodeURIComponent(`name = '${UNIQUE_FILE}' and trashed = false`)}`);
|
|
203
|
+
const files = (check3.body.files || []).filter((f: any) => f.name === UNIQUE_FILE);
|
|
201
204
|
expect(files.length).toBe(2);
|
|
202
205
|
});
|
|
203
206
|
});
|
package/test/upload.test.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { describe,
|
|
1
|
+
import { describe, expect, beforeAll, afterAll } from 'vitest';
|
|
2
|
+
import { it } from './config';;
|
|
2
3
|
import { getTestConfig, TestConfig } from './config';
|
|
3
4
|
|
|
4
5
|
describe('Multipart Upload Feature', () => {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
|
|
2
|
-
import { describe,
|
|
2
|
+
import { describe, expect, beforeAll, afterAll } from 'vitest';
|
|
3
|
+
import { it } from './config';;
|
|
3
4
|
import { getTestConfig, TestConfig } from './config';
|
|
4
5
|
|
|
5
6
|
describe('URL Parameters Test', () => {
|
package/test/v2_basics.test.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { describe,
|
|
1
|
+
import { describe, expect, beforeAll, afterAll } from 'vitest';
|
|
2
|
+
import { it } from './config';;
|
|
2
3
|
import { getTestConfig, TestConfig } from './config';
|
|
3
4
|
import { Server } from 'http';
|
|
4
5
|
|
|
@@ -63,12 +64,13 @@ describe('Google Drive API V2 Basics', () => {
|
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
it('should create a file with V2 fields (title vs name)', async () => {
|
|
67
|
+
const title = 'V2 Created File ' + Math.random().toString(36).substring(7);
|
|
66
68
|
const createRes = await req('POST', '/drive/v2/files', {
|
|
67
|
-
title
|
|
69
|
+
title,
|
|
68
70
|
mimeType: 'text/plain'
|
|
69
71
|
});
|
|
70
72
|
expect(createRes.status).toBe(200);
|
|
71
|
-
expect(createRes.body.title).toBe(
|
|
73
|
+
expect(createRes.body.title).toBe(title);
|
|
72
74
|
expect(createRes.body.kind).toBe('drive#file');
|
|
73
75
|
expect(createRes.body.id).toBeTruthy();
|
|
74
76
|
|
|
@@ -77,38 +79,43 @@ describe('Google Drive API V2 Basics', () => {
|
|
|
77
79
|
// Verify with GET
|
|
78
80
|
const getRes = await req('GET', `/drive/v2/files/${fileId}`);
|
|
79
81
|
expect(getRes.status).toBe(200);
|
|
80
|
-
expect(getRes.body.title).toBe(
|
|
82
|
+
expect(getRes.body.title).toBe(title);
|
|
81
83
|
});
|
|
82
84
|
|
|
83
85
|
it('should update a file using PUT', async () => {
|
|
84
86
|
// Create
|
|
85
|
-
const
|
|
87
|
+
const title = 'To Update ' + Math.random().toString(36).substring(7);
|
|
88
|
+
const updatedTitle = 'Updated via PUT ' + Math.random().toString(36).substring(7);
|
|
89
|
+
const createRes = await req('POST', '/drive/v2/files', { title });
|
|
86
90
|
const fileId = createRes.body.id;
|
|
87
91
|
|
|
88
92
|
// Update
|
|
89
93
|
const updateRes = await req('PUT', `/drive/v2/files/${fileId}`, {
|
|
90
|
-
title:
|
|
94
|
+
title: updatedTitle
|
|
91
95
|
});
|
|
92
96
|
expect(updateRes.status).toBe(200);
|
|
93
|
-
expect(updateRes.body.title).toBe(
|
|
97
|
+
expect(updateRes.body.title).toBe(updatedTitle);
|
|
94
98
|
});
|
|
95
99
|
|
|
96
100
|
it('should patch a file using PATCH', async () => {
|
|
97
101
|
// Create
|
|
98
|
-
const
|
|
102
|
+
const title = 'To Patch ' + Math.random().toString(36).substring(7);
|
|
103
|
+
const patchedTitle = 'Patched Title ' + Math.random().toString(36).substring(7);
|
|
104
|
+
const createRes = await req('POST', '/drive/v2/files', { title });
|
|
99
105
|
const fileId = createRes.body.id;
|
|
100
106
|
|
|
101
107
|
// Patch
|
|
102
108
|
const patchRes = await req('PATCH', `/drive/v2/files/${fileId}`, {
|
|
103
|
-
title:
|
|
109
|
+
title: patchedTitle
|
|
104
110
|
});
|
|
105
111
|
expect(patchRes.status).toBe(200);
|
|
106
|
-
expect(patchRes.body.title).toBe(
|
|
112
|
+
expect(patchRes.body.title).toBe(patchedTitle);
|
|
107
113
|
});
|
|
108
114
|
|
|
109
115
|
it('should delete a file', async () => {
|
|
110
116
|
// Create
|
|
111
|
-
const
|
|
117
|
+
const title = 'To Delete ' + Math.random().toString(36).substring(7);
|
|
118
|
+
const createRes = await req('POST', '/drive/v2/files', { title });
|
|
112
119
|
const fileId = createRes.body.id;
|
|
113
120
|
|
|
114
121
|
// Delete
|
|
@@ -121,14 +128,16 @@ describe('Google Drive API V2 Basics', () => {
|
|
|
121
128
|
});
|
|
122
129
|
|
|
123
130
|
it('should handle V2 parent references correctly', async () => {
|
|
131
|
+
const parentTitle = 'V2 Parent Folder ' + Math.random().toString(36).substring(7);
|
|
132
|
+
const childTitle = 'V2 Child File ' + Math.random().toString(36).substring(7);
|
|
124
133
|
const parentRes = await req('POST', '/drive/v2/files', {
|
|
125
|
-
title:
|
|
134
|
+
title: parentTitle,
|
|
126
135
|
mimeType: 'application/vnd.google-apps.folder'
|
|
127
136
|
});
|
|
128
137
|
const parentId = parentRes.body.id;
|
|
129
138
|
|
|
130
139
|
const childRes = await req('POST', '/drive/v2/files', {
|
|
131
|
-
title:
|
|
140
|
+
title: childTitle,
|
|
132
141
|
parents: [{ id: parentId }]
|
|
133
142
|
});
|
|
134
143
|
|
package/test/v2_content.test.ts
CHANGED