google-drive-mock 1.0.8 → 1.0.9

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/dist/routes/v2.js CHANGED
@@ -391,6 +391,14 @@ const createV2Router = (config) => {
391
391
  res.status(404).json({ error: { code: 404, message: "File not found" } });
392
392
  return;
393
393
  }
394
+ const ifMatchHeader = req.headers['if-match'];
395
+ const ifMatch = Array.isArray(ifMatchHeader) ? ifMatchHeader[0] : ifMatchHeader;
396
+ if (ifMatch && ifMatch !== '*' && ifMatch !== existingFile.etag) {
397
+ if (ifMatch !== existingFile.etag && ifMatch !== `"${existingFile.etag}"`) {
398
+ res.status(412).json({ error: { code: 412, message: "Precondition Failed" } });
399
+ return;
400
+ }
401
+ }
394
402
  const uploadType = req.query.uploadType;
395
403
  if (uploadType === 'media') {
396
404
  const rawBody = req.body;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "google-drive-mock",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "Mock-Server that simulates being google-drive. Used for testing.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/src/routes/v2.ts CHANGED
@@ -454,6 +454,15 @@ export const createV2Router = (config: AppConfig) => {
454
454
  return;
455
455
  }
456
456
 
457
+ const ifMatchHeader = req.headers['if-match'];
458
+ const ifMatch = Array.isArray(ifMatchHeader) ? ifMatchHeader[0] : ifMatchHeader;
459
+ if (ifMatch && ifMatch !== '*' && ifMatch !== existingFile.etag) {
460
+ if (ifMatch !== existingFile.etag && ifMatch !== `"${existingFile.etag}"`) {
461
+ res.status(412).json({ error: { code: 412, message: "Precondition Failed" } });
462
+ return;
463
+ }
464
+ }
465
+
457
466
  const uploadType = req.query.uploadType as string;
458
467
 
459
468
  if (uploadType === 'media') {
@@ -139,4 +139,103 @@ describe('V2 Upload Features', () => {
139
139
  });
140
140
  expect(await contentRes.text()).toBe(newContent);
141
141
  });
142
+ it('should respect If-Match header in V2 media upload (PUT)', async () => {
143
+ // 1. Create file
144
+ const createRes = await fetch(`${config.baseUrl}/drive/v2/files`, {
145
+ method: 'POST',
146
+ headers: {
147
+ 'Authorization': `Bearer ${config.token}`,
148
+ 'Content-Type': 'application/json'
149
+ },
150
+ body: JSON.stringify({ title: 'ETag Media Test', mimeType: 'text/plain' })
151
+ });
152
+ const file = await createRes.json();
153
+ const fileId = file.id;
154
+ const etag = file.etag;
155
+
156
+ const invalidEtag = etag ? etag.replace(/.$/, '0') : '"wrong-etag"';
157
+
158
+ // 2. Update with WRONG ETag
159
+ const wrongEtagRes = await fetch(`${config.baseUrl}/upload/drive/v2/files/${fileId}?uploadType=media`, {
160
+ method: 'PUT',
161
+ headers: {
162
+ 'Authorization': `Bearer ${config.token}`,
163
+ 'Content-Type': 'text/plain',
164
+ 'If-Match': invalidEtag
165
+ },
166
+ body: 'Should Fail'
167
+ });
168
+ expect(wrongEtagRes.status).toBe(412);
169
+
170
+ // 3. Update with CORRECT ETag
171
+ const correctEtagRes = await fetch(`${config.baseUrl}/upload/drive/v2/files/${fileId}?uploadType=media`, {
172
+ method: 'PUT',
173
+ headers: {
174
+ 'Authorization': `Bearer ${config.token}`,
175
+ 'Content-Type': 'text/plain',
176
+ 'If-Match': etag
177
+ },
178
+ body: 'Updated with ETag'
179
+ });
180
+ expect(correctEtagRes.status).toBe(200);
181
+
182
+ // Verify Content
183
+ const contentRes = await fetch(`${config.baseUrl}/drive/v2/files/${fileId}?alt=media`, {
184
+ headers: { 'Authorization': `Bearer ${config.token}` }
185
+ });
186
+ expect(await contentRes.text()).toBe('Updated with ETag');
187
+ });
188
+
189
+ it('should respect If-Match header in V2 multipart upload (PUT)', async () => {
190
+ // 1. Create file
191
+ const createRes = await fetch(`${config.baseUrl}/drive/v2/files`, {
192
+ method: 'POST',
193
+ headers: {
194
+ 'Authorization': `Bearer ${config.token}`,
195
+ 'Content-Type': 'application/json'
196
+ },
197
+ body: JSON.stringify({ title: 'ETag Multipart Test', mimeType: 'text/plain' })
198
+ });
199
+ const file = await createRes.json();
200
+ const fileId = file.id;
201
+ const etag = file.etag;
202
+
203
+ const boundary = 'foo_bar_baz';
204
+ const delimiter = `\r\n--${boundary}\r\n`;
205
+ const closeDelim = `\r\n--${boundary}--`;
206
+ const body = delimiter +
207
+ 'Content-Type: application/json\r\n\r\n' +
208
+ JSON.stringify({ title: 'Updated Title' }) +
209
+ delimiter +
210
+ 'Content-Type: text/plain\r\n\r\n' +
211
+ 'Multipart Update' +
212
+ closeDelim;
213
+
214
+ const invalidEtag = etag ? etag.replace(/.$/, '0') : '"wrong-etag"';
215
+
216
+ // 2. Update with WRONG ETag
217
+ const wrongEtagRes = await fetch(`${config.baseUrl}/upload/drive/v2/files/${fileId}?uploadType=multipart`, {
218
+ method: 'PUT',
219
+ headers: {
220
+ 'Authorization': `Bearer ${config.token}`,
221
+ 'Content-Type': `multipart/related; boundary="${boundary}"`,
222
+ 'If-Match': invalidEtag
223
+ },
224
+ body: body
225
+ });
226
+ expect(wrongEtagRes.status).toBe(412);
227
+
228
+ // 3. Update with CORRECT ETag
229
+ const correctEtagRes = await fetch(`${config.baseUrl}/upload/drive/v2/files/${fileId}?uploadType=multipart`, {
230
+ method: 'PUT',
231
+ headers: {
232
+ 'Authorization': `Bearer ${config.token}`,
233
+ 'Content-Type': `multipart/related; boundary="${boundary}"`,
234
+ 'If-Match': etag
235
+ },
236
+ body: body
237
+ });
238
+ expect(correctEtagRes.status).toBe(200);
239
+ expect((await correctEtagRes.json()).title).toBe('Updated Title');
240
+ });
142
241
  });