Skip to content

Commit 9c751cf

Browse files
committed
gcpApis tests introduction
Issue: ARSN-524
1 parent 590aac4 commit 9c751cf

File tree

1 file changed

+304
-0
lines changed

1 file changed

+304
-0
lines changed
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
const assert = require('assert');
2+
const sinon = require('sinon');
3+
const { ListObjectsCommand, ListObjectVersionsCommand } = require('@aws-sdk/client-s3');
4+
5+
const { createMpuKey } = require('../../../../../lib/storage/data/external/GCP/GcpUtils');
6+
const MpuHelper = require('../../../../../lib/storage/data/external/GCP/GcpApis/mpuHelper');
7+
8+
const listParts = require('../../../../../lib/storage/data/external/GCP/GcpApis/listParts');
9+
const abortMultipartUpload = require('../../../../../lib/storage/data/external/GCP/GcpApis/abortMultipartUpload');
10+
const completeMultipartUpload = require('../../../../../lib/storage/data/external/GCP/GcpApis/completeMultipartUpload');
11+
12+
describe('GcpApis', () => {
13+
let sandbox;
14+
15+
beforeEach(() => {
16+
sandbox = sinon.createSandbox();
17+
});
18+
19+
afterEach(() => {
20+
sandbox.restore();
21+
});
22+
23+
describe('listParts', () => {
24+
it('should list parts', done => {
25+
const send = sandbox.stub().resolves({ Contents: [] });
26+
const service = { send };
27+
28+
const params = {
29+
Bucket: 'b',
30+
Key: 'obj',
31+
UploadId: 'upload',
32+
PartNumberMarker: 3,
33+
MaxParts: 10,
34+
};
35+
36+
listParts.call(service, params, (err, res) => {
37+
assert.ifError(err);
38+
assert(res);
39+
assert(send.calledOnce);
40+
const [command] = send.firstCall.args;
41+
assert(command instanceof ListObjectsCommand);
42+
assert.deepStrictEqual(command.input, {
43+
Bucket: params.Bucket,
44+
Prefix: createMpuKey(params.Key, params.UploadId, 'parts'),
45+
Marker: createMpuKey(params.Key, params.UploadId,
46+
params.PartNumberMarker, 'parts'),
47+
MaxKeys: params.MaxParts,
48+
});
49+
done();
50+
});
51+
});
52+
53+
it('should return error when listParts fails', done => {
54+
const listObjectsError = new Error('send(ListObjectsCommand) failed');
55+
const service = { send: sandbox.stub().rejects(listObjectsError) };
56+
57+
listParts.call(service, {
58+
Bucket: 'b',
59+
Key: 'obj',
60+
UploadId: 'upload',
61+
}, err => {
62+
assert.strictEqual(err, listObjectsError);
63+
done();
64+
});
65+
});
66+
});
67+
68+
describe('mpuHelper', () => {
69+
describe('removeParts', () => {
70+
it('should list versions and delete each version', done => {
71+
const service = {
72+
_maxConcurrent: 10,
73+
send: sandbox.stub()
74+
.onCall(0).callsFake(command => {
75+
assert(command instanceof ListObjectVersionsCommand);
76+
assert.deepStrictEqual(command.input, {
77+
Bucket: 'mpu-bucket',
78+
Prefix: 'pfx/',
79+
KeyMarker: undefined,
80+
VersionIdMarker: undefined,
81+
});
82+
return Promise.resolve({
83+
IsTruncated: true,
84+
NextKeyMarker: 'k2',
85+
NextVersionIdMarker: 'v2',
86+
Versions: [
87+
{ Key: 'a', VersionId: '1' },
88+
],
89+
});
90+
})
91+
.onCall(1).callsFake(command => {
92+
assert(command instanceof ListObjectVersionsCommand);
93+
assert.deepStrictEqual(command.input, {
94+
Bucket: 'mpu-bucket',
95+
Prefix: 'pfx/',
96+
KeyMarker: 'k2',
97+
VersionIdMarker: 'v2',
98+
});
99+
return Promise.resolve({
100+
IsTruncated: false,
101+
NextKeyMarker: undefined,
102+
NextVersionIdMarker: undefined,
103+
Versions: [
104+
{ Key: 'b', VersionId: '2' },
105+
{ Key: 'c', VersionId: '3' },
106+
],
107+
});
108+
}),
109+
deleteObject: sandbox.stub().callsFake((params, cb) => cb(null)),
110+
};
111+
112+
const helper = new MpuHelper(service);
113+
helper.removeParts({ MPU: 'mpu-bucket', Prefix: 'pfx/' }, err => {
114+
assert.ifError(err);
115+
assert(service.send.calledTwice);
116+
assert.strictEqual(service.deleteObject.callCount, 3);
117+
assert.deepStrictEqual(service.deleteObject.getCall(0).args[0], {
118+
Bucket: 'mpu-bucket',
119+
Key: 'a',
120+
VersionId: '1',
121+
});
122+
done();
123+
});
124+
});
125+
126+
it('should ignore NoSuchKey errors during delete', done => {
127+
const service = {
128+
_maxConcurrent: 10,
129+
send: sandbox.stub().resolves({
130+
IsTruncated: false,
131+
Versions: [
132+
{ Key: 'a', VersionId: '1' },
133+
{ Key: 'b', VersionId: '2' },
134+
],
135+
}),
136+
deleteObject: sandbox.stub().callsFake((params, cb) => {
137+
if (params.Key === 'a') {
138+
const err = new Error('gone');
139+
err.name = 'NoSuchKey';
140+
return cb(err);
141+
}
142+
return cb(null);
143+
}),
144+
};
145+
146+
const helper = new MpuHelper(service);
147+
helper.removeParts({ MPU: 'mpu-bucket', Prefix: 'pfx/' }, err => {
148+
assert.ifError(err);
149+
assert(service.send.calledOnce);
150+
assert.strictEqual(service.deleteObject.callCount, 2);
151+
done();
152+
});
153+
});
154+
155+
it('should return error when listVersions fails', done => {
156+
const listObjectVersionsError = new Error('send(ListObjectVersionsCommand) failed');
157+
const service = {
158+
_maxConcurrent: 10,
159+
send: sandbox.stub().callsFake(command => {
160+
assert(command instanceof ListObjectVersionsCommand);
161+
return Promise.reject(listObjectVersionsError);
162+
}),
163+
deleteObject: sandbox.stub(),
164+
};
165+
166+
const helper = new MpuHelper(service);
167+
helper.removeParts({ MPU: 'mpu-bucket', Prefix: 'pfx/' }, err => {
168+
assert.strictEqual(err, listObjectVersionsError);
169+
assert(service.deleteObject.notCalled);
170+
done();
171+
});
172+
});
173+
});
174+
});
175+
176+
describe('abortMultipartUpload', () => {
177+
it('should reject missing parameters', done => {
178+
abortMultipartUpload.call({}, { Bucket: 'b' }, err => {
179+
assert(err);
180+
assert(err.is.InvalidRequest);
181+
done();
182+
});
183+
});
184+
185+
it('should call removeParts with derived Prefix', done => {
186+
const removeStub = sandbox.stub(MpuHelper.prototype, 'removeParts')
187+
.callsFake((_delParams, cb) => cb(null));
188+
189+
const params = {
190+
Bucket: 'b',
191+
MPU: 'mpu-b',
192+
Key: 'obj',
193+
UploadId: 'upload',
194+
};
195+
196+
abortMultipartUpload.call({}, params, err => {
197+
assert.ifError(err);
198+
assert(removeStub.calledOnce);
199+
assert.deepStrictEqual(removeStub.firstCall.args[0], {
200+
Bucket: params.Bucket,
201+
MPU: params.MPU,
202+
Prefix: createMpuKey(params.Key, params.UploadId),
203+
});
204+
done();
205+
});
206+
});
207+
});
208+
209+
describe('completeMultipartUpload', () => {
210+
it('should reject missing parameters', done => {
211+
completeMultipartUpload.call({}, { Bucket: 'b' }, err => {
212+
assert(err);
213+
assert(err.is.InvalidRequest);
214+
done();
215+
});
216+
});
217+
218+
it('should reject empty parts list', done => {
219+
completeMultipartUpload.call({}, {
220+
Bucket: 'b',
221+
MPU: 'mpu-b',
222+
Key: 'obj',
223+
UploadId: 'upload',
224+
MultipartUpload: { Parts: [] },
225+
}, err => {
226+
assert(err);
227+
assert(err.is.InvalidRequest);
228+
done();
229+
});
230+
});
231+
232+
it('should reject invalid part order', done => {
233+
completeMultipartUpload.call({}, {
234+
Bucket: 'b',
235+
MPU: 'mpu-b',
236+
Key: 'obj',
237+
UploadId: 'upload',
238+
MultipartUpload: {
239+
Parts: [
240+
{ PartNumber: 2 },
241+
{ PartNumber: 1 },
242+
],
243+
},
244+
}, err => {
245+
assert(err);
246+
assert.strictEqual(err.message, 'InvalidPartOrder');
247+
done();
248+
});
249+
});
250+
251+
it('should run MPU flow and remove parts', done => {
252+
sandbox.stub(console, 'log').callsFake(() => undefined);
253+
254+
const splitMergeStub = sandbox.stub(MpuHelper.prototype, 'splitMerge')
255+
.callsFake((params, partList, level, cb) => cb(null, 2));
256+
const composeFinalStub = sandbox.stub(MpuHelper.prototype, 'composeFinal')
257+
.callsFake((numParts, params, cb) => cb(null, 'finalKey'));
258+
const generateStub = sandbox.stub(MpuHelper.prototype, 'generateMpuResult')
259+
.callsFake((result, partList, cb) => cb(null, result, 'aggEtag'));
260+
const copyStub = sandbox.stub(MpuHelper.prototype, 'copyToMain')
261+
.callsFake((result, aggregateETag, params, cb) => cb(null, {
262+
Bucket: params.Bucket,
263+
Key: params.Key,
264+
VersionId: 'v1',
265+
ETag: '"aggEtag"',
266+
}));
267+
const removeStub = sandbox.stub(MpuHelper.prototype, 'removeParts')
268+
.callsFake((_delParams, cb) => cb(null));
269+
270+
const params = {
271+
Bucket: 'b',
272+
MPU: 'mpu-b',
273+
Key: 'obj',
274+
UploadId: 'upload',
275+
MultipartUpload: {
276+
Parts: [
277+
{ PartNumber: 1 },
278+
{ PartNumber: 2 },
279+
],
280+
},
281+
};
282+
283+
completeMultipartUpload.call({}, params, (err, res) => {
284+
assert.ifError(err);
285+
assert(res);
286+
assert.strictEqual(res.Bucket, params.Bucket);
287+
assert.strictEqual(res.Key, params.Key);
288+
289+
assert(splitMergeStub.calledOnce);
290+
assert(composeFinalStub.calledOnce);
291+
assert(generateStub.calledOnce);
292+
assert(copyStub.calledOnce);
293+
assert(removeStub.calledOnce);
294+
assert.deepStrictEqual(removeStub.firstCall.args[0], {
295+
Bucket: params.Bucket,
296+
MPU: params.MPU,
297+
Prefix: createMpuKey(params.Key, params.UploadId),
298+
});
299+
done();
300+
});
301+
});
302+
});
303+
});
304+

0 commit comments

Comments
 (0)