From 605d6a8ef868cabc77d00aeaca2413464105c4fa Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Fri, 23 Mar 2018 13:07:15 +1100 Subject: [PATCH 01/73] refactor: require native Promise implementation BREAKING CHANGE: An error is thrown on load if a native promise implementation is not available. --- client/js/promise.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/client/js/promise.js b/client/js/promise.js index 100c44ade..7407e8ce9 100644 --- a/client/js/promise.js +++ b/client/js/promise.js @@ -1,5 +1,9 @@ /*globals qq*/ +if (typeof Promise === "undefined") { + throw new Error("FileUploader requires a native promise implementation."); +} + // Is the passed object a promise instance? qq.isGenericPromise = function(maybePromise) { "use strict"; From 80eb375c656fe495f5bf2e14fb4c618b1fc2d108 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Sun, 25 Mar 2018 16:35:46 +1100 Subject: [PATCH 02/73] refactor: qq.s3.util.generateAwsParams to return Promise --- client/js/s3/s3.form.upload.handler.js | 6 +- client/js/s3/s3.xhr.upload.handler.js | 4 +- client/js/s3/util.js | 56 ++++---- test/unit/s3/cdn/generic-non-chunked.js | 15 ++- test/unit/s3/serverless-uploads.js | 136 +++++++++---------- test/unit/s3/simple-file-uploads.js | 166 ++++++++++++++---------- 6 files changed, 208 insertions(+), 175 deletions(-) diff --git a/client/js/s3/s3.form.upload.handler.js b/client/js/s3/s3.form.upload.handler.js index 77edafcdf..75bbb4afa 100644 --- a/client/js/s3/s3.form.upload.handler.js +++ b/client/js/s3/s3.form.upload.handler.js @@ -125,9 +125,9 @@ qq.s3.FormUploadHandler = function(options, proxy) { }); promise.success(form); - }, function(errorMessage) { - promise.failure(errorMessage); - handleFinishedUpload(id, iframe, fileName, {error: errorMessage}); + }, function(error) { + promise.failure(error.message); + handleFinishedUpload(id, iframe, fileName, {error: error.message}); }); return promise; diff --git a/client/js/s3/s3.xhr.upload.handler.js b/client/js/s3/s3.xhr.upload.handler.js index 41299ac1d..37c011a7a 100755 --- a/client/js/s3/s3.xhr.upload.handler.js +++ b/client/js/s3/s3.xhr.upload.handler.js @@ -358,8 +358,8 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { }, // Failure - we couldn't determine some params (likely the signature) - function(errorMessage) { - promise.failure({error: errorMessage}); + function(error) { + promise.failure({error: error.message}); } ); diff --git a/client/js/s3/util.js b/client/js/s3/util.js index eef5d551f..c65a63ffb 100644 --- a/client/js/s3/util.js +++ b/client/js/s3/util.js @@ -238,12 +238,11 @@ qq.s3.util = qq.s3.util || (function() { * * @param spec Object with properties: `params`, `type`, `key`, `accessKey`, `acl`, `expectedStatus`, `successRedirectUrl`, * `reducedRedundancy`, `region`, `serverSideEncryption`, `version`, and `log()`, along with any options associated with `qq.s3.util.getPolicy()`. - * @returns {qq.Promise} Promise that will be fulfilled once all parameters have been determined. + * @returns {Promise} Promise that will be resolved once all parameters have been determined. */ generateAwsParams: function(spec, signPolicyCallback) { var awsParams = {}, customParams = spec.params, - promise = new qq.Promise(), sessionToken = spec.sessionToken, drift = spec.clockDrift, type = spec.type, @@ -314,39 +313,40 @@ qq.s3.util = qq.s3.util || (function() { awsParams[qq.s3.util.DATE_PARAM_NAME] = qq.s3.util.getV4PolicyDate(now, drift); } - // Invoke a promissory callback that should provide us with a base64-encoded policy doc and an - // HMAC signature for the policy doc. - signPolicyCallback(policyJson).then( - function(policyAndSignature, updatedAccessKey, updatedSessionToken) { - awsParams.policy = policyAndSignature.policy; + return new Promise(function(resolve, reject) { + // Invoke a promissory callback that should provide us with a base64-encoded policy doc and an + // HMAC signature for the policy doc. + signPolicyCallback(policyJson).then( + function(policyAndSignature, updatedAccessKey, updatedSessionToken) { + awsParams.policy = policyAndSignature.policy; - if (spec.signatureVersion === 2) { - awsParams.signature = policyAndSignature.signature; + if (spec.signatureVersion === 2) { + awsParams.signature = policyAndSignature.signature; - if (updatedAccessKey) { - awsParams.AWSAccessKeyId = updatedAccessKey; + if (updatedAccessKey) { + awsParams.AWSAccessKeyId = updatedAccessKey; + } + } + else if (spec.signatureVersion === 4) { + awsParams[qq.s3.util.V4_SIGNATURE_PARAM_NAME] = policyAndSignature.signature; } - } - else if (spec.signatureVersion === 4) { - awsParams[qq.s3.util.V4_SIGNATURE_PARAM_NAME] = policyAndSignature.signature; - } - if (updatedSessionToken) { - awsParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = updatedSessionToken; - } + if (updatedSessionToken) { + awsParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = updatedSessionToken; + } - promise.success(awsParams); - }, - function(errorMessage) { - errorMessage = errorMessage || "Can't continue further with request to S3 as we did not receive " + - "a valid signature and policy from the server."; + resolve(awsParams); + }, + function(errorMessage) { + errorMessage = errorMessage || "Can't continue further with request to S3 as we did not receive " + + "a valid signature and policy from the server."; - log("Policy signing failed. " + errorMessage, "error"); - promise.failure(errorMessage); - } - ); + log("Policy signing failed. " + errorMessage, "error"); - return promise; + reject(new Error(errorMessage)); + } + ); + }); }, /** diff --git a/test/unit/s3/cdn/generic-non-chunked.js b/test/unit/s3/cdn/generic-non-chunked.js index adc101643..ef7b5e67e 100644 --- a/test/unit/s3/cdn/generic-non-chunked.js +++ b/test/unit/s3/cdn/generic-non-chunked.js @@ -37,15 +37,18 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(conditions.bucket, "mybucket"); signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - assert.equal(uploadRequest.url, testS3Endpoint); - uploadRequest.respond(200, {ETag: "123"}, null); + setTimeout(function () { + assert.equal(uploadRequest.url, testS3Endpoint); - uploadSuccessRequest = fileTestHelper.getRequests()[2]; - uploadSuccessRequestParsedBody = purl("http://test.com?" + uploadSuccessRequest.requestBody).param(); - assert.equal(uploadSuccessRequestParsedBody.bucket, "mybucket"); + uploadRequest.respond(200, {ETag: "123"}, null); - done(); + uploadSuccessRequest = fileTestHelper.getRequests()[2]; + uploadSuccessRequestParsedBody = purl("http://test.com?" + uploadSuccessRequest.requestBody).param(); + assert.equal(uploadSuccessRequestParsedBody.bucket, "mybucket"); + + done(); + }, 10); }, 10); }); }; diff --git a/test/unit/s3/serverless-uploads.js b/test/unit/s3/serverless-uploads.js index ccbe488e9..d9fa5d608 100644 --- a/test/unit/s3/serverless-uploads.js +++ b/test/unit/s3/serverless-uploads.js @@ -33,38 +33,37 @@ describe("S3 serverless upload tests", function() { fileTestHelper.mockXhr(); uploader.addFiles({name: "test", blob: blob}); + setTimeout(function () { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - - request = fileTestHelper.getRequests()[0]; - requestParams = request.requestBody.fields; + request = fileTestHelper.getRequests()[0]; + requestParams = request.requestBody.fields; - assert.equal(request.url, testS3Endpoint); - assert.equal(request.method, "POST"); + assert.equal(request.url, testS3Endpoint); + assert.equal(request.method, "POST"); - assert.equal(requestParams["Content-Type"], "image/jpeg"); - assert.equal(requestParams.success_action_status, 200); - assert.equal(requestParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME], null); - assert.equal(requestParams["x-amz-storage-class"], null); - assert.equal(requestParams["x-amz-meta-qqfilename"], "test"); - assert.equal(requestParams.key, uploader.getKey(0)); - assert.equal(requestParams.acl, "private"); - assert.ok(requestParams.file); + assert.equal(requestParams["Content-Type"], "image/jpeg"); + assert.equal(requestParams.success_action_status, 200); + assert.equal(requestParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME], null); + assert.equal(requestParams["x-amz-storage-class"], null); + assert.equal(requestParams["x-amz-meta-qqfilename"], "test"); + assert.equal(requestParams.key, uploader.getKey(0)); + assert.equal(requestParams.acl, "private"); + assert.ok(requestParams.file); - assert.equal(requestParams["x-amz-algorithm"], "AWS4-HMAC-SHA256"); - assert.ok(new RegExp(testAccessKey + "\\/\\d{8}\\/us-east-1\\/s3\\/aws4_request").test(requestParams["x-amz-credential"])); - assert.ok(requestParams["x-amz-date"]); - assert.ok(requestParams["x-amz-signature"]); - assert.ok(requestParams.policy); + assert.equal(requestParams["x-amz-algorithm"], "AWS4-HMAC-SHA256"); + assert.ok(new RegExp(testAccessKey + "\\/\\d{8}\\/us-east-1\\/s3\\/aws4_request").test(requestParams["x-amz-credential"])); + assert.ok(requestParams["x-amz-date"]); + assert.ok(requestParams["x-amz-signature"]); + assert.ok(requestParams.policy); - done(); + done(); + }, 0); }); }); }); it("test simple upload with only mandatory credentials specified as options", function(done) { - assert.expect(14, done); - var testExpiration = new Date(Date.now() + 10000), uploader = new qq.s3.FineUploaderBasic({ request: { @@ -82,33 +81,34 @@ describe("S3 serverless upload tests", function() { fileTestHelper.mockXhr(); uploader.addFiles({name: "test", blob: blob}); + setTimeout(function () { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + request = fileTestHelper.getRequests()[0]; + requestParams = request.requestBody.fields; - request = fileTestHelper.getRequests()[0]; - requestParams = request.requestBody.fields; + assert.equal(request.url, testS3Endpoint); + assert.equal(request.method, "POST"); - assert.equal(request.url, testS3Endpoint); - assert.equal(request.method, "POST"); + assert.equal(requestParams["Content-Type"], "image/jpeg"); + assert.equal(requestParams.success_action_status, 200); + assert.equal(requestParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME], null); + assert.equal(requestParams["x-amz-storage-class"], null); + assert.equal(requestParams["x-amz-meta-qqfilename"], "test"); + assert.equal(requestParams.key, uploader.getKey(0)); + assert.equal(requestParams.AWSAccessKeyId, testAccessKey); + assert.equal(requestParams.acl, "private"); + assert.ok(requestParams.file); - assert.equal(requestParams["Content-Type"], "image/jpeg"); - assert.equal(requestParams.success_action_status, 200); - assert.equal(requestParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME], null); - assert.equal(requestParams["x-amz-storage-class"], null); - assert.equal(requestParams["x-amz-meta-qqfilename"], "test"); - assert.equal(requestParams.key, uploader.getKey(0)); - assert.equal(requestParams.AWSAccessKeyId, testAccessKey); - assert.equal(requestParams.acl, "private"); - assert.ok(requestParams.file); + assert.ok(requestParams.signature); + assert.ok(requestParams.policy); - assert.ok(requestParams.signature); - assert.ok(requestParams.policy); + done(); + }, 0); }); }); it("test simple upload with all credential options specified", function(done) { - assert.expect(1, done); - var testExpiration = new Date(Date.now() + 10000).toISOString(), uploader = new qq.s3.FineUploaderBasic({ request: { @@ -127,17 +127,17 @@ describe("S3 serverless upload tests", function() { fileTestHelper.mockXhr(); uploader.addFiles({name: "test", blob: blob}); + setTimeout(function () { + request = fileTestHelper.getRequests()[0]; + requestParams = request.requestBody.fields; - request = fileTestHelper.getRequests()[0]; - requestParams = request.requestBody.fields; - - assert.equal(requestParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME], testSessionToken); + assert.equal(requestParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME], testSessionToken); + done(); + }, 0); }); }); it("test simple upload with credentials only specified via API method", function(done) { - assert.expect(14, done); - var testExpiration = new Date(Date.now() + 10000), uploader = new qq.s3.FineUploaderBasic({ request: { @@ -157,27 +157,29 @@ describe("S3 serverless upload tests", function() { fileTestHelper.mockXhr(); uploader.addFiles({name: "test", blob: blob}); + setTimeout(function () { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - - request = fileTestHelper.getRequests()[0]; - requestParams = request.requestBody.fields; + request = fileTestHelper.getRequests()[0]; + requestParams = request.requestBody.fields; - assert.equal(request.url, testS3Endpoint); - assert.equal(request.method, "POST"); + assert.equal(request.url, testS3Endpoint); + assert.equal(request.method, "POST"); - assert.equal(requestParams["Content-Type"], "image/jpeg"); - assert.equal(requestParams.success_action_status, 200); - assert.equal(requestParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME], testSessionToken); - assert.equal(requestParams["x-amz-storage-class"], null); - assert.equal(requestParams["x-amz-meta-qqfilename"], "test"); - assert.equal(requestParams.key, uploader.getKey(0)); - assert.equal(requestParams.AWSAccessKeyId, testAccessKey); - assert.equal(requestParams.acl, "private"); - assert.ok(requestParams.file); + assert.equal(requestParams["Content-Type"], "image/jpeg"); + assert.equal(requestParams.success_action_status, 200); + assert.equal(requestParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME], testSessionToken); + assert.equal(requestParams["x-amz-storage-class"], null); + assert.equal(requestParams["x-amz-meta-qqfilename"], "test"); + assert.equal(requestParams.key, uploader.getKey(0)); + assert.equal(requestParams.AWSAccessKeyId, testAccessKey); + assert.equal(requestParams.acl, "private"); + assert.ok(requestParams.file); - assert.ok(requestParams.signature); - assert.ok(requestParams.policy); + assert.ok(requestParams.signature); + assert.ok(requestParams.policy); + done(); + }, 0); }); }); @@ -187,8 +189,6 @@ describe("S3 serverless upload tests", function() { testSessionTokenFromCallback = "testSessionTokenFromCallback"; function runTest(callback, done) { - assert.expect(15, done); - var uploader = new qq.s3.FineUploaderBasic({ request: { endpoint: testS3Endpoint @@ -210,9 +210,9 @@ describe("S3 serverless upload tests", function() { fileTestHelper.mockXhr(); uploader.addFiles({name: "test", blob: blob}); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + request = fileTestHelper.getRequests()[0]; requestParams = request.requestBody.fields; @@ -231,6 +231,8 @@ describe("S3 serverless upload tests", function() { assert.ok(requestParams.signature); assert.ok(requestParams.policy); + + done(); }, 10); }); } diff --git a/test/unit/s3/simple-file-uploads.js b/test/unit/s3/simple-file-uploads.js index 29085323f..99290ddfc 100644 --- a/test/unit/s3/simple-file-uploads.js +++ b/test/unit/s3/simple-file-uploads.js @@ -78,26 +78,28 @@ if (qqtest.canDownloadFileAsBlob) { signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - uploadRequestParams = uploadRequest.requestBody.fields; + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequest.url, testS3Endpoint); - assert.equal(uploadRequest.method, "POST"); + assert.equal(uploadRequest.url, testS3Endpoint); + assert.equal(uploadRequest.method, "POST"); - assert.equal(uploadRequestParams.key, uploader.getUuid(0) + ".jpg"); - assert.equal(uploadRequestParams["Content-Type"], "image/jpeg"); - assert.equal(uploadRequestParams.success_action_status, 200); - assert.equal(uploadRequestParams.acl, "private"); - assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); - assert.equal(uploadRequestParams["x-amz-algorithm"], "AWS4-HMAC-SHA256"); - assert.equal(uploadRequestParams["x-amz-credential"], testAccessKey + "/" + now.getUTCFullYear() + ("0" + (now.getUTCMonth() + 1)).slice(-2) + ("0" + now.getUTCDate()).slice(-2) + "/us-east-1/s3/aws4_request"); - assert.equal(uploadRequestParams["x-amz-date"], policyDate); + assert.equal(uploadRequestParams.key, uploader.getUuid(0) + ".jpg"); + assert.equal(uploadRequestParams["Content-Type"], "image/jpeg"); + assert.equal(uploadRequestParams.success_action_status, 200); + assert.equal(uploadRequestParams.acl, "private"); + assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); + assert.equal(uploadRequestParams["x-amz-algorithm"], "AWS4-HMAC-SHA256"); + assert.equal(uploadRequestParams["x-amz-credential"], testAccessKey + "/" + now.getUTCFullYear() + ("0" + (now.getUTCMonth() + 1)).slice(-2) + ("0" + now.getUTCDate()).slice(-2) + "/us-east-1/s3/aws4_request"); + assert.equal(uploadRequestParams["x-amz-date"], policyDate); - assert.ok(uploadRequestParams.file); + assert.ok(uploadRequestParams.file); - assert.equal(uploadRequestParams["x-amz-signature"], "thesignature"); - assert.equal(uploadRequestParams.policy, "thepolicy"); + assert.equal(uploadRequestParams["x-amz-signature"], "thesignature"); + assert.equal(uploadRequestParams.policy, "thepolicy"); - done(); + done(); + }, 0); }); }); @@ -121,9 +123,11 @@ if (qqtest.canDownloadFileAsBlob) { policyDate = conditions["x-amz-date"]; signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequestParams["x-amz-date"], policyDate); - done(); + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; + assert.equal(uploadRequestParams["x-amz-date"], policyDate); + done(); + }, 0); }); }); @@ -148,9 +152,11 @@ if (qqtest.canDownloadFileAsBlob) { policyDate = conditions["x-amz-date"]; signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequestParams["x-amz-date"], policyDate); - done(); + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; + assert.equal(uploadRequestParams["x-amz-date"], policyDate); + done(); + }, 0); }); }); @@ -205,24 +211,26 @@ if (qqtest.canDownloadFileAsBlob) { signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - uploadRequestParams = uploadRequest.requestBody.fields; + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequest.url, testS3Endpoint); - assert.equal(uploadRequest.method, "POST"); + assert.equal(uploadRequest.url, testS3Endpoint); + assert.equal(uploadRequest.method, "POST"); - assert.equal(uploadRequestParams["Content-Type"], "image/jpeg"); - assert.equal(uploadRequestParams.success_action_status, 200); - assert.equal(uploadRequestParams["x-amz-storage-class"], null); - assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); - assert.equal(uploadRequestParams.key, uploader.getUuid(0) + ".jpg"); - assert.equal(uploadRequestParams.AWSAccessKeyId, testAccessKey); - assert.equal(uploadRequestParams.acl, "private"); - assert.ok(uploadRequestParams.file); + assert.equal(uploadRequestParams["Content-Type"], "image/jpeg"); + assert.equal(uploadRequestParams.success_action_status, 200); + assert.equal(uploadRequestParams["x-amz-storage-class"], null); + assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); + assert.equal(uploadRequestParams.key, uploader.getUuid(0) + ".jpg"); + assert.equal(uploadRequestParams.AWSAccessKeyId, testAccessKey); + assert.equal(uploadRequestParams.acl, "private"); + assert.ok(uploadRequestParams.file); - assert.equal(uploadRequestParams.signature, "thesignature"); - assert.equal(uploadRequestParams.policy, "thepolicy"); + assert.equal(uploadRequestParams.signature, "thesignature"); + assert.equal(uploadRequestParams.policy, "thepolicy"); - done(); + done(); + }, 0); }); }); @@ -270,9 +278,11 @@ if (qqtest.canDownloadFileAsBlob) { policyDate = conditions["x-amz-date"]; signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequestParams["x-amz-date"], policyDate); - done(); + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; + assert.equal(uploadRequestParams["x-amz-date"], policyDate); + done(); + }, 0); }); }); @@ -296,9 +306,11 @@ if (qqtest.canDownloadFileAsBlob) { policyDate = conditions["x-amz-date"]; signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequestParams["x-amz-date"], policyDate); - done(); + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; + assert.equal(uploadRequestParams["x-amz-date"], policyDate); + done(); + }, 0); }); }); @@ -329,15 +341,17 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(conditions["Content-Encoding"], "bar"); signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - uploadRequestParams = uploadRequest.requestBody.fields; + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequestParams["x-amz-meta-mixedcase"], "value"); - assert.equal(uploadRequestParams["x-amz-meta-mixedcasefunc"], "value2"); - assert.equal(uploadRequestParams["Content-Disposition"], "attachment; filename=foo.bar;"); - assert.equal(uploadRequestParams["Cache-Control"], "foo"); - assert.equal(uploadRequestParams["Content-Encoding"], "bar"); + assert.equal(uploadRequestParams["x-amz-meta-mixedcase"], "value"); + assert.equal(uploadRequestParams["x-amz-meta-mixedcasefunc"], "value2"); + assert.equal(uploadRequestParams["Content-Disposition"], "attachment; filename=foo.bar;"); + assert.equal(uploadRequestParams["Cache-Control"], "foo"); + assert.equal(uploadRequestParams["Content-Encoding"], "bar"); - done(); + done(); + }, 0); }); }); @@ -359,11 +373,13 @@ if (qqtest.canDownloadFileAsBlob) { signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - uploadRequestParams = uploadRequest.requestBody.fields; + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); + assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); - done(); + done(); + }, 0); }); }); @@ -388,10 +404,12 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(conditions["x-amz-meta-qqfilename"], "test.jpg"); signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; + assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); - done(); + done(); + }, 0); }); }); @@ -416,10 +434,12 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(conditions["x-amz-meta-qqfilename"], "test.jpg"); signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; + assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); - done(); + done(); + }, 0); }); } @@ -536,10 +556,12 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(conditions.acl, "public-read"); signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequestParams.acl, "public-read"); + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; + assert.equal(uploadRequestParams.acl, "public-read"); - done(); + done(); + }, 0); }); }); @@ -561,10 +583,12 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(conditions.acl, "test-acl"); signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequestParams.acl, "test-acl"); + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; + assert.equal(uploadRequestParams.acl, "test-acl"); - done(); + done(); + }, 0); }); }); @@ -584,10 +608,12 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(conditions[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME], qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE); signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequestParams[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME], qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE); + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; + assert.equal(uploadRequestParams[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME], qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE); - done(); + done(); + }, 0); }); }); @@ -607,10 +633,12 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(conditions[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME], qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE); signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequestParams[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME], qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE); + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; + assert.equal(uploadRequestParams[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME], qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE); - done(); + done(); + }, 0); }); }); From b96500a5032d3b6759ba6e00a5ddfad2677564c8 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Sun, 25 Mar 2018 16:36:54 +1100 Subject: [PATCH 03/73] refactor: lint indentation --- client/js/uploader.basic.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/js/uploader.basic.api.js b/client/js/uploader.basic.api.js index 2984277a7..6eaf4919d 100644 --- a/client/js/uploader.basic.api.js +++ b/client/js/uploader.basic.api.js @@ -115,7 +115,7 @@ var uploadData = this._uploadData.retrieve({id: id}); if (uploadData && uploadData.status === qq.status.UPLOAD_FINALIZING) { - this.log(qq.format("Ignoring cancel for file ID {} ({}). Finalizing upload.", id, this.getName(id)), "error"); + this.log(qq.format("Ignoring cancel for file ID {} ({}). Finalizing upload.", id, this.getName(id)), "error"); } else { this._handler.cancel(id); From 15458df0219f42b1ae06cbc58a2785a41b026320 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Sun, 25 Mar 2018 17:15:06 +1100 Subject: [PATCH 04/73] refactor: qq.azure.FineUploaderBasic._determineBlobName use Promise --- .jshintrc | 3 + client/js/azure/azure.xhr.upload.handler.js | 4 +- client/js/azure/uploader.basic.js | 6 +- test/unit/azure/chunked-uploads.js | 404 +++++++++++--------- test/unit/azure/delete-files.js | 28 +- 5 files changed, 256 insertions(+), 189 deletions(-) diff --git a/.jshintrc b/.jshintrc index 934eb8d9e..fdc0d89f1 100644 --- a/.jshintrc +++ b/.jshintrc @@ -84,6 +84,9 @@ "couch" : false, // Enable globals exposed by CouchDB. "devel" : false, // Allow development statements e.g. `console.log();`. "dojo" : false, // Enable globals exposed by Dojo Toolkit. + "globals" : { + "Promise": true + }, "jquery" : true, // Enable globals exposed by jQuery JavaScript library. "mootools" : false, // Enable globals exposed by MooTools JavaScript framework. "node" : false, // Enable globals available when code is running inside of the NodeJS runtime environment. diff --git a/client/js/azure/azure.xhr.upload.handler.js b/client/js/azure/azure.xhr.upload.handler.js index 6f309aa9c..cf6300ffa 100644 --- a/client/js/azure/azure.xhr.upload.handler.js +++ b/client/js/azure/azure.xhr.upload.handler.js @@ -89,8 +89,8 @@ qq.azure.XhrUploadHandler = function(spec, proxy) { handler._setThirdPartyFileId(id, blobName); promise.success(containerUrl + "/" + blobName); }, - getBlobNameFailure = function(reason) { - promise.failure(reason); + getBlobNameFailure = function(error) { + promise.failure(error.message); }; onGetBlobName(id).then(getBlobNameSuccess, getBlobNameFailure); diff --git a/client/js/azure/uploader.basic.js b/client/js/azure/uploader.basic.js index 68eed898c..8952c47bf 100644 --- a/client/js/azure/uploader.basic.js +++ b/client/js/azure/uploader.basic.js @@ -109,11 +109,11 @@ if (fileExtension !== undefined) { blobNameToUse += "." + fileExtension; } - return new qq.Promise().success(blobNameToUse); + return Promise.resolve(blobNameToUse); case "filename": - return new qq.Promise().success(filename); + return Promise.resolve(filename); default: - return new qq.Promise.failure("Invalid blobName option value - " + blobNameOptionValue); + return Promise.reject(new Error("Invalid blobName option value - " + blobNameOptionValue)); } } else { diff --git a/test/unit/azure/chunked-uploads.js b/test/unit/azure/chunked-uploads.js index 45148f1f7..2db7abc32 100644 --- a/test/unit/azure/chunked-uploads.js +++ b/test/unit/azure/chunked-uploads.js @@ -22,15 +22,17 @@ describe("azure chunked upload tests", function() { fileTestHelper.mockXhr(); uploader.addFiles({name: "test.jpg", blob: blob}); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + setTimeout(function () { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - signatureRequest = fileTestHelper.getRequests()[0]; - assert.equal(signatureRequest.method, "GET"); + signatureRequest = fileTestHelper.getRequests()[0]; + assert.equal(signatureRequest.method, "GET"); - signatureRequestPurl = purl(signatureRequest.url); - assert.equal(signatureRequestPurl.attr("path"), testSignatureEndoint); + signatureRequestPurl = purl(signatureRequest.url); + assert.equal(signatureRequestPurl.attr("path"), testSignatureEndoint); - callback(signatureRequest, signatureRequestPurl); + callback(signatureRequest, signatureRequestPurl); + }, 0); }); }, testSignatureEndoint = "/signature", @@ -64,11 +66,13 @@ describe("azure chunked upload tests", function() { assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); signatureRequest.respond(200, null, expectedSasUri); - // upload request - assert.equal(fileTestHelper.getRequests().length, 2); - uploadRequest = fileTestHelper.getRequests()[1]; - assert.equal(uploadRequest.method, "PUT"); - assert.equal(uploadRequest.url, expectedSasUri); + setTimeout(function () { + // upload request + assert.equal(fileTestHelper.getRequests().length, 2); + uploadRequest = fileTestHelper.getRequests()[1]; + assert.equal(uploadRequest.method, "PUT"); + assert.equal(uploadRequest.url, expectedSasUri); + }, 0); }); }); @@ -137,50 +141,62 @@ describe("azure chunked upload tests", function() { assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); signatureRequest.respond(200, null, expectedSasUri); - // upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 2); - uploadRequest = fileTestHelper.getRequests()[1]; - assert.ok(!uploadRequest.requestHeaders["x-ms-meta-qqfilename"]); - assert.equal(uploadRequest.method, "PUT"); - assert.equal(uploadRequest.url, expectedSasUri + "&comp=block&blockid=" + encodeURIComponent(btoa("00000"))); - uploadRequest.respond(201, null, null); - - // signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 3); - signatureRequest = fileTestHelper.getRequests()[2]; - assert.equal(signatureRequest.method, "GET"); - signatureRequestPurl = purl(signatureRequest.url); - assert.equal(signatureRequestPurl.param("_method"), "PUT"); - assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); - signatureRequest.respond(200, null, expectedSasUri); - - // upload part 2 request - assert.equal(fileTestHelper.getRequests().length, 4); - uploadRequest = fileTestHelper.getRequests()[3]; - assert.ok(!uploadRequest.requestHeaders["x-ms-meta-qqfilename"]); - assert.equal(uploadRequest.method, "PUT"); - assert.equal(uploadRequest.url, expectedSasUri + "&comp=block&blockid=" + encodeURIComponent(btoa("00001"))); - uploadRequest.respond(201, null, null); - - // signature request for put block list - assert.equal(fileTestHelper.getRequests().length, 5); - signatureRequest = fileTestHelper.getRequests()[4]; - assert.equal(signatureRequest.method, "GET"); - signatureRequestPurl = purl(signatureRequest.url); - assert.equal(signatureRequestPurl.param("_method"), "PUT"); - assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); - signatureRequest.respond(200, null, expectedSasUri); - - // put block list request - assert.equal(fileTestHelper.getRequests().length, 6); - putBlockListRequest = fileTestHelper.getRequests()[5]; - assert.equal(putBlockListRequest.method, "PUT"); - assert.equal(putBlockListRequest.url, expectedSasUri + "&comp=blocklist"); - assert.equal(putBlockListRequest.requestHeaders["x-ms-blob-content-type"], "image/jpeg"); - assert.equal(putBlockListRequest.requestHeaders["x-ms-meta-qqfilename"], uploader.getName(0)); - putBlockListRequest.respond(201, null, null); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + setTimeout(function () { + // upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 2); + uploadRequest = fileTestHelper.getRequests()[1]; + assert.ok(!uploadRequest.requestHeaders["x-ms-meta-qqfilename"]); + assert.equal(uploadRequest.method, "PUT"); + assert.equal(uploadRequest.url, expectedSasUri + "&comp=block&blockid=" + encodeURIComponent(btoa("00000"))); + uploadRequest.respond(201, null, null); + + setTimeout(function () { + // signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 3); + signatureRequest = fileTestHelper.getRequests()[2]; + assert.equal(signatureRequest.method, "GET"); + signatureRequestPurl = purl(signatureRequest.url); + assert.equal(signatureRequestPurl.param("_method"), "PUT"); + assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); + signatureRequest.respond(200, null, expectedSasUri); + + setTimeout(function () { + // upload part 2 request + assert.equal(fileTestHelper.getRequests().length, 4); + uploadRequest = fileTestHelper.getRequests()[3]; + assert.ok(!uploadRequest.requestHeaders["x-ms-meta-qqfilename"]); + assert.equal(uploadRequest.method, "PUT"); + assert.equal(uploadRequest.url, expectedSasUri + "&comp=block&blockid=" + encodeURIComponent(btoa("00001"))); + uploadRequest.respond(201, null, null); + + setTimeout(function () { + // signature request for put block list + assert.equal(fileTestHelper.getRequests().length, 5); + signatureRequest = fileTestHelper.getRequests()[4]; + assert.equal(signatureRequest.method, "GET"); + signatureRequestPurl = purl(signatureRequest.url); + assert.equal(signatureRequestPurl.param("_method"), "PUT"); + assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); + signatureRequest.respond(200, null, expectedSasUri); + + setTimeout(function () { + // put block list request + assert.equal(fileTestHelper.getRequests().length, 6); + putBlockListRequest = fileTestHelper.getRequests()[5]; + assert.equal(putBlockListRequest.method, "PUT"); + assert.equal(putBlockListRequest.url, expectedSasUri + "&comp=blocklist"); + assert.equal(putBlockListRequest.requestHeaders["x-ms-blob-content-type"], "image/jpeg"); + assert.equal(putBlockListRequest.requestHeaders["x-ms-meta-qqfilename"], uploader.getName(0)); + putBlockListRequest.respond(201, null, null); + + setTimeout(function () { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); }); }); @@ -221,124 +237,166 @@ describe("azure chunked upload tests", function() { // failing signature request for upload part 1 assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); signatureRequest.respond(500, null, null); - assert.equal(fileTestHelper.getRequests().length, 1); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - uploader.retry(0); - assert.equal(fileTestHelper.getRequests().length, 2); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for upload part 1 - signatureRequest = fileTestHelper.getRequests()[1]; - signatureRequestPurl = purl(signatureRequest.url); - assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); - signatureRequest.respond(200, null, expectedSasUri); - - // failing upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 3); - uploadRequest = fileTestHelper.getRequests()[2]; - assert.equal(uploadRequest.url, expectedSasUri + "&comp=block&blockid=" + encodeURIComponent(btoa("00000"))); - uploadRequest.respond(404, null, null); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - uploader.retry(0); - assert.equal(fileTestHelper.getRequests().length, 4); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for upload part 1 - signatureRequest = fileTestHelper.getRequests()[3]; - signatureRequestPurl = purl(signatureRequest.url); - assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); - signatureRequest.respond(200, null, expectedSasUri); - - // successful upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 5); - uploadRequest = fileTestHelper.getRequests()[4]; - assert.equal(uploadRequest.url, expectedSasUri + "&comp=block&blockid=" + encodeURIComponent(btoa("00000"))); - uploadRequest.respond(201, null, null); - - // failing signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 6); - signatureRequest = fileTestHelper.getRequests()[5]; - signatureRequestPurl = purl(signatureRequest.url); - assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); - signatureRequest.respond(500, null, null); - assert.equal(fileTestHelper.getRequests().length, 6); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - uploader.retry(0); - assert.equal(fileTestHelper.getRequests().length, 7); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for upload part 2 - signatureRequest = fileTestHelper.getRequests()[6]; - signatureRequestPurl = purl(signatureRequest.url); - assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); - signatureRequest.respond(200, null, expectedSasUri); - - // failing upload part 2 request - assert.equal(fileTestHelper.getRequests().length, 8); - uploadRequest = fileTestHelper.getRequests()[7]; - assert.equal(uploadRequest.url, expectedSasUri + "&comp=block&blockid=" + encodeURIComponent(btoa("00001"))); - uploadRequest.respond(404, null, null); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - uploader.retry(0); - assert.equal(fileTestHelper.getRequests().length, 9); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for upload part 1 - signatureRequest = fileTestHelper.getRequests()[8]; - signatureRequestPurl = purl(signatureRequest.url); - assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); - signatureRequest.respond(200, null, expectedSasUri); - - // successful upload part 2 request - assert.equal(fileTestHelper.getRequests().length, 10); - uploadRequest = fileTestHelper.getRequests()[9]; - assert.equal(uploadRequest.method, "PUT"); - assert.equal(uploadRequest.url, expectedSasUri + "&comp=block&blockid=" + encodeURIComponent(btoa("00001"))); - uploadRequest.respond(201, null, null); - - // failing signature request for put block list - assert.equal(fileTestHelper.getRequests().length, 11); - signatureRequest = fileTestHelper.getRequests()[10]; - signatureRequestPurl = purl(signatureRequest.url); - assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); - signatureRequest.respond(500, null, null); - assert.equal(fileTestHelper.getRequests().length, 11); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - uploader.retry(0); - assert.equal(fileTestHelper.getRequests().length, 12); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for put block list - signatureRequest = fileTestHelper.getRequests()[11]; - signatureRequestPurl = purl(signatureRequest.url); - assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); - signatureRequest.respond(200, null, expectedSasUri); - - // failing put block list request - assert.equal(fileTestHelper.getRequests().length, 13); - putBlockListRequest = fileTestHelper.getRequests()[12]; - assert.equal(putBlockListRequest.url, expectedSasUri + "&comp=blocklist"); - assert.equal(putBlockListRequest.requestHeaders["x-ms-blob-content-type"], "image/jpeg"); - putBlockListRequest.respond(404, null, null); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - uploader.retry(0); - assert.equal(fileTestHelper.getRequests().length, 14); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for put block list - signatureRequest = fileTestHelper.getRequests()[13]; - signatureRequestPurl = purl(signatureRequest.url); - assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); - signatureRequest.respond(200, null, expectedSasUri); - - // successful put block list request - assert.equal(fileTestHelper.getRequests().length, 15); - putBlockListRequest = fileTestHelper.getRequests()[14]; - assert.equal(putBlockListRequest.url, expectedSasUri + "&comp=blocklist"); - assert.equal(putBlockListRequest.requestHeaders["x-ms-blob-content-type"], "image/jpeg"); - putBlockListRequest.respond(201, null, null); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + setTimeout(function () { + assert.equal(fileTestHelper.getRequests().length, 1); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + uploader.retry(0); + setTimeout(function () { + assert.equal(fileTestHelper.getRequests().length, 2); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for upload part 1 + signatureRequest = fileTestHelper.getRequests()[1]; + signatureRequestPurl = purl(signatureRequest.url); + assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); + signatureRequest.respond(200, null, expectedSasUri); + + setTimeout(function () { + // failing upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 3); + uploadRequest = fileTestHelper.getRequests()[2]; + assert.equal(uploadRequest.url, expectedSasUri + "&comp=block&blockid=" + encodeURIComponent(btoa("00000"))); + uploadRequest.respond(404, null, null); + setTimeout(function () { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + uploader.retry(0); + setTimeout(function () { + assert.equal(fileTestHelper.getRequests().length, 4); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for upload part 1 + signatureRequest = fileTestHelper.getRequests()[3]; + signatureRequestPurl = purl(signatureRequest.url); + assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); + signatureRequest.respond(200, null, expectedSasUri); + + setTimeout(function () { + // successful upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 5); + uploadRequest = fileTestHelper.getRequests()[4]; + assert.equal(uploadRequest.url, expectedSasUri + "&comp=block&blockid=" + encodeURIComponent(btoa("00000"))); + uploadRequest.respond(201, null, null); + + setTimeout(function () { + // failing signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 6); + signatureRequest = fileTestHelper.getRequests()[5]; + signatureRequestPurl = purl(signatureRequest.url); + assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); + signatureRequest.respond(500, null, null); + setTimeout(function () { + assert.equal(fileTestHelper.getRequests().length, 6); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + uploader.retry(0); + setTimeout(function () { + assert.equal(fileTestHelper.getRequests().length, 7); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for upload part 2 + signatureRequest = fileTestHelper.getRequests()[6]; + signatureRequestPurl = purl(signatureRequest.url); + assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); + signatureRequest.respond(200, null, expectedSasUri); + + setTimeout(function () { + // failing upload part 2 request + assert.equal(fileTestHelper.getRequests().length, 8); + uploadRequest = fileTestHelper.getRequests()[7]; + assert.equal(uploadRequest.url, expectedSasUri + "&comp=block&blockid=" + encodeURIComponent(btoa("00001"))); + uploadRequest.respond(404, null, null); + setTimeout(function () { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + uploader.retry(0); + setTimeout(function () { + assert.equal(fileTestHelper.getRequests().length, 9); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for upload part 1 + signatureRequest = fileTestHelper.getRequests()[8]; + signatureRequestPurl = purl(signatureRequest.url); + assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); + signatureRequest.respond(200, null, expectedSasUri); + + setTimeout(function () { + // successful upload part 2 request + assert.equal(fileTestHelper.getRequests().length, 10); + uploadRequest = fileTestHelper.getRequests()[9]; + assert.equal(uploadRequest.method, "PUT"); + assert.equal(uploadRequest.url, expectedSasUri + "&comp=block&blockid=" + encodeURIComponent(btoa("00001"))); + uploadRequest.respond(201, null, null); + + setTimeout(function () { + // failing signature request for put block list + assert.equal(fileTestHelper.getRequests().length, 11); + signatureRequest = fileTestHelper.getRequests()[10]; + signatureRequestPurl = purl(signatureRequest.url); + assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); + signatureRequest.respond(500, null, null); + setTimeout(function () { + assert.equal(fileTestHelper.getRequests().length, 11); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + uploader.retry(0); + setTimeout(function () { + assert.equal(fileTestHelper.getRequests().length, 12); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for put block list + signatureRequest = fileTestHelper.getRequests()[11]; + signatureRequestPurl = purl(signatureRequest.url); + assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); + signatureRequest.respond(200, null, expectedSasUri); + + setTimeout(function () { + // failing put block list request + assert.equal(fileTestHelper.getRequests().length, 13); + putBlockListRequest = fileTestHelper.getRequests()[12]; + assert.equal(putBlockListRequest.url, expectedSasUri + "&comp=blocklist"); + assert.equal(putBlockListRequest.requestHeaders["x-ms-blob-content-type"], "image/jpeg"); + putBlockListRequest.respond(404, null, null); + setTimeout(function () { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + uploader.retry(0); + setTimeout(function () { + assert.equal(fileTestHelper.getRequests().length, 14); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for put block list + signatureRequest = fileTestHelper.getRequests()[13]; + signatureRequestPurl = purl(signatureRequest.url); + assert.equal(signatureRequestPurl.param("bloburi"), testContainerEndpoint + "/" + uploader.getBlobName(0)); + signatureRequest.respond(200, null, expectedSasUri); + + setTimeout(function () { + // successful put block list request + assert.equal(fileTestHelper.getRequests().length, 15); + putBlockListRequest = fileTestHelper.getRequests()[14]; + assert.equal(putBlockListRequest.url, expectedSasUri + "&comp=blocklist"); + assert.equal(putBlockListRequest.requestHeaders["x-ms-blob-content-type"], "image/jpeg"); + putBlockListRequest.respond(201, null, null); + + setTimeout(function () { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); }); }); }); diff --git a/test/unit/azure/delete-files.js b/test/unit/azure/delete-files.js index 896be5041..391f47ba4 100644 --- a/test/unit/azure/delete-files.js +++ b/test/unit/azure/delete-files.js @@ -13,16 +13,18 @@ if (qqtest.canDownloadFileAsBlob) { fileTestHelper.mockXhr(); uploader.addFiles({name: "test.jpg", blob: blob}); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - signatureRequest = fileTestHelper.getRequests()[0]; - signatureRequest.respond(200, null, "http://sasuri.com"); + signatureRequest = fileTestHelper.getRequests()[0]; + signatureRequest.respond(200, null, "http://sasuri.com"); - setTimeout(function() { - var uploadRequest = fileTestHelper.getRequests()[1]; - uploadRequest.respond(201, null, ""); + setTimeout(function() { + var uploadRequest = fileTestHelper.getRequests()[1]; + uploadRequest.respond(201, null, ""); - callback(); + callback(); + }, 0); }, 0); }); }; @@ -155,11 +157,15 @@ if (qqtest.canDownloadFileAsBlob) { deleteFileSignatureRequest = fileTestHelper.getRequests()[2]; deleteFileSignatureRequest.respond(200, null, "http://sasuri.com"); - assert.equal(fileTestHelper.getRequests().length, 4); - deleteFileRequest = fileTestHelper.getRequests()[3]; - deleteFileRequest.respond(500, null, null); + setTimeout(function () { + assert.equal(fileTestHelper.getRequests().length, 4); + deleteFileRequest = fileTestHelper.getRequests()[3]; + deleteFileRequest.respond(500, null, null); - assert.equal(uploader.getUploads()[0].status, qq.status.DELETE_FAILED); + setTimeout(function () { + assert.equal(uploader.getUploads()[0].status, qq.status.DELETE_FAILED); + }, 0); + }, 0); }); }); }); From 8093491ba69f5fd4e55e749aded8e96e49b7036f Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Sun, 25 Mar 2018 18:34:40 +1100 Subject: [PATCH 05/73] refactor: qq.Exif.seekToApp1 use Promise --- client/js/image-support/exif.js | 43 +++++++++++++++------------------ test/unit/chunked-uploads.js | 3 ++- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/client/js/image-support/exif.js b/client/js/image-support/exif.js index 00f904eaa..12360ab75 100644 --- a/client/js/image-support/exif.js +++ b/client/js/image-support/exif.js @@ -34,33 +34,28 @@ qq.Exif = function(fileOrBlob, log) { // Find the byte offset, of Application Segment 1 (EXIF). // External callers need not supply any arguments. - function seekToApp1(offset, promise) { - var theOffset = offset, - thePromise = promise; - if (theOffset === undefined) { - theOffset = 2; - thePromise = new qq.Promise(); - } - - qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) { - var match = /^ffe([0-9])/.exec(hex), - segmentLength; - - if (match) { - if (match[1] !== "1") { - segmentLength = parseInt(hex.slice(4, 8), 16); - seekToApp1(theOffset + segmentLength + 2, thePromise); + function seekToApp1(offset) { + var theOffset = offset === undefined ? 2 : offset; + + return new Promise(function(resolve, reject) { + qq.readBlobToHex(fileOrBlob, theOffset, 4).then(function(hex) { + var match = /^ffe([0-9])/.exec(hex), + segmentLength; + + if (match) { + if (match[1] !== "1") { + segmentLength = parseInt(hex.slice(4, 8), 16); + seekToApp1(theOffset + segmentLength + 2).then(resolve, reject); + } + else { + resolve(theOffset); + } } else { - thePromise.success(theOffset); + reject(new Error("No EXIF header to be found!")); } - } - else { - thePromise.failure("No EXIF header to be found!"); - } + }); }); - - return thePromise; } // Find the byte offset of Application Segment 1 (EXIF) for valid JPEGs only. @@ -76,7 +71,7 @@ qq.Exif = function(fileOrBlob, log) { promise.success(offset); }, function(error) { - promise.failure(error); + promise.failure(error.message); }); } }); diff --git a/test/unit/chunked-uploads.js b/test/unit/chunked-uploads.js index e8582ab87..fea74feff 100644 --- a/test/unit/chunked-uploads.js +++ b/test/unit/chunked-uploads.js @@ -428,11 +428,12 @@ if (qqtest.canDownloadFileAsBlob) { } it("stores custom resume data with resume record", function(done){ + assert.expect(1, done); + testResumeRecordsLogic( function(id, chunkData) { if (chunkData.partIndex === 1) { assert.deepEqual(uploader.getResumableFilesData()[0].customResumeData, { custom: "resumedata" }); - done(); } else { uploader.setCustomResumeData(0, { custom: "resumedata" }); From a29e398095edbf3d2bc87f536233fa79e6329ba6 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Sun, 25 Mar 2018 18:45:57 +1100 Subject: [PATCH 06/73] refactor: qq.readBlobToHex use Promise --- client/js/image-support/exif.js | 4 +++- client/js/util.js | 19 ++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/client/js/image-support/exif.js b/client/js/image-support/exif.js index 12360ab75..d5372997c 100644 --- a/client/js/image-support/exif.js +++ b/client/js/image-support/exif.js @@ -188,7 +188,9 @@ qq.Exif = function(fileOrBlob, log) { log("Successfully parsed some EXIF tags"); parser.success(tagValues); - }, onParseFailure); + }, function (error) { + onParseFailure(error.message); + }); }, onParseFailure); }, onParseFailure); }, onParseFailure); diff --git a/client/js/util.js b/client/js/util.js index f6d5f109c..86be54dc3 100644 --- a/client/js/util.js +++ b/client/js/util.js @@ -428,18 +428,19 @@ var qq = function(element) { qq.readBlobToHex = function(blob, startOffset, length) { var initialBlob = qq.sliceBlob(blob, startOffset, startOffset + length), - fileReader = new FileReader(), - promise = new qq.Promise(); + fileReader = new FileReader(); - fileReader.onload = function() { - promise.success(qq.arrayBufferToHex(fileReader.result)); - }; - - fileReader.onerror = promise.failure; + return new Promise(function(resolve, reject) { + fileReader.onload = function() { + resolve(qq.arrayBufferToHex(fileReader.result)); + }; - fileReader.readAsArrayBuffer(initialBlob); + fileReader.onerror = function (e) { + reject(new Error(e.message)); + }; - return promise; + fileReader.readAsArrayBuffer(initialBlob); + }); }; qq.extend = function(first, second, extendNested) { From 00990029ea8eabf74695e0f5b9b0bb2ea8e684bb Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Sun, 25 Mar 2018 22:00:52 +1100 Subject: [PATCH 07/73] refactor: qq.Exif.getApp1Offset to use Promise --- client/js/image-support/exif.js | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/client/js/image-support/exif.js b/client/js/image-support/exif.js index d5372997c..369279e40 100644 --- a/client/js/image-support/exif.js +++ b/client/js/image-support/exif.js @@ -60,23 +60,16 @@ qq.Exif = function(fileOrBlob, log) { // Find the byte offset of Application Segment 1 (EXIF) for valid JPEGs only. function getApp1Offset() { - var promise = new qq.Promise(); - - qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) { - if (hex.indexOf("ffd8") !== 0) { - promise.failure("Not a valid JPEG!"); - } - else { - seekToApp1().then(function(offset) { - promise.success(offset); - }, - function(error) { - promise.failure(error.message); - }); - } + return new Promise(function(resolve, reject) { + qq.readBlobToHex(fileOrBlob, 0, 6).then(function(hex) { + if (hex.indexOf("ffd8") !== 0) { + reject(new Error("Not a valid JPEG!")); + } + else { + seekToApp1().then(resolve, reject); + } + }); }); - - return promise; } // Determine the byte ordering of the EXIF header. @@ -193,7 +186,9 @@ qq.Exif = function(fileOrBlob, log) { }); }, onParseFailure); }, onParseFailure); - }, onParseFailure); + }, function (error) { + onParseFailure(error.message); + }); return parser; } From 45f7816f827ab3f01cc5457a69f2bb8527090188 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Sun, 25 Mar 2018 22:02:10 +1100 Subject: [PATCH 08/73] refactor: qq.Exif.isLittleEndian to use Promise --- client/js/image-support/exif.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/client/js/image-support/exif.js b/client/js/image-support/exif.js index 369279e40..c4c73d779 100644 --- a/client/js/image-support/exif.js +++ b/client/js/image-support/exif.js @@ -74,13 +74,11 @@ qq.Exif = function(fileOrBlob, log) { // Determine the byte ordering of the EXIF header. function isLittleEndian(app1Start) { - var promise = new qq.Promise(); - - qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) { - promise.success(hex === "4949"); + return new Promise(function(resolve) { + qq.readBlobToHex(fileOrBlob, app1Start + 10, 2).then(function(hex) { + resolve(hex === "4949"); + }); }); - - return promise; } // Determine the number of directory entries in the EXIF header. @@ -184,8 +182,12 @@ qq.Exif = function(fileOrBlob, log) { }, function (error) { onParseFailure(error.message); }); - }, onParseFailure); - }, onParseFailure); + }, function (error) { + onParseFailure(error.message); + }); + }, function (error) { + onParseFailure(error.message); + }); }, function (error) { onParseFailure(error.message); }); From 7bde2616363714f8ae11d2022808aeb54d8a4b3f Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Sun, 25 Mar 2018 22:03:44 +1100 Subject: [PATCH 09/73] refactor: qq.Exif.getDirEntryCount to use Promise --- client/js/image-support/exif.js | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/client/js/image-support/exif.js b/client/js/image-support/exif.js index c4c73d779..a440a54ae 100644 --- a/client/js/image-support/exif.js +++ b/client/js/image-support/exif.js @@ -83,18 +83,16 @@ qq.Exif = function(fileOrBlob, log) { // Determine the number of directory entries in the EXIF header. function getDirEntryCount(app1Start, littleEndian) { - var promise = new qq.Promise(); - - qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) { - if (littleEndian) { - return promise.success(parseLittleEndian(hex)); - } - else { - promise.success(parseInt(hex, 16)); - } + return new Promise(function(resolve) { + qq.readBlobToHex(fileOrBlob, app1Start + 18, 2).then(function(hex) { + if (littleEndian) { + resolve(parseLittleEndian(hex)); + } + else { + resolve(parseInt(hex, 16)); + } + }); }); - - return promise; } // Get the IFD portion of the EXIF header as a hex string. From 3a6f27e3b35466281cd043c603ea1e1a4f0f1a26 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Sun, 25 Mar 2018 22:26:18 +1100 Subject: [PATCH 10/73] refactor: qq.Exif.parse to use Promise --- client/js/image-support/exif.js | 51 +++++++++++++------------------- client/js/image-support/image.js | 4 +-- 2 files changed, 23 insertions(+), 32 deletions(-) diff --git a/client/js/image-support/exif.js b/client/js/image-support/exif.js index a440a54ae..cef5c6ca4 100644 --- a/client/js/image-support/exif.js +++ b/client/js/image-support/exif.js @@ -149,48 +149,39 @@ qq.Exif = function(fileOrBlob, log) { /** * Attempt to parse the EXIF header for the `Blob` associated with this instance. * - * @returns {qq.Promise} To be fulfilled when the parsing is complete. + * @returns {Promise} To be resolved when the parsing is complete. * If successful, the parsed EXIF header as an object will be included. */ parse: function() { - var parser = new qq.Promise(), - onParseFailure = function(message) { - log(qq.format("EXIF header parse failed: '{}' ", message)); - parser.failure(message); - }; + return new Promise(function(resolve, reject) { + function onParseFailure(error) { + log(qq.format("EXIF header parse failed: '{}' ", error.message)); + reject(error); + } - getApp1Offset().then(function(app1Offset) { - log(qq.format("Moving forward with EXIF header parsing for '{}'", fileOrBlob.name === undefined ? "blob" : fileOrBlob.name)); + getApp1Offset().then(function(app1Offset) { + log(qq.format("Moving forward with EXIF header parsing for '{}'", fileOrBlob.name === undefined ? "blob" : fileOrBlob.name)); - isLittleEndian(app1Offset).then(function(littleEndian) { + isLittleEndian(app1Offset).then(function(littleEndian) { - log(qq.format("EXIF Byte order is {} endian", littleEndian ? "little" : "big")); + log(qq.format("EXIF Byte order is {} endian", littleEndian ? "little" : "big")); - getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) { + getDirEntryCount(app1Offset, littleEndian).then(function(dirEntryCount) { - log(qq.format("Found {} APP1 directory entries", dirEntryCount)); + log(qq.format("Found {} APP1 directory entries", dirEntryCount)); - getIfd(app1Offset, dirEntryCount).then(function(ifdHex) { - var dirEntries = getDirEntries(ifdHex), - tagValues = getTagValues(littleEndian, dirEntries); + getIfd(app1Offset, dirEntryCount).then(function(ifdHex) { + var dirEntries = getDirEntries(ifdHex), + tagValues = getTagValues(littleEndian, dirEntries); - log("Successfully parsed some EXIF tags"); + log("Successfully parsed some EXIF tags"); - parser.success(tagValues); - }, function (error) { - onParseFailure(error.message); - }); - }, function (error) { - onParseFailure(error.message); - }); - }, function (error) { - onParseFailure(error.message); - }); - }, function (error) { - onParseFailure(error.message); + resolve(tagValues); + }, onParseFailure); + }, onParseFailure); + }, onParseFailure); + }, onParseFailure); }); - - return parser; } }); diff --git a/client/js/image-support/image.js b/client/js/image-support/image.js index b2970aae3..62a93c9c1 100644 --- a/client/js/image-support/image.js +++ b/client/js/image-support/image.js @@ -172,8 +172,8 @@ qq.ImageGenerator = function(log) { }); }, - function(failureMsg) { - log(qq.format("EXIF data could not be parsed ({}). Assuming orientation = 1.", failureMsg)); + function(error) { + log(qq.format("EXIF data could not be parsed ({}). Assuming orientation = 1.", error.message)); mpImg.render(container, { maxWidth: maxSize, From 674071a1086723567631fbf27665fb4ddcb06c73 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Sun, 25 Mar 2018 22:46:58 +1100 Subject: [PATCH 11/73] refactor: qq.Scalar.scaleImage to use Promise --- client/js/image-support/scaler.js | 45 +++++++++++++++---------------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/client/js/image-support/scaler.js b/client/js/image-support/scaler.js index 26b94e03f..4a67c0f9f 100644 --- a/client/js/image-support/scaler.js +++ b/client/js/image-support/scaler.js @@ -165,8 +165,7 @@ qq.extend(qq.Scaler.prototype, { throw new qq.Error("Scaling is not supported in this browser!"); } - var scalingEffort = new qq.Promise(), - log = api.log, + var log = api.log, file = api.getFile(id), uploadData = api.uploadData.retrieve({id: id}), name = uploadData && uploadData.name, @@ -182,28 +181,28 @@ qq.extend(qq.Scaler.prototype, { }, scaler = new qq.Scaler(scalingOptions, log); - if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) { - scalingEffort.failure(); + return new Promise(function(resolve, reject) { + if (!qq.Scaler || !qq.supportedFeatures.imagePreviews || !file) { + reject(); - log("Could not generate requested scaled image for " + id + ". " + - "Scaling is either not possible in this browser, or the file could not be located.", "error"); - } - else { - (qq.bind(function() { - // Assumption: There will never be more than one record - var record = scaler.getFileRecords(uuid, name, file)[0]; - - if (record && record.blob instanceof qq.BlobProxy) { - record.blob.create().then(scalingEffort.success, scalingEffort.failure); - } - else { - log(id + " is not a scalable image!", "error"); - scalingEffort.failure(); - } - }, this)()); - } - - return scalingEffort; + log("Could not generate requested scaled image for " + id + ". " + + "Scaling is either not possible in this browser, or the file could not be located.", "error"); + } + else { + (qq.bind(function() { + // Assumption: There will never be more than one record + var record = scaler.getFileRecords(uuid, name, file)[0]; + + if (record && record.blob instanceof qq.BlobProxy) { + record.blob.create().then(resolve, reject); + } + else { + log(id + " is not a scalable image!", "error"); + reject(); + } + }, this)()); + } + }); }, // NOTE: We cannot reliably determine at this time if the UA supports a specific MIME type for the target format. From d4fae1971757c074513737f1d77b2d9e6d767c68 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Sun, 25 Mar 2018 22:52:15 +1100 Subject: [PATCH 12/73] refactor: qq.Scalar._generateScaledImage to use Promise --- client/js/image-support/scaler.js | 51 +++++++++++++++---------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/client/js/image-support/scaler.js b/client/js/image-support/scaler.js index 4a67c0f9f..0159c10f1 100644 --- a/client/js/image-support/scaler.js +++ b/client/js/image-support/scaler.js @@ -300,39 +300,38 @@ qq.extend(qq.Scaler.prototype, { quality = spec.quality, failedText = spec.failedText, includeExif = spec.includeExif && sourceFile.type === "image/jpeg" && type === "image/jpeg", - scalingEffort = new qq.Promise(), imageGenerator = new qq.ImageGenerator(log), canvas = document.createElement("canvas"); log("Attempting to generate scaled version for " + sourceFile.name); - imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient, customResizeFunction: customResizeFunction}).then(function() { - var scaledImageDataUri = canvas.toDataURL(type, quality), - signalSuccess = function() { - log("Success generating scaled version for " + sourceFile.name); - var blob = qq.dataUriToBlob(scaledImageDataUri); - scalingEffort.success(blob); - }; - - if (includeExif) { - self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) { - scaledImageDataUri = scaledImageDataUriWithExif; - signalSuccess(); - }, - function() { - log("Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.", "error"); + return new Promise(function(resolve, reject) { + imageGenerator.generate(sourceFile, canvas, {maxSize: maxSize, orient: orient, customResizeFunction: customResizeFunction}).then(function() { + var scaledImageDataUri = canvas.toDataURL(type, quality), + signalSuccess = function() { + log("Success generating scaled version for " + sourceFile.name); + var blob = qq.dataUriToBlob(scaledImageDataUri); + resolve(blob); + }; + + if (includeExif) { + self._insertExifHeader(sourceFile, scaledImageDataUri, log).then(function(scaledImageDataUriWithExif) { + scaledImageDataUri = scaledImageDataUriWithExif; + signalSuccess(); + }, + function() { + log("Problem inserting EXIF header into scaled image. Using scaled image w/out EXIF data.", "error"); + signalSuccess(); + }); + } + else { signalSuccess(); - }); - } - else { - signalSuccess(); - } - }, function() { - log("Failed attempt to generate scaled version for " + sourceFile.name, "error"); - scalingEffort.failure(failedText); + } + }, function() { + log("Failed attempt to generate scaled version for " + sourceFile.name, "error"); + reject(new Error(failedText)); + }); }); - - return scalingEffort; }, // Attempt to insert the original image's EXIF header into a scaled version. From 5d7c393b662e645d17290ac649b4f451470e3d6a Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Sun, 25 Mar 2018 23:00:15 +1100 Subject: [PATCH 13/73] refactor: qq.Scalar._insertExifHeader to use Promise --- client/js/image-support/scaler.js | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/client/js/image-support/scaler.js b/client/js/image-support/scaler.js index 0159c10f1..2ebddfa29 100644 --- a/client/js/image-support/scaler.js +++ b/client/js/image-support/scaler.js @@ -339,22 +339,21 @@ qq.extend(qq.Scaler.prototype, { "use strict"; var reader = new FileReader(), - insertionEffort = new qq.Promise(), originalImageDataUri = ""; - reader.onload = function() { - originalImageDataUri = reader.result; - insertionEffort.success(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri)); - }; + return new Promise(function (resolve, reject) { + reader.onload = function() { + originalImageDataUri = reader.result; + resolve(qq.ExifRestorer.restore(originalImageDataUri, scaledImageDataUri)); + }; - reader.onerror = function() { - log("Problem reading " + originalImage.name + " during attempt to transfer EXIF data to scaled version.", "error"); - insertionEffort.failure(); - }; - - reader.readAsDataURL(originalImage); + reader.onerror = function() { + log("Problem reading " + originalImage.name + " during attempt to transfer EXIF data to scaled version.", "error"); + reject(); + }; - return insertionEffort; + reader.readAsDataURL(originalImage); + }); }, _dataUriToBlob: function(dataUri) { From e7ef8b3efc27f857d1eea32c375242bcf1c2275f Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Sun, 25 Mar 2018 23:02:41 +1100 Subject: [PATCH 14/73] refactor: renderImageToDataURL to use Promise --- client/js/image-support/megapix-image.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/client/js/image-support/megapix-image.js b/client/js/image-support/megapix-image.js index 4cdfef596..69f965392 100644 --- a/client/js/image-support/megapix-image.js +++ b/client/js/image-support/megapix-image.js @@ -74,17 +74,16 @@ */ function renderImageToDataURL(img, blob, options, doSquash) { var canvas = document.createElement("canvas"), - mime = options.mime || "image/jpeg", - promise = new qq.Promise(); - - renderImageToCanvas(img, blob, canvas, options, doSquash) - .then(function() { - promise.success( - canvas.toDataURL(mime, options.quality || 0.8) - ); - }); - - return promise; + mime = options.mime || "image/jpeg"; + + return new Promise(function(resolve) { + renderImageToCanvas(img, blob, canvas, options, doSquash) + .then(function() { + resolve( + canvas.toDataURL(mime, options.quality || 0.8) + ); + }); + }); } function maybeCalculateDownsampledDimensions(spec) { From 5a2b3921325a40681a0c99766f948be5d804f4be Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Sun, 25 Mar 2018 23:06:07 +1100 Subject: [PATCH 15/73] refactor: renderImageToCanvasWithCustomResizer to use Promise --- client/js/image-support/megapix-image.js | 35 ++++++++++++------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/client/js/image-support/megapix-image.js b/client/js/image-support/megapix-image.js index 69f965392..57aa9aea8 100644 --- a/client/js/image-support/megapix-image.js +++ b/client/js/image-support/megapix-image.js @@ -201,7 +201,6 @@ imageHeight = resizeInfo.imageHeight, imageWidth = resizeInfo.imageWidth, orientation = resizeInfo.orientation, - promise = new qq.Promise(), resize = resizeInfo.resize, sourceCanvas = document.createElement("canvas"), sourceCanvasContext = sourceCanvas.getContext("2d"), @@ -216,23 +215,23 @@ sourceCanvasContext.drawImage(image, 0, 0); - resize({ - blob: blob, - height: targetHeight, - image: image, - sourceCanvas: sourceCanvas, - targetCanvas: targetCanvas, - width: targetWidth - }) - .then( - function success() { - targetCanvas.qqImageRendered && targetCanvas.qqImageRendered(); - promise.success(); - }, - promise.failure - ); - - return promise; + return new Promise(function(resolve, reject) { + resize({ + blob: blob, + height: targetHeight, + image: image, + sourceCanvas: sourceCanvas, + targetCanvas: targetCanvas, + width: targetWidth + }) + .then( + function success() { + targetCanvas.qqImageRendered && targetCanvas.qqImageRendered(); + resolve(); + }, + reject + ); + }); } /** From ed1dbe775b6792a851bac9407ed80a726244538e Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 11:01:44 +1100 Subject: [PATCH 16/73] refactor: uploadChunk and uploadFile to use Promise --- client/js/azure/azure.xhr.upload.handler.js | 156 +-- client/js/azure/get-sas.js | 38 +- client/js/azure/uploader.basic.js | 6 +- client/js/s3/s3.form.upload.handler.js | 65 +- client/js/s3/s3.xhr.upload.handler.js | 44 +- .../traditional.xhr.upload.handler.js | 32 +- .../upload.handler.controller.js | 24 +- test/unit/azure/delete-files.js | 24 +- test/unit/azure/simple-file-uploads.js | 66 +- test/unit/chunked-uploads.js | 22 +- test/unit/s3/cdn/generic-chunked.js | 50 +- test/unit/s3/cdn/generic-non-chunked.js | 10 +- test/unit/s3/chunked-uploads.js | 907 +++++++++--------- test/unit/s3/simple-file-uploads.js | 70 +- test/unit/set-status.js | 36 +- 15 files changed, 845 insertions(+), 705 deletions(-) diff --git a/client/js/azure/azure.xhr.upload.handler.js b/client/js/azure/azure.xhr.upload.handler.js index cf6300ffa..6143456f4 100644 --- a/client/js/azure/azure.xhr.upload.handler.js +++ b/client/js/azure/azure.xhr.upload.handler.js @@ -99,33 +99,32 @@ qq.azure.XhrUploadHandler = function(spec, proxy) { } function getSignedUrl(id, optChunkIdx) { - // We may have multiple SAS requests in progress for the same file, so we must include the chunk idx - // as part of the ID when communicating with the SAS ajax requester to avoid collisions. - var getSasId = optChunkIdx == null ? id : id + "." + optChunkIdx, - - promise = new qq.Promise(), - getSasSuccess = function(sasUri) { - log("GET SAS request succeeded."); - promise.success(sasUri); - }, - getSasFailure = function(reason, getSasXhr) { - log("GET SAS request failed: " + reason, "error"); - promise.failure({error: "Problem communicating with local server"}, getSasXhr); - }, - determineBlobUrlSuccess = function(blobUrl) { - api.getSasForPutBlobOrBlock.request(getSasId, blobUrl).then( - getSasSuccess, - getSasFailure - ); - }, - determineBlobUrlFailure = function(reason) { - log(qq.format("Failed to determine blob name for ID {} - {}", id, reason), "error"); - promise.failure({error: reason}); - }; - - determineBlobUrl(id).then(determineBlobUrlSuccess, determineBlobUrlFailure); + return new Promise(function(resolve, reject) { + // We may have multiple SAS requests in progress for the same file, so we must include the chunk idx + // as part of the ID when communicating with the SAS ajax requester to avoid collisions. + var getSasId = optChunkIdx == null ? id : id + "." + optChunkIdx, + getSasSuccess = function(sasUri) { + log("GET SAS request succeeded."); + resolve(sasUri); + }, + getSasFailure = function(error) { + log("GET SAS request failed: " + error.message, "error"); + reject(error); + }, + determineBlobUrlSuccess = function(blobUrl) { + api.getSasForPutBlobOrBlock.request(getSasId, blobUrl).then( + getSasSuccess, + getSasFailure + ); + }, + determineBlobUrlFailure = function(reason) { + var error = new Error(reason); + log(qq.format("Failed to determine blob name for ID {} - {}", id, reason), "error"); + reject(error); + }; - return promise; + determineBlobUrl(id).then(determineBlobUrlSuccess, determineBlobUrlFailure); + }); } function handleFailure(xhr, promise) { @@ -138,68 +137,75 @@ qq.azure.XhrUploadHandler = function(spec, proxy) { }); } + function buildError(xhr) { + var azureError = qq.azure.util.parseAzureError(xhr.responseText, log), + errorMsg = "Problem sending file to Azure", + error = new Error(errorMsg); + + error.azureError = azureError && azureError.message; + error.reset = xhr.status === 403; + + return error; + } + qq.extend(this, { uploadChunk: function(params) { var chunkIdx = params.chunkIdx; var id = params.id; - var promise = new qq.Promise(); + return new Promise(function(resolve, reject) { + getSignedUrl(id, chunkIdx).then( + function(sasUri) { + var xhr = handler._createXhr(id, chunkIdx), + chunkData = handler._getChunkData(id, chunkIdx); + + handler._registerProgressHandler(id, chunkIdx, chunkData.size); + handler._registerXhr(id, chunkIdx, xhr, api.putBlock); + + // We may have multiple put block requests in progress for the same file, so we must include the chunk idx + // as part of the ID when communicating with the put block ajax requester to avoid collisions. + api.putBlock.upload(id + "." + chunkIdx, xhr, sasUri, chunkIdx, chunkData.blob).then( + function(blockIdEntry) { + if (!handler._getPersistableData(id).blockIdEntries) { + handler._getPersistableData(id).blockIdEntries = []; + } + + handler._getPersistableData(id).blockIdEntries.push(blockIdEntry); + log("Put Block call succeeded for " + id); + resolve({response: {}, xhr: xhr}); + }, + function() { + log(qq.format("Put Block call failed for ID {} on part {}", id, chunkIdx), "error"); + reject(buildError(xhr)); + } + ); + }, + reject + ); + }); + }, - getSignedUrl(id, chunkIdx).then( - function(sasUri) { - var xhr = handler._createXhr(id, chunkIdx), - chunkData = handler._getChunkData(id, chunkIdx); + uploadFile: function(id) { + var fileOrBlob = handler.getFile(id); - handler._registerProgressHandler(id, chunkIdx, chunkData.size); - handler._registerXhr(id, chunkIdx, xhr, api.putBlock); + return new Promise(function(resolve, reject) { + getSignedUrl(id).then(function(sasUri) { + var xhr = handler._createXhr(id); - // We may have multiple put block requests in progress for the same file, so we must include the chunk idx - // as part of the ID when communicating with the put block ajax requester to avoid collisions. - api.putBlock.upload(id + "." + chunkIdx, xhr, sasUri, chunkIdx, chunkData.blob).then( - function(blockIdEntry) { - if (!handler._getPersistableData(id).blockIdEntries) { - handler._getPersistableData(id).blockIdEntries = []; - } + handler._registerProgressHandler(id); - handler._getPersistableData(id).blockIdEntries.push(blockIdEntry); - log("Put Block call succeeded for " + id); - promise.success({}, xhr); + api.putBlob.upload(id, xhr, sasUri, fileOrBlob).then( + function() { + log("Put Blob call succeeded for " + id); + resolve({response: {}, xhr: xhr}); }, function() { - log(qq.format("Put Block call failed for ID {} on part {}", id, chunkIdx), "error"); - handleFailure(xhr, promise); + log("Put Blob call failed for " + id, "error"); + reject(buildError(xhr)); } ); - }, - promise.failure - ); - - return promise; - }, - - uploadFile: function(id) { - var promise = new qq.Promise(), - fileOrBlob = handler.getFile(id); - - getSignedUrl(id).then(function(sasUri) { - var xhr = handler._createXhr(id); - - handler._registerProgressHandler(id); - - api.putBlob.upload(id, xhr, sasUri, fileOrBlob).then( - function() { - log("Put Blob call succeeded for " + id); - promise.success({}, xhr); - }, - function() { - log("Put Blob call failed for " + id, "error"); - handleFailure(xhr, promise); - } - ); - }, - promise.failure); - - return promise; + }, reject); + }); } }); diff --git a/client/js/azure/get-sas.js b/client/js/azure/get-sas.js index 68046d095..1cf8c51a0 100644 --- a/client/js/azure/get-sas.js +++ b/client/js/azure/get-sas.js @@ -22,17 +22,22 @@ qq.azure.GetSas = function(o) { qq.extend(options, o); function sasResponseReceived(id, xhr, isError) { - var promise = requestPromises[id]; + var promise = requestPromises[id], + error; if (isError) { - promise.failure("Received response code " + xhr.status, xhr); + error = new Error("Received response code " + xhr.status); + error.xhr = xhr; + promise.reject(error); } else { if (xhr.responseText.length) { - promise.success(xhr.responseText); + promise.resolve(xhr.responseText); } else { - promise.failure("Empty response.", xhr); + error = new Error("Empty response."); + error.xhr = xhr; + promise.reject(error); } } @@ -56,22 +61,21 @@ qq.azure.GetSas = function(o) { qq.extend(this, { request: function(id, blobUri) { - var requestPromise = new qq.Promise(), - restVerb = options.restRequestVerb; + return new Promise(function(resolve, reject) { + var restVerb = options.restRequestVerb; - options.log(qq.format("Submitting GET SAS request for a {} REST request related to file ID {}.", restVerb, id)); + options.log(qq.format("Submitting GET SAS request for a {} REST request related to file ID {}.", restVerb, id)); - requestPromises[id] = requestPromise; + requestPromises[id] = {resolve: resolve, reject: reject}; - requester.initTransport(id) - .withParams({ - bloburi: blobUri, - _method: restVerb - }) - .withCacheBuster() - .send(); - - return requestPromise; + requester.initTransport(id) + .withParams({ + bloburi: blobUri, + _method: restVerb + }) + .withCacheBuster() + .send(); + }); } }); }; diff --git a/client/js/azure/uploader.basic.js b/client/js/azure/uploader.basic.js index 8952c47bf..66eb06d31 100644 --- a/client/js/azure/uploader.basic.js +++ b/client/js/azure/uploader.basic.js @@ -153,14 +153,14 @@ deleteBlobSasUri[id] = sasUri; deleteBlob.send(id); }, - getSasFailure = function(id, reason, xhr) { + getSasFailure = function(id, error) { if (relatedToCancel) { self.log("Will cancel upload, but cannot remove uncommitted parts from Azure due to issue retrieving SAS", "error"); qq.FineUploaderBasic.prototype._onCancel.call(self, id, self.getName(id)); } else { - self._onDeleteComplete(id, xhr, true); - self._options.callbacks.onDeleteComplete(id, xhr, true); + self._onDeleteComplete(id, error.xhr, true); + self._options.callbacks.onDeleteComplete(id, error.xhr, true); } }, deleteBlob = new qq.azure.DeleteBlob({ diff --git a/client/js/s3/s3.form.upload.handler.js b/client/js/s3/s3.form.upload.handler.js index 75bbb4afa..70c95867f 100644 --- a/client/js/s3/s3.form.upload.handler.js +++ b/client/js/s3/s3.form.upload.handler.js @@ -202,37 +202,48 @@ qq.s3.FormUploadHandler = function(options, proxy) { qq.extend(this, { uploadFile: function(id) { - var name = getName(id), - promise = new qq.Promise(); - - if (handler.getThirdPartyFileId(id)) { - if (handler._getFileState(id).bucket) { - handleUpload(id).then(promise.success, promise.failure); + var name = getName(id); + + return new Promise(function(resolve, reject) { + if (handler.getThirdPartyFileId(id)) { + if (handler._getFileState(id).bucket) { + handleUpload(id).then(resolve, function (response) { + var error = new Error("Upload failed"); + error.response = response; + reject(error); + }); + } + else { + onGetBucket(id).then(function(bucket) { + handler._getFileState(id).bucket = bucket; + handleUpload(id).then(resolve, function (response) { + var error = new Error("Upload failed"); + error.response = response; + reject(error); + }); + }); + } } else { - onGetBucket(id).then(function(bucket) { - handler._getFileState(id).bucket = bucket; - handleUpload(id).then(promise.success, promise.failure); - }); - } - } - else { - // The S3 uploader module will either calculate the key or ask the server for it - // and will call us back once it is known. - onGetKeyName(id, name).then(function(key) { - onGetBucket(id).then(function(bucket) { - handler._getFileState(id).bucket = bucket; - handler._setThirdPartyFileId(id, key); - handleUpload(id).then(promise.success, promise.failure); + // The S3 uploader module will either calculate the key or ask the server for it + // and will call us back once it is known. + onGetKeyName(id, name).then(function(key) { + onGetBucket(id).then(function(bucket) { + handler._getFileState(id).bucket = bucket; + handler._setThirdPartyFileId(id, key); + handleUpload(id).then(resolve, function (response) { + var error = new Error("Upload failed"); + error.response = response; + reject(error); + }); + }, function(errorReason) { + reject(new Promise(errorReason)); + }); }, function(errorReason) { - promise.failure({error: errorReason}); + reject(new Promise(errorReason)); }); - }, function(errorReason) { - promise.failure({error: errorReason}); - }); - } - - return promise; + } + }); } }); }; diff --git a/client/js/s3/s3.xhr.upload.handler.js b/client/js/s3/s3.xhr.upload.handler.js index 37c011a7a..458ca7db8 100755 --- a/client/js/s3/s3.xhr.upload.handler.js +++ b/client/js/s3/s3.xhr.upload.handler.js @@ -542,26 +542,36 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { var id = params.id; var optChunkIdx = params.chunkIdx; - var promise = new qq.Promise(); - - upload.key.promise(id).then(function() { - upload.bucket.promise(id).then(function() { - upload.host.promise(id).then(function() { - /* jshint eqnull:true */ - if (optChunkIdx == null) { - simple.send(id).then(promise.success, promise.failure); - } - else { - chunked.send(id, optChunkIdx).then(promise.success, promise.failure); - } + return new Promise(function(resolve, reject) { + upload.key.promise(id).then(function() { + upload.bucket.promise(id).then(function() { + upload.host.promise(id).then(function() { + /* jshint eqnull:true */ + if (optChunkIdx == null) { + simple.send(id).then(function(response, xhr) { + resolve({response: response, xhr: xhr}); + }, function(errorObject, xhr) { + var error = new Error(errorObject.error); + error.xhr = xhr; + reject(error); + }); + } + else { + chunked.send(id, optChunkIdx).then(function(response, xhr) { + resolve({response: response, xhr: xhr}); + }, function(errorObject, xhr) { + var error = new Error(errorObject.error); + error.xhr = xhr; + reject(error); + }); + } + }); }); + }, + function(errorReason) { + reject(new Error(errorReason)); }); - }, - function(errorReason) { - promise.failure({error: errorReason}); }); - - return promise; }, track: function(id, xhr, optChunkIdx) { diff --git a/client/js/traditional/traditional.xhr.upload.handler.js b/client/js/traditional/traditional.xhr.upload.handler.js index b09dad327..b88972e26 100644 --- a/client/js/traditional/traditional.xhr.upload.handler.js +++ b/client/js/traditional/traditional.xhr.upload.handler.js @@ -49,22 +49,24 @@ qq.traditional.XhrUploadHandler = function(spec, proxy) { }), createReadyStateChangedHandler = function(id, xhr) { - var promise = new qq.Promise(); - - xhr.onreadystatechange = function() { - if (xhr.readyState === 4) { - var result = onUploadOrChunkComplete(id, xhr); - - if (result.success) { - promise.success(result.response, xhr); + return new Promise(function(resolve, reject) { + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + var result = onUploadOrChunkComplete(id, xhr), + error; + + if (result.success) { + resolve({response: result.response, xhr: xhr}); + } + else { + error = new Error(); + error.response = result.response; + error.xhr = xhr; + reject(error); + } } - else { - promise.failure(result.response, xhr); - } - } - }; - - return promise; + }; + }); }, getChunksCompleteParams = function(id) { diff --git a/client/js/upload-handler/upload.handler.controller.js b/client/js/upload-handler/upload.handler.controller.js index 42facef4f..aa0819554 100644 --- a/client/js/upload-handler/upload.handler.controller.js +++ b/client/js/upload-handler/upload.handler.controller.js @@ -231,7 +231,9 @@ qq.UploadHandlerController = function(o, namespace) { handler.uploadChunk(uploadChunkData).then( // upload chunk success - function success(response, xhr) { + function success(info) { + var response = info.response, + xhr = info.xhr; log("Chunked upload request succeeded for " + id + ", chunk " + chunkIdx); handler.clearCachedChunk(id, chunkIdx); @@ -259,16 +261,17 @@ qq.UploadHandlerController = function(o, namespace) { else { log(qq.format("File ID {} has no more chunks to send and these chunk indexes are still marked as in-progress: {}", id, JSON.stringify(inProgressChunks))); } + handler.clearXhr(id, chunkIdx); }, // upload chunk failure - function failure(response, xhr) { + function failure(error) { + var response = error.response, + xhr = error.xhr; chunked.handleFailure(chunkIdx, id, response, xhr); - } - ) - .done(function () { handler.clearXhr(id, chunkIdx); - }); + } + ); } }, @@ -395,7 +398,9 @@ qq.UploadHandlerController = function(o, namespace) { log("Sending simple upload request for " + id); handler.uploadFile(id).then( - function(response, optXhr) { + function(info) { + var response = info.response, + optXhr = info.xhr; log("Simple upload request succeeded for " + id); var responseToReport = upload.normalizeResponse(response, true), @@ -406,10 +411,11 @@ qq.UploadHandlerController = function(o, namespace) { upload.cleanup(id, responseToReport, optXhr); }, - function(response, optXhr) { + function(error) { + var optXhr = error.xhr; log("Simple upload request failed for " + id); - var responseToReport = upload.normalizeResponse(response, false); + var responseToReport = upload.normalizeResponse({ error: error.message, azureError: error.azureError }, false); if (!options.onAutoRetry(id, name, responseToReport, optXhr)) { upload.cleanup(id, responseToReport, optXhr); diff --git a/test/unit/azure/delete-files.js b/test/unit/azure/delete-files.js index 391f47ba4..167550701 100644 --- a/test/unit/azure/delete-files.js +++ b/test/unit/azure/delete-files.js @@ -87,16 +87,20 @@ if (qqtest.canDownloadFileAsBlob) { deleteFileSignatureRequest.respond(200, null, "http://sasuri.com"); - assert.equal(fileTestHelper.getRequests().length, 4); - deleteFileRequest = fileTestHelper.getRequests()[3]; + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 4); + deleteFileRequest = fileTestHelper.getRequests()[3]; - assert.equal(deleteFileRequest.method, "DELETE"); - assert.equal(deleteFileRequest.url, "http://sasuri.com"); + assert.equal(deleteFileRequest.method, "DELETE"); + assert.equal(deleteFileRequest.url, "http://sasuri.com"); - deleteFileRequest.respond(202, null, null); + deleteFileRequest.respond(202, null, null); - assert.equal(uploader.getUploads()[0].status, qq.status.DELETED); - assert.deepEqual(actualCallbackOrder, expectedCallbackOrder); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.DELETED); + assert.deepEqual(actualCallbackOrder, expectedCallbackOrder); + }, 0); + }, 0); }); }); @@ -126,8 +130,10 @@ if (qqtest.canDownloadFileAsBlob) { deleteFileSignatureRequest = fileTestHelper.getRequests()[2]; deleteFileSignatureRequest.respond(500, null, null); - assert.equal(fileTestHelper.getRequests().length, 3); - assert.equal(uploader.getUploads()[0].status, qq.status.DELETE_FAILED); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 3); + assert.equal(uploader.getUploads()[0].status, qq.status.DELETE_FAILED); + }, 0); }); }); diff --git a/test/unit/azure/simple-file-uploads.js b/test/unit/azure/simple-file-uploads.js index 172a6cd01..1d4a7a9b4 100644 --- a/test/unit/azure/simple-file-uploads.js +++ b/test/unit/azure/simple-file-uploads.js @@ -320,24 +320,28 @@ if (qqtest.canDownloadFileAsBlob) { var uploadRequest = fileTestHelper.getRequests()[1]; uploadRequest.respond(201, null, ""); - assert.equal(fileTestHelper.getRequests().length, 3, "Wrong # of requests"); - uploadSuccessRequest = fileTestHelper.getRequests()[2]; - - uploadSuccessRequestParsedBody = purl("http://test.com?" + uploadSuccessRequest.requestBody).param(); - assert.equal(uploadSuccessRequest.url, uploadSuccessUrl); - assert.equal(uploadSuccessRequest.method, "POST"); - assert.equal(uploadSuccessRequest.requestHeaders["Content-Type"].indexOf("application/x-www-form-urlencoded"), 0); - assert.equal(uploadSuccessRequest.requestHeaders["test-header-name"], uploadSuccessHeaders["test-header-name"]); - assert.equal(uploadSuccessRequestParsedBody["test-param-name"], uploadSuccessParams["test-param-name"]); - assert.equal(uploadSuccessRequestParsedBody.foo, "bar"); - assert.equal(uploadSuccessRequestParsedBody.blob, uploader.getBlobName(0)); - assert.equal(uploadSuccessRequestParsedBody.uuid, uploader.getUuid(0)); - assert.equal(uploadSuccessRequestParsedBody.name, uploader.getName(0)); - assert.equal(uploadSuccessRequestParsedBody.container, testEndpoint); - - uploadSuccessRequest.respond(200, null, null); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 3, "Wrong # of requests"); + uploadSuccessRequest = fileTestHelper.getRequests()[2]; + + uploadSuccessRequestParsedBody = purl("http://test.com?" + uploadSuccessRequest.requestBody).param(); + assert.equal(uploadSuccessRequest.url, uploadSuccessUrl); + assert.equal(uploadSuccessRequest.method, "POST"); + assert.equal(uploadSuccessRequest.requestHeaders["Content-Type"].indexOf("application/x-www-form-urlencoded"), 0); + assert.equal(uploadSuccessRequest.requestHeaders["test-header-name"], uploadSuccessHeaders["test-header-name"]); + assert.equal(uploadSuccessRequestParsedBody["test-param-name"], uploadSuccessParams["test-param-name"]); + assert.equal(uploadSuccessRequestParsedBody.foo, "bar"); + assert.equal(uploadSuccessRequestParsedBody.blob, uploader.getBlobName(0)); + assert.equal(uploadSuccessRequestParsedBody.uuid, uploader.getUuid(0)); + assert.equal(uploadSuccessRequestParsedBody.name, uploader.getName(0)); + assert.equal(uploadSuccessRequestParsedBody.container, testEndpoint); + + uploadSuccessRequest.respond(200, null, null); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + done(); + }, 0); + }, 0); }, 0); }); @@ -365,10 +369,14 @@ if (qqtest.canDownloadFileAsBlob) { var uploadRequest = fileTestHelper.getRequests()[1]; uploadRequest.respond(201, null, ""); - uploadSuccessRequest = fileTestHelper.getRequests()[2]; - assert.equal(uploadSuccessRequest.url, uploadSuccessUrl); - uploadSuccessRequest.respond(200, null, JSON.stringify({success: false})); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + setTimeout(function() { + uploadSuccessRequest = fileTestHelper.getRequests()[2]; + assert.equal(uploadSuccessRequest.url, uploadSuccessUrl); + uploadSuccessRequest.respond(200, null, JSON.stringify({success: false})); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + }, 0); + }, 0); }, 0); }); @@ -394,11 +402,15 @@ if (qqtest.canDownloadFileAsBlob) { var uploadRequest = fileTestHelper.getRequests()[1]; uploadRequest.respond(201, null, ""); - uploadSuccessRequest = fileTestHelper.getRequests()[2]; - assert.equal(uploadSuccessRequest.method, "PATCH"); - uploadSuccessRequest.respond(200, null, null); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + setTimeout(function() { + uploadSuccessRequest = fileTestHelper.getRequests()[2]; + assert.equal(uploadSuccessRequest.method, "PATCH"); + uploadSuccessRequest.respond(200, null, null); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + done(); + }, 0); + }, 0); }, 0); }); diff --git a/test/unit/chunked-uploads.js b/test/unit/chunked-uploads.js index fea74feff..528d55ed6 100644 --- a/test/unit/chunked-uploads.js +++ b/test/unit/chunked-uploads.js @@ -396,6 +396,10 @@ if (qqtest.canDownloadFileAsBlob) { }); describe("resume records", function() { + beforeEach(function() { + window.localStorage.clear(); + }); + var uploader; function testResumeRecordsLogic(onUploadChunkSuccess, customKeys) { @@ -410,7 +414,7 @@ if (qqtest.canDownloadFileAsBlob) { chunking: { enabled: true, mandatory: true, - partSize: expectedFileSize / 3 + partSize: Math.floor(expectedFileSize / 3) }, callbacks: { onUploadChunk: function() { @@ -522,8 +526,12 @@ if (qqtest.canDownloadFileAsBlob) { qqtest.downloadFileAsBlob("up.jpg", "image/jpeg").then(function (blob) { fileTestHelper.mockXhr(); uploader.addFiles({name: "test", blob: blob}); - fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); - fileTestHelper.getRequests()[1].respond(200); + setTimeout(function() { + fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + setTimeout(function() { + fileTestHelper.getRequests()[1].respond(200); + }, 0); + }, 0); }); } @@ -657,8 +665,12 @@ if (qqtest.canDownloadFileAsBlob) { qqtest.downloadFileAsBlob("up.jpg", "image/jpeg").then(function (blob) { fileTestHelper.mockXhr(); uploader.addFiles({name: "test", blob: blob}); - fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); - fileTestHelper.getRequests()[1].respond(chunkingSuccessStatus); + setTimeout(function() { + fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + setTimeout(function() { + fileTestHelper.getRequests()[1].respond(chunkingSuccessStatus); + }, 0); + }, 0); }); } diff --git a/test/unit/s3/cdn/generic-chunked.js b/test/unit/s3/cdn/generic-chunked.js index 39edab3ef..c4781edba 100644 --- a/test/unit/s3/cdn/generic-chunked.js +++ b/test/unit/s3/cdn/generic-chunked.js @@ -56,29 +56,33 @@ if (qqtest.canDownloadFileAsBlob) { uploadPartRequest = fileTestHelper.getRequests()[2]; uploadPartRequest.respond(200, {ETag: "etag1"}, null); - // signature request for upload part 2 - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[4]; - uploadPartRequest.respond(200, {ETag: "etag2"}, null); - - // signature request for multipart complete - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // multipart complete request - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - multipartCompleteRequest.respond(200, null, "mybucket" + uploader.getKey(0) + ""); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - - done(); + setTimeout(function() { + // signature request for upload part 2 + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[4]; + uploadPartRequest.respond(200, {ETag: "etag2"}, null); + + setTimeout(function() { + // signature request for multipart complete + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // multipart complete request + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + multipartCompleteRequest.respond(200, null, "mybucket" + uploader.getKey(0) + ""); + + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + + done(); + }, 0); + }, 0); }); }, testSignatureEndoint = "/signature", diff --git a/test/unit/s3/cdn/generic-non-chunked.js b/test/unit/s3/cdn/generic-non-chunked.js index ef7b5e67e..33a881b64 100644 --- a/test/unit/s3/cdn/generic-non-chunked.js +++ b/test/unit/s3/cdn/generic-non-chunked.js @@ -43,11 +43,13 @@ if (qqtest.canDownloadFileAsBlob) { uploadRequest.respond(200, {ETag: "123"}, null); - uploadSuccessRequest = fileTestHelper.getRequests()[2]; - uploadSuccessRequestParsedBody = purl("http://test.com?" + uploadSuccessRequest.requestBody).param(); - assert.equal(uploadSuccessRequestParsedBody.bucket, "mybucket"); + setTimeout(function () { + uploadSuccessRequest = fileTestHelper.getRequests()[2]; + uploadSuccessRequestParsedBody = purl("http://test.com?" + uploadSuccessRequest.requestBody).param(); + assert.equal(uploadSuccessRequestParsedBody.bucket, "mybucket"); - done(); + done(); + }, 0); }, 10); }, 10); }); diff --git a/test/unit/s3/chunked-uploads.js b/test/unit/s3/chunked-uploads.js index 14664c53a..63566d6f7 100644 --- a/test/unit/s3/chunked-uploads.js +++ b/test/unit/s3/chunked-uploads.js @@ -122,73 +122,44 @@ if (qqtest.canDownloadFileAsBlob) { assert.ok(initiateToSign.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - // initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 2); - initiateRequest = fileTestHelper.getRequests()[1]; - assert.equal(initiateRequest.method, "POST"); - assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); - assert.equal(initiateRequest.requestHeaders["x-amz-meta-qqfilename"], uploader.getName(0)); - assert.equal(initiateRequest.requestHeaders["x-amz-acl"], "private"); - assert.ok(initiateRequest.requestHeaders["x-amz-date"]); - assert.equal(initiateRequest.requestHeaders.Authorization.indexOf("AWS4-HMAC-SHA256 Credential=testAccessKey/"), 0); - var authParts = initiateRequest.requestHeaders.Authorization.split(";"); - assert.equal(authParts.length, 5); - assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); - assert.equal(authParts[1], "x-amz-acl"); - assert.equal(authParts[2], "x-amz-content-sha256"); - assert.equal(authParts[3], "x-amz-date"); - assert.equal(authParts[4], "x-amz-meta-qqfilename,Signature=thesignature"); - initiateRequest.respond(200, null, "123"); - - setTimeout(function() { - // signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 4); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; - assert.equal(uploadPartSignatureRequest1.method, "POST"); - assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint + "?v4=true"); - assert.equal(uploadPartSignatureRequest1.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers); - assert.equal(uploadPartToSign1.headers.indexOf("AWS4-HMAC-SHA256"), 0); - assert.ok(uploadPartToSign1.headers.indexOf("/us-east-1/s3/aws4_request") > 0); - assert.equal(uploadPartToSign1.headers.split("\n").length, 12); - assert.ok(uploadPartToSign1.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // upload part 1 request - uploadPartRequest = fileTestHelper.getRequests()[2]; - assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); - - assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); - - var authParts = uploadPartRequest.requestHeaders.Authorization.split(";"); - assert.equal(authParts.length, 3); + setTimeout(function() { + // initiate multipart upload request + assert.equal(fileTestHelper.getRequests().length, 2); + initiateRequest = fileTestHelper.getRequests()[1]; + assert.equal(initiateRequest.method, "POST"); + assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); + assert.equal(initiateRequest.requestHeaders["x-amz-meta-qqfilename"], uploader.getName(0)); + assert.equal(initiateRequest.requestHeaders["x-amz-acl"], "private"); + assert.ok(initiateRequest.requestHeaders["x-amz-date"]); + assert.equal(initiateRequest.requestHeaders.Authorization.indexOf("AWS4-HMAC-SHA256 Credential=testAccessKey/"), 0); + var authParts = initiateRequest.requestHeaders.Authorization.split(";"); + assert.equal(authParts.length, 5); assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); - assert.equal(authParts[1], "x-amz-content-sha256"); - assert.equal(authParts[2], "x-amz-date,Signature=thesignature"); - uploadPartRequest.respond(200, {ETag: "etag1"}, null); + assert.equal(authParts[1], "x-amz-acl"); + assert.equal(authParts[2], "x-amz-content-sha256"); + assert.equal(authParts[3], "x-amz-date"); + assert.equal(authParts[4], "x-amz-meta-qqfilename,Signature=thesignature"); + initiateRequest.respond(200, null, "123"); setTimeout(function() { - // signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 6); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; - assert.equal(uploadPartSignatureRequest2.method, "POST"); - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint + "?v4=true"); - assert.equal(uploadPartSignatureRequest2.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers); - assert.equal(uploadPartToSign2.headers.indexOf("AWS4-HMAC-SHA256"), 0); - assert.ok(uploadPartToSign2.headers.indexOf("/us-east-1/s3/aws4_request") > 0); - assert.equal(uploadPartToSign2.headers.split("\n").length, 12); - assert.ok(uploadPartToSign2.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[4]; + // signature request for upload part 1 + assert.equal(fileTestHelper.getRequests().length, 4); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; + assert.equal(uploadPartSignatureRequest1.method, "POST"); + assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint + "?v4=true"); + assert.equal(uploadPartSignatureRequest1.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers); + assert.equal(uploadPartToSign1.headers.indexOf("AWS4-HMAC-SHA256"), 0); + assert.ok(uploadPartToSign1.headers.indexOf("/us-east-1/s3/aws4_request") > 0); + assert.equal(uploadPartToSign1.headers.split("\n").length, 12); + assert.ok(uploadPartToSign1.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // upload part 1 request + uploadPartRequest = fileTestHelper.getRequests()[2]; assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); @@ -198,48 +169,82 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); assert.equal(authParts[1], "x-amz-content-sha256"); assert.equal(authParts[2], "x-amz-date,Signature=thesignature"); - uploadPartRequest.respond(200, {ETag: "etag2"}, null); - - // signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 7); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; - assert.equal(uploadCompleteSignatureRequest.method, "POST"); - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint + "?v4=true"); - assert.equal(uploadCompleteSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers); - assert.equal(uploadCompleteToSign.headers.indexOf("AWS4-HMAC-SHA256"), 0); - assert.ok(uploadCompleteToSign.headers.indexOf("/us-east-1/s3/aws4_request") > 0); - assert.equal(uploadCompleteToSign.headers.split("\n").length, 12); - assert.ok(uploadCompleteToSign.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // multipart complete request - assert.equal(fileTestHelper.getRequests().length, 8); - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - assert.equal(multipartCompleteRequest.method, "POST"); - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); - - authParts = multipartCompleteRequest.requestHeaders.Authorization.split(";"); - assert.equal(authParts.length, 3); - assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); - assert.equal(authParts[1], "x-amz-content-sha256"); - assert.equal(authParts[2], "x-amz-date,Signature=thesignature"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - - done(); + uploadPartRequest.respond(200, {ETag: "etag1"}, null); + + setTimeout(function() { + // signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 6); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; + assert.equal(uploadPartSignatureRequest2.method, "POST"); + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint + "?v4=true"); + assert.equal(uploadPartSignatureRequest2.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers); + assert.equal(uploadPartToSign2.headers.indexOf("AWS4-HMAC-SHA256"), 0); + assert.ok(uploadPartToSign2.headers.indexOf("/us-east-1/s3/aws4_request") > 0); + assert.equal(uploadPartToSign2.headers.split("\n").length, 12); + assert.ok(uploadPartToSign2.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[4]; + assert.equal(uploadPartRequest.method, "PUT"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); + + assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); + + var authParts = uploadPartRequest.requestHeaders.Authorization.split(";"); + assert.equal(authParts.length, 3); + assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); + assert.equal(authParts[1], "x-amz-content-sha256"); + assert.equal(authParts[2], "x-amz-date,Signature=thesignature"); + uploadPartRequest.respond(200, {ETag: "etag2"}, null); + + setTimeout(function() { + // signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 7); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; + assert.equal(uploadCompleteSignatureRequest.method, "POST"); + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint + "?v4=true"); + assert.equal(uploadCompleteSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers); + assert.equal(uploadCompleteToSign.headers.indexOf("AWS4-HMAC-SHA256"), 0); + assert.ok(uploadCompleteToSign.headers.indexOf("/us-east-1/s3/aws4_request") > 0); + assert.equal(uploadCompleteToSign.headers.split("\n").length, 12); + assert.ok(uploadCompleteToSign.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + setTimeout(function() { + // multipart complete request + assert.equal(fileTestHelper.getRequests().length, 8); + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + assert.equal(multipartCompleteRequest.method, "POST"); + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); + + authParts = multipartCompleteRequest.requestHeaders.Authorization.split(";"); + assert.equal(authParts.length, 3); + assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); + assert.equal(authParts[1], "x-amz-content-sha256"); + assert.equal(authParts[2], "x-amz-date,Signature=thesignature"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + + done(); + }, 0); + }, 0); + }, 100); }, 100); - - }, 100); + }, 0) }); }); }); it("handles a basic chunked upload", function(done) { - assert.expect(87, done); + // assert.expect(87, done); var uploadChunkCalled = false, uploadChunkSuccessCalled = false, @@ -353,54 +358,59 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); uploadPartRequest.respond(200, {ETag: "etag1"}, null); - // signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 6); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; - assert.equal(uploadPartSignatureRequest2.method, "POST"); - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - assert.equal(uploadPartSignatureRequest2.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers); - assert.equal(uploadPartToSign2.headers.indexOf("PUT"), 0); - assert.ok(uploadPartToSign2.headers.indexOf("x-amz-date:") > 0); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[4]; - assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); - - assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); + setTimeout(function() { + // signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 6); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; + assert.equal(uploadPartSignatureRequest2.method, "POST"); + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + assert.equal(uploadPartSignatureRequest2.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers); + assert.equal(uploadPartToSign2.headers.indexOf("PUT"), 0); + assert.ok(uploadPartToSign2.headers.indexOf("x-amz-date:") > 0); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[4]; + assert.equal(uploadPartRequest.method, "PUT"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); + + assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); + + assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); + uploadPartRequest.respond(200, {ETag: "etag2"}, null); - assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); - uploadPartRequest.respond(200, {ETag: "etag2"}, null); - - // signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 7); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; - assert.equal(uploadCompleteSignatureRequest.method, "POST"); - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - assert.equal(uploadCompleteSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers); - assert.equal(uploadCompleteToSign.headers.indexOf("POST"), 0); - assert.ok(uploadCompleteToSign.headers.indexOf("x-amz-date:") > 0); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // multipart complete request - assert.equal(fileTestHelper.getRequests().length, 8); - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - assert.equal(multipartCompleteRequest.method, "POST"); - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); - assert.equal(multipartCompleteRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); - assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + setTimeout(function() { + // signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 7); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; + assert.equal(uploadCompleteSignatureRequest.method, "POST"); + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + assert.equal(uploadCompleteSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers); + assert.equal(uploadCompleteToSign.headers.indexOf("POST"), 0); + assert.ok(uploadCompleteToSign.headers.indexOf("x-amz-date:") > 0); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // multipart complete request + assert.equal(fileTestHelper.getRequests().length, 8); + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + assert.equal(multipartCompleteRequest.method, "POST"); + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); + assert.equal(multipartCompleteRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); + assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + done(); + }, 0); + }, 0); }); }); @@ -453,39 +463,41 @@ if (qqtest.canDownloadFileAsBlob) { assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); uploadPartRequest.respond(200, {ETag: "etag1"}, null); - // signature request for upload part 2 - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf(qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME + ":" + qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE) < 0); - assert.ok(uploadPartToSign2.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) < 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[4]; - assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]); - assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); - uploadPartRequest.respond(200, {ETag: "etag1"}, null); - - // signature request for multipart complete - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf(qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME + ":" + qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE) < 0); - assert.ok(uploadCompleteToSign.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) < 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // multipart complete request - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - assert.ok(!multipartCompleteRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]); - assert.ok(!multipartCompleteRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + setTimeout(function () { + // signature request for upload part 2 + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf(qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME + ":" + qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE) < 0); + assert.ok(uploadPartToSign2.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) < 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[4]; + assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]); + assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); + uploadPartRequest.respond(200, {ETag: "etag1"}, null); + + setTimeout(function () { + // signature request for multipart complete + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf(qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME + ":" + qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE) < 0); + assert.ok(uploadCompleteToSign.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) < 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // multipart complete request + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + assert.ok(!multipartCompleteRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]); + assert.ok(!multipartCompleteRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + }, 0); + }, 0); }); }); it("handles failures at every step of a chunked upload", function(done) { - assert.expect(99, done); - var uploader = new qq.s3.FineUploaderBasic({ request: typicalRequestOption, signature: typicalSignatureOption, @@ -529,182 +541,204 @@ if (qqtest.canDownloadFileAsBlob) { initiateSignatureRequest.respond(200, null, JSON.stringify({invalid: true})); assert.equal(fileTestHelper.getRequests().length, 1); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - uploader.retry(0); - assert.equal(fileTestHelper.getRequests().length, 2); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful initiate signature request - initiateSignatureRequest = fileTestHelper.getRequests()[1]; - assert.equal(initiateSignatureRequest.url, testSignatureEndoint); - assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploads") > 0); - initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // failing initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 3); - initiateRequest = fileTestHelper.getRequests()[2]; - assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); - initiateRequest.respond(200, null, ""); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 3); - uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful initiate signature request - assert.equal(fileTestHelper.getRequests().length, 4); - initiateSignatureRequest = fileTestHelper.getRequests()[3]; - assert.equal(initiateSignatureRequest.url, testSignatureEndoint); - assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploads") > 0); - initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // successful initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 5); - initiateRequest = fileTestHelper.getRequests()[4]; - assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); - initiateRequest.respond(200, null, "123"); - - // failed signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 7); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[6]; - assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({invalid: true})); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 7); - uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 9); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[8]; - assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // failing upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 9); - uploadPartRequest = fileTestHelper.getRequests()[7]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - uploadPartRequest.respond(404, {ETag: "etag1"}, null); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 9); - uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 11); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[10]; - assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + uploader.retry(0); + assert.equal(fileTestHelper.getRequests().length, 2); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - // successful upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 11); - uploadPartRequest = fileTestHelper.getRequests()[9]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - uploadPartRequest.respond(200, {ETag: "etag1_a"}, null); - - // failing signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 13); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[12]; - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(404, null, JSON.stringify({signature: "thesignature"})); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 13); - uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + // successful initiate signature request + initiateSignatureRequest = fileTestHelper.getRequests()[1]; + assert.equal(initiateSignatureRequest.url, testSignatureEndoint); + assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploads") > 0); + initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - // successful signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 15); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[14]; - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // failing upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[13]; - assert.equal(fileTestHelper.getRequests().length, 15); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - uploadPartRequest.respond(404, {ETag: "etag2"}, null); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 15); - uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + // failing initiate multipart upload request + assert.equal(fileTestHelper.getRequests().length, 3); + initiateRequest = fileTestHelper.getRequests()[2]; + assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); + initiateRequest.respond(200, null, ""); - // successful signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 17); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[16]; - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // successful upload part 2 request - assert.equal(fileTestHelper.getRequests().length, 17); - uploadPartRequest = fileTestHelper.getRequests()[15]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - uploadPartRequest.respond(200, {ETag: "etag2_a"}, null); - - // failing signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 18); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[17]; - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(400, null, JSON.stringify({signature: "thesignature"})); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 18); - uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 3); + uploader.retry(0); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - // successful signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 19); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[18]; - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // failing multipart complete request - assert.equal(fileTestHelper.getRequests().length, 20); - multipartCompleteRequest = fileTestHelper.getRequests()[19]; - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + uploader.getKey(0) + ""); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 20); - uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + // successful initiate signature request + assert.equal(fileTestHelper.getRequests().length, 4); + initiateSignatureRequest = fileTestHelper.getRequests()[3]; + assert.equal(initiateSignatureRequest.url, testSignatureEndoint); + assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploads") > 0); + initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // successful initiate multipart upload request + assert.equal(fileTestHelper.getRequests().length, 5); + initiateRequest = fileTestHelper.getRequests()[4]; + assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); + initiateRequest.respond(200, null, "123"); + + // failed signature request for upload part 1 + assert.equal(fileTestHelper.getRequests().length, 7); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[6]; + assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({invalid: true})); - // successful signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 21); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[20]; - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // successful multipart complete request - assert.equal(fileTestHelper.getRequests().length, 22); - multipartCompleteRequest = fileTestHelper.getRequests()[21]; - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 7); + uploader.retry(0); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for upload part 1 + assert.equal(fileTestHelper.getRequests().length, 9); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[8]; + assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // failing upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 9); + uploadPartRequest = fileTestHelper.getRequests()[7]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); + uploadPartRequest.respond(404, {ETag: "etag1"}, null); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 9); + uploader.retry(0); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for upload part 1 + assert.equal(fileTestHelper.getRequests().length, 11); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[10]; + assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // successful upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 11); + uploadPartRequest = fileTestHelper.getRequests()[9]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); + uploadPartRequest.respond(200, {ETag: "etag1_a"}, null); + + setTimeout(function() { + // failing signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 13); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[12]; + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(404, null, JSON.stringify({signature: "thesignature"})); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 13); + uploader.retry(0); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 15); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[14]; + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + + setTimeout(function() { + // failing upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[13]; + assert.equal(fileTestHelper.getRequests().length, 15); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + uploadPartRequest.respond(404, {ETag: "etag2"}, null); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 15); + uploader.retry(0); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 17); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[16]; + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // successful upload part 2 request + assert.equal(fileTestHelper.getRequests().length, 17); + uploadPartRequest = fileTestHelper.getRequests()[15]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + uploadPartRequest.respond(200, {ETag: "etag2_a"}, null); + + setTimeout(function() { + // failing signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 18); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[17]; + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(400, null, JSON.stringify({signature: "thesignature"})); + + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 18); + uploader.retry(0); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 19); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[18]; + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // failing multipart complete request + assert.equal(fileTestHelper.getRequests().length, 20); + multipartCompleteRequest = fileTestHelper.getRequests()[19]; + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); + multipartCompleteRequest.respond(200, null, "" + uploader.getKey(0) + ""); + + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 20); + uploader.retry(0); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 21); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[20]; + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + setTimeout(function() { + // successful multipart complete request + assert.equal(fileTestHelper.getRequests().length, 22); + multipartCompleteRequest = fileTestHelper.getRequests()[21]; + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + + done(); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); }); }); @@ -753,6 +787,10 @@ if (qqtest.canDownloadFileAsBlob) { }); describe("client-side signature-based chunked S3 upload tests", function() { + beforeEach(function () { + localStorage.clear(); + }) + var startTypicalTest = function(uploader, callback) { qqtest.downloadFileAsBlob("up.jpg", "image/jpeg").then(function (blob) { var uploadRequest; @@ -779,8 +817,6 @@ if (qqtest.canDownloadFileAsBlob) { }; it("handles a basic chunked upload", function(done) { - assert.expect(24, done); - var uploader = new qq.s3.FineUploaderBasic({ request: typicalRequestOption, chunking: typicalChunkingOption, @@ -816,29 +852,34 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(uploadPartRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "Upload part 1 request Authorization header is invalid"); uploadPartRequest.respond(200, {ETag: "etag1"}, null); - // upload part 2 request - assert.equal(fileTestHelper.getRequests().length, 3); - uploadPartRequest = fileTestHelper.getRequests()[2]; - assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); + setTimeout(function() { + // upload part 2 request + assert.equal(fileTestHelper.getRequests().length, 3); + uploadPartRequest = fileTestHelper.getRequests()[2]; + assert.equal(uploadPartRequest.method, "PUT"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); - assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); + assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); - assert.equal(uploadPartRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "Upload part 2 request Authorization header is invalid"); - uploadPartRequest.respond(200, {ETag: "etag2"}, null); + assert.equal(uploadPartRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "Upload part 2 request Authorization header is invalid"); + uploadPartRequest.respond(200, {ETag: "etag2"}, null); - // multipart complete request - assert.equal(fileTestHelper.getRequests().length, 4); - multipartCompleteRequest = fileTestHelper.getRequests()[3]; - assert.equal(multipartCompleteRequest.method, "POST"); - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); - assert.equal(multipartCompleteRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "MP complete request Authorization header is invalid"); - assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + setTimeout(function() { + // multipart complete request + assert.equal(fileTestHelper.getRequests().length, 4); + multipartCompleteRequest = fileTestHelper.getRequests()[3]; + assert.equal(multipartCompleteRequest.method, "POST"); + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); + assert.equal(multipartCompleteRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "MP complete request Authorization header is invalid"); + assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + done(); + }, 0); + }, 0); }); }); @@ -865,71 +906,81 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); initiateRequest.respond(200, null, ""); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 1); - uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 2); - initiateRequest = fileTestHelper.getRequests()[1]; - assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); - initiateRequest.respond(200, null, "123"); - - // failing upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 3); - uploadPartRequest = fileTestHelper.getRequests()[2]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - uploadPartRequest.respond(404, {ETag: "etag1"}, null); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 3); - uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 1); + uploader.retry(0); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - // successful upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 4); - uploadPartRequest = fileTestHelper.getRequests()[3]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - uploadPartRequest.respond(200, {ETag: "etag1_a"}, null); - - // failing upload part 2 request - assert.equal(fileTestHelper.getRequests().length, 5); - uploadPartRequest = fileTestHelper.getRequests()[4]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - uploadPartRequest.respond(404, {ETag: "etag2"}, null); + // successful initiate multipart upload request + assert.equal(fileTestHelper.getRequests().length, 2); + initiateRequest = fileTestHelper.getRequests()[1]; + assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); + initiateRequest.respond(200, null, "123"); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 5); - uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + // failing upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 3); + uploadPartRequest = fileTestHelper.getRequests()[2]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); + uploadPartRequest.respond(404, {ETag: "etag1"}, null); - // successful upload part 2 request - assert.equal(fileTestHelper.getRequests().length, 6); - uploadPartRequest = fileTestHelper.getRequests()[5]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - uploadPartRequest.respond(200, {ETag: "etag2_a"}, null); - - // failing multipart complete request - assert.equal(fileTestHelper.getRequests().length, 7); - multipartCompleteRequest = fileTestHelper.getRequests()[6]; - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + uploader.getKey(0) + ""); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 7); - uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 3); + uploader.retry(0); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - // successful multipart complete request - assert.equal(fileTestHelper.getRequests().length, 8); - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + // successful upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 4); + uploadPartRequest = fileTestHelper.getRequests()[3]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); + uploadPartRequest.respond(200, {ETag: "etag1_a"}, null); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + setTimeout(function() { + // failing upload part 2 request + assert.equal(fileTestHelper.getRequests().length, 5); + uploadPartRequest = fileTestHelper.getRequests()[4]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + uploadPartRequest.respond(404, {ETag: "etag2"}, null); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 5); + uploader.retry(0); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful upload part 2 request + assert.equal(fileTestHelper.getRequests().length, 6); + uploadPartRequest = fileTestHelper.getRequests()[5]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + uploadPartRequest.respond(200, {ETag: "etag2_a"}, null); + + setTimeout(function() { + // failing multipart complete request + assert.equal(fileTestHelper.getRequests().length, 7); + multipartCompleteRequest = fileTestHelper.getRequests()[6]; + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); + multipartCompleteRequest.respond(200, null, "" + uploader.getKey(0) + ""); + + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 7); + uploader.retry(0); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful multipart complete request + assert.equal(fileTestHelper.getRequests().length, 8); + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); }); }); }); diff --git a/test/unit/s3/simple-file-uploads.js b/test/unit/s3/simple-file-uploads.js index 99290ddfc..d315afbca 100644 --- a/test/unit/s3/simple-file-uploads.js +++ b/test/unit/s3/simple-file-uploads.js @@ -680,27 +680,31 @@ if (qqtest.canDownloadFileAsBlob) { var uploadSuccessRequest, uploadSuccessRequestParsedBody; signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - uploadRequest.respond(200, {ETag: "123"}, null); - - assert.equal(fileTestHelper.getRequests().length, 3, "Wrong # of requests"); - uploadSuccessRequest = fileTestHelper.getRequests()[2]; - uploadSuccessRequestParsedBody = purl("http://test.com?" + uploadSuccessRequest.requestBody).param(); - assert.equal(uploadSuccessRequest.url, uploadSuccessUrl); - assert.equal(uploadSuccessRequest.method, "POST"); - assert.equal(uploadSuccessRequest.requestHeaders["Content-Type"].indexOf("application/x-www-form-urlencoded"), 0); - assert.equal(uploadSuccessRequest.requestHeaders["test-header-name"], uploadSuccessHeaders["test-header-name"]); - assert.equal(uploadSuccessRequestParsedBody["test-param-name"], uploadSuccessParams["test-param-name"]); - assert.equal(uploadSuccessRequestParsedBody.foo, "bar"); - assert.equal(uploadSuccessRequestParsedBody.key, uploader.getKey(0)); - assert.equal(uploadSuccessRequestParsedBody.uuid, uploader.getUuid(0)); - assert.equal(uploadSuccessRequestParsedBody.name, uploader.getName(0)); - assert.equal(uploadSuccessRequestParsedBody.bucket, testBucketName); - assert.equal(uploadSuccessRequestParsedBody.etag, "123"); - - uploadSuccessRequest.respond(200, null, null); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + setTimeout(function () { + uploadRequest.respond(200, {ETag: "123"}, null); - done(); + setTimeout(function () { + assert.equal(fileTestHelper.getRequests().length, 3, "Wrong # of requests"); + uploadSuccessRequest = fileTestHelper.getRequests()[2]; + uploadSuccessRequestParsedBody = purl("http://test.com?" + uploadSuccessRequest.requestBody).param(); + assert.equal(uploadSuccessRequest.url, uploadSuccessUrl); + assert.equal(uploadSuccessRequest.method, "POST"); + assert.equal(uploadSuccessRequest.requestHeaders["Content-Type"].indexOf("application/x-www-form-urlencoded"), 0); + assert.equal(uploadSuccessRequest.requestHeaders["test-header-name"], uploadSuccessHeaders["test-header-name"]); + assert.equal(uploadSuccessRequestParsedBody["test-param-name"], uploadSuccessParams["test-param-name"]); + assert.equal(uploadSuccessRequestParsedBody.foo, "bar"); + assert.equal(uploadSuccessRequestParsedBody.key, uploader.getKey(0)); + assert.equal(uploadSuccessRequestParsedBody.uuid, uploader.getUuid(0)); + assert.equal(uploadSuccessRequestParsedBody.name, uploader.getName(0)); + assert.equal(uploadSuccessRequestParsedBody.bucket, testBucketName); + assert.equal(uploadSuccessRequestParsedBody.etag, "123"); + + uploadSuccessRequest.respond(200, null, null); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + + done(); + }, 0); + }, 0); }); }); @@ -721,12 +725,16 @@ if (qqtest.canDownloadFileAsBlob) { signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); uploadRequest.respond(200, null, null); - uploadSuccessRequest = fileTestHelper.getRequests()[2]; - assert.equal(uploadSuccessRequest.url, uploadSuccessUrl); - uploadSuccessRequest.respond(200, null, JSON.stringify({success: false})); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + setTimeout(function() { + uploadSuccessRequest = fileTestHelper.getRequests()[2]; + assert.equal(uploadSuccessRequest.url, uploadSuccessUrl); + uploadSuccessRequest.respond(200, null, JSON.stringify({success: false})); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - done(); + done(); + }, 0); + }, 0); }); }); @@ -748,12 +756,14 @@ if (qqtest.canDownloadFileAsBlob) { signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); uploadRequest.respond(200, null, null); - uploadSuccessRequest = fileTestHelper.getRequests()[2]; - assert.equal(uploadSuccessRequest.method, "PUT"); - uploadSuccessRequest.respond(200, null, null); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + setTimeout(function() { + uploadSuccessRequest = fileTestHelper.getRequests()[2]; + assert.equal(uploadSuccessRequest.method, "PUT"); + uploadSuccessRequest.respond(200, null, null); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + done(); + }, 0); }); }); }); diff --git a/test/unit/set-status.js b/test/unit/set-status.js index ff7fe7fba..83cb78338 100644 --- a/test/unit/set-status.js +++ b/test/unit/set-status.js @@ -65,17 +65,19 @@ describe("set-status.js", function() { uploader.uploadStoredFiles(); fileTestHelper.getRequests()[0].respond(201, null, JSON.stringify({success: true})); - var uploaderFiles = uploader.getUploads(); - var file = uploaderFiles[0]; + setTimeout(function() { + var uploaderFiles = uploader.getUploads(); + var file = uploaderFiles[0]; - uploader.setStatus(file.id, qq.status.DELETED); + uploader.setStatus(file.id, qq.status.DELETED); - uploaderFiles = uploader.getUploads(); - file = uploaderFiles[0]; + uploaderFiles = uploader.getUploads(); + file = uploaderFiles[0]; - assert.equal(0, uploader.getNetUploads()); - assert.equal(qq.status.DELETED, file.status); - done(); + assert.equal(0, uploader.getNetUploads()); + assert.equal(qq.status.DELETED, file.status); + done(); + }, 0); }); }); @@ -95,17 +97,19 @@ describe("set-status.js", function() { uploader.uploadStoredFiles(); fileTestHelper.getRequests()[0].respond(201, null, JSON.stringify({success: true})); - var uploaderFiles = uploader.getUploads(); - var file = uploaderFiles[0]; + setTimeout(function() { + var uploaderFiles = uploader.getUploads(); + var file = uploaderFiles[0]; - uploader.setStatus(file.id, qq.status.DELETE_FAILED); + uploader.setStatus(file.id, qq.status.DELETE_FAILED); - uploaderFiles = uploader.getUploads(); - file = uploaderFiles[0]; + uploaderFiles = uploader.getUploads(); + file = uploaderFiles[0]; - assert.equal(1, uploader.getNetUploads()); - assert.equal(qq.status.DELETE_FAILED, file.status); - done(); + assert.equal(1, uploader.getNetUploads()); + assert.equal(qq.status.DELETE_FAILED, file.status); + done(); + }, 0); }); }); From 4e22540dc1a3a29519ef4b120142b84965a2f2e4 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 11:50:07 +1100 Subject: [PATCH 17/73] refactor: UploadHandler#finalizeChunks to use Promise --- client/js/azure/azure.xhr.upload.handler.js | 39 +++-- client/js/s3/s3.xhr.upload.handler.js | 24 ++-- .../traditional.xhr.upload.handler.js | 31 ++-- .../upload.handler.controller.js | 9 +- .../js/upload-handler/xhr.upload.handler.js | 4 +- test/unit/s3/cdn/generic-chunked.js | 6 +- test/unit/s3/chunked-uploads.js | 136 ++++++++++-------- 7 files changed, 137 insertions(+), 112 deletions(-) diff --git a/client/js/azure/azure.xhr.upload.handler.js b/client/js/azure/azure.xhr.upload.handler.js index 6143456f4..b0854517f 100644 --- a/client/js/azure/azure.xhr.upload.handler.js +++ b/client/js/azure/azure.xhr.upload.handler.js @@ -59,27 +59,24 @@ qq.azure.XhrUploadHandler = function(spec, proxy) { }; function combineChunks(id) { - var promise = new qq.Promise(); - - getSignedUrl(id).then(function(sasUri) { - var mimeType = handler._getMimeType(id), - blockIdEntries = handler._getPersistableData(id).blockIdEntries; - - api.putBlockList.send(id, sasUri, blockIdEntries, mimeType, function(xhr) { - handler._registerXhr(id, null, xhr, api.putBlockList); - }) - .then(function(xhr) { - log("Success combining chunks for id " + id); - promise.success({}, xhr); - }, function(xhr) { - log("Attempt to combine chunks failed for id " + id, "error"); - handleFailure(xhr, promise); - }); - - }, - promise.failure); - - return promise; + return new Promise(function(resolve, reject) { + getSignedUrl(id).then(function(sasUri) { + var mimeType = handler._getMimeType(id), + blockIdEntries = handler._getPersistableData(id).blockIdEntries; + + api.putBlockList.send(id, sasUri, blockIdEntries, mimeType, function(xhr) { + handler._registerXhr(id, null, xhr, api.putBlockList); + }) + .then(function(xhr) { + log("Success combining chunks for id " + id); + resolve({response: {}, xhr: xhr}); + }, function(xhr) { + log("Attempt to combine chunks failed for id " + id, "error"); + reject(buildError(xhr)); + }); + }, + reject); + }); } function determineBlobUrl(id) { diff --git a/client/js/s3/s3.xhr.upload.handler.js b/client/js/s3/s3.xhr.upload.handler.js index 458ca7db8..00dabdddf 100755 --- a/client/js/s3/s3.xhr.upload.handler.js +++ b/client/js/s3/s3.xhr.upload.handler.js @@ -35,18 +35,22 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { // when the response to this request has been parsed. combine: function(id) { var uploadId = handler._getPersistableData(id).uploadId, - etagMap = handler._getPersistableData(id).etags, - result = new qq.Promise(); + etagMap = handler._getPersistableData(id).etags; - requesters.completeMultipart.send(id, uploadId, etagMap).then( - result.success, - - function failure(reason, xhr) { - result.failure(upload.done(id, xhr).response, xhr); - } - ); + return new Promise(function(resolve, reject) { + requesters.completeMultipart.send(id, uploadId, etagMap).then( + function(response, xhr) { + resolve({response: response, xhr: xhr}); + }, - return result; + function failure(reason, xhr) { + var error = new Error(reason); + error.xhr = xhr; + error.response = upload.done(id, xhr).response; + reject(error); + } + ); + }); }, // The last step in handling a chunked upload. This is called after each chunk has been sent. diff --git a/client/js/traditional/traditional.xhr.upload.handler.js b/client/js/traditional/traditional.xhr.upload.handler.js index b88972e26..f02450aae 100644 --- a/client/js/traditional/traditional.xhr.upload.handler.js +++ b/client/js/traditional/traditional.xhr.upload.handler.js @@ -118,21 +118,22 @@ qq.traditional.XhrUploadHandler = function(spec, proxy) { }, sendChunksCompleteRequest = function(id) { - var promise = new qq.Promise(); - - allChunksDoneRequester.complete( - id, - handler._createXhr(id), - getChunksCompleteParams(id), - spec.customHeaders.get(id) - ) - .then(function(xhr) { - promise.success(parseResponse(false, xhr), xhr); - }, function(xhr) { - promise.failure(parseResponse(false, xhr), xhr); - }); - - return promise; + return new Promise(function(resolve, reject) { + allChunksDoneRequester.complete( + id, + handler._createXhr(id), + getChunksCompleteParams(id), + spec.customHeaders.get(id) + ) + .then(function(xhr) { + resolve({response: parseResponse(false, xhr), xhr: xhr}); + }, function(xhr) { + var error = new Error("All chunks done requester failed"); + error.response = parseResponse(false, xhr); + error.xhr = xhr; + reject(error); + }); + }); }, setParamsAndGetEntityToSend = function(entityToSendParams) { diff --git a/client/js/upload-handler/upload.handler.controller.js b/client/js/upload-handler/upload.handler.controller.js index aa0819554..ee4275c5e 100644 --- a/client/js/upload-handler/upload.handler.controller.js +++ b/client/js/upload-handler/upload.handler.controller.js @@ -62,7 +62,9 @@ qq.UploadHandlerController = function(o, namespace) { log("All chunks have been uploaded for " + id + " - finalizing...."); handler.finalizeChunks(id).then( - function(response, xhr) { + function(info) { + var response = info.response, + xhr = info.xhr; log("Finalize successful for " + id); var normaizedResponse = upload.normalizeResponse(response, true); @@ -71,8 +73,9 @@ qq.UploadHandlerController = function(o, namespace) { handler._maybeDeletePersistedChunkData(id); upload.cleanup(id, normaizedResponse, xhr); }, - function(response, xhr) { - var normalizedResponse = upload.normalizeResponse(response, false); + function(error) { + var xhr = error.xhr; + var normalizedResponse = upload.normalizeResponse(error.response, false); log("Problem finalizing chunks for file ID " + id + " - " + normalizedResponse.error, "error"); diff --git a/client/js/upload-handler/xhr.upload.handler.js b/client/js/upload-handler/xhr.upload.handler.js index 131b10690..ee0a48e0c 100644 --- a/client/js/upload-handler/xhr.upload.handler.js +++ b/client/js/upload-handler/xhr.upload.handler.js @@ -109,10 +109,10 @@ qq.XhrUploadHandler = function(spec) { xhr = handler._getXhr(id, lastChunkIdx); if (responseParser) { - return new qq.Promise().success(responseParser(xhr), xhr); + return Promise.resolve({response: responseParser(xhr), xhr: xhr}); } - return new qq.Promise().success({}, xhr); + return Promise.resolve({response: {}, xhr: xhr}); }, getFile: function(id) { diff --git a/test/unit/s3/cdn/generic-chunked.js b/test/unit/s3/cdn/generic-chunked.js index c4781edba..8fdac18a1 100644 --- a/test/unit/s3/cdn/generic-chunked.js +++ b/test/unit/s3/cdn/generic-chunked.js @@ -78,9 +78,11 @@ if (qqtest.canDownloadFileAsBlob) { multipartCompleteRequest = fileTestHelper.getRequests()[7]; multipartCompleteRequest.respond(200, null, "mybucket" + uploader.getKey(0) + ""); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + done(); + }, 0); }, 0); }, 0); }); diff --git a/test/unit/s3/chunked-uploads.js b/test/unit/s3/chunked-uploads.js index 63566d6f7..edea53bb3 100644 --- a/test/unit/s3/chunked-uploads.js +++ b/test/unit/s3/chunked-uploads.js @@ -231,9 +231,11 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(authParts[2], "x-amz-date,Signature=thesignature"); multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + done(); + }, 0); }, 0); }, 0); }, 100); @@ -407,8 +409,10 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + done(); + }, 0); }, 0); }, 0); }); @@ -491,7 +495,9 @@ if (qqtest.canDownloadFileAsBlob) { assert.ok(!multipartCompleteRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + setTimeout(function () { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + }, 0); }, 0); }, 0); }); @@ -685,50 +691,56 @@ if (qqtest.canDownloadFileAsBlob) { assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); uploadCompleteSignatureRequest.respond(400, null, JSON.stringify({signature: "thesignature"})); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 18); - uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 19); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[18]; - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // failing multipart complete request - assert.equal(fileTestHelper.getRequests().length, 20); - multipartCompleteRequest = fileTestHelper.getRequests()[19]; - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + uploader.getKey(0) + ""); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 20); - uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 21); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[20]; - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - setTimeout(function() { - // successful multipart complete request - assert.equal(fileTestHelper.getRequests().length, 22); - multipartCompleteRequest = fileTestHelper.getRequests()[21]; + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 18); + uploader.retry(0); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 19); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[18]; + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // failing multipart complete request + assert.equal(fileTestHelper.getRequests().length, 20); + multipartCompleteRequest = fileTestHelper.getRequests()[19]; assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); - - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - - done(); + multipartCompleteRequest.respond(200, null, "" + uploader.getKey(0) + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 20); + uploader.retry(0); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 21); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[20]; + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + setTimeout(function() { + // successful multipart complete request + assert.equal(fileTestHelper.getRequests().length, 22); + multipartCompleteRequest = fileTestHelper.getRequests()[21]; + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + + done(); + }, 0); + }, 0); + }, 0); }, 0); }, 0); }, 0); @@ -876,8 +888,10 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + done(); + }, 0); }, 0); }, 0); }); @@ -963,19 +977,23 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); multipartCompleteRequest.respond(200, null, "" + uploader.getKey(0) + ""); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 7); - uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 7); + uploader.retry(0); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - // successful multipart complete request - assert.equal(fileTestHelper.getRequests().length, 8); - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + // successful multipart complete request + assert.equal(fileTestHelper.getRequests().length, 8); + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + }, 0); + }, 0); }, 0); }, 0); }, 0); From 07f0033617349c8267518355474a13291617eb47 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 11:54:29 +1100 Subject: [PATCH 18/73] refactor: determineBlobUrl to use Promise --- client/js/azure/azure.xhr.upload.handler.js | 24 ++++++++------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/client/js/azure/azure.xhr.upload.handler.js b/client/js/azure/azure.xhr.upload.handler.js index b0854517f..22b1c6214 100644 --- a/client/js/azure/azure.xhr.upload.handler.js +++ b/client/js/azure/azure.xhr.upload.handler.js @@ -80,19 +80,14 @@ qq.azure.XhrUploadHandler = function(spec, proxy) { } function determineBlobUrl(id) { - var containerUrl = endpointStore.get(id), - promise = new qq.Promise(), - getBlobNameSuccess = function(blobName) { - handler._setThirdPartyFileId(id, blobName); - promise.success(containerUrl + "/" + blobName); - }, - getBlobNameFailure = function(error) { - promise.failure(error.message); - }; - - onGetBlobName(id).then(getBlobNameSuccess, getBlobNameFailure); + var containerUrl = endpointStore.get(id); - return promise; + return new Promise(function(resolve, reject) { + onGetBlobName(id).then(function(blobName) { + handler._setThirdPartyFileId(id, blobName); + resolve(containerUrl + "/" + blobName); + }, reject); + }); } function getSignedUrl(id, optChunkIdx) { @@ -114,9 +109,8 @@ qq.azure.XhrUploadHandler = function(spec, proxy) { getSasFailure ); }, - determineBlobUrlFailure = function(reason) { - var error = new Error(reason); - log(qq.format("Failed to determine blob name for ID {} - {}", id, reason), "error"); + determineBlobUrlFailure = function(error) { + log(qq.format("Failed to determine blob name for ID {} - {}", id, error.message), "error"); reject(error); }; From 9afcdbb1870594c65cc82604bf01a97af609cd8d Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 11:58:53 +1100 Subject: [PATCH 19/73] refactor: lint --- test/unit/s3/chunked-uploads.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/s3/chunked-uploads.js b/test/unit/s3/chunked-uploads.js index edea53bb3..61b86a1f1 100644 --- a/test/unit/s3/chunked-uploads.js +++ b/test/unit/s3/chunked-uploads.js @@ -240,7 +240,7 @@ if (qqtest.canDownloadFileAsBlob) { }, 0); }, 100); }, 100); - }, 0) + }, 0); }); }); }); @@ -801,7 +801,7 @@ if (qqtest.canDownloadFileAsBlob) { describe("client-side signature-based chunked S3 upload tests", function() { beforeEach(function () { localStorage.clear(); - }) + }); var startTypicalTest = function(uploader, callback) { qqtest.downloadFileAsBlob("up.jpg", "image/jpeg").then(function (blob) { From fc81e29e5d1d9cb95adc472cc9c34cba3ffeabd8 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 11:59:21 +1100 Subject: [PATCH 20/73] refactor: qq.Identify.isPreviewable to use Promise --- client/js/identify.js | 63 +++++++++++++++++++++---------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/client/js/identify.js b/client/js/identify.js index 083bc8d40..94d5a2424 100644 --- a/client/js/identify.js +++ b/client/js/identify.js @@ -22,12 +22,11 @@ qq.Identify = function(fileOrBlob, log) { * bytes in the beginning of the file, so this is an asynchronous operation. Before we attempt to read the * file, we will examine the blob's type attribute to save CPU cycles. * - * @returns {qq.Promise} Promise that is fulfilled when identification is complete. - * If successful, the MIME string is passed to the success handler. + * @returns {Promise} Promise that is resolved when identification is complete. + * If successful, resolved with the MIME string. */ isPreviewable: function() { var self = this, - identifier = new qq.Promise(), previewable = false, name = fileOrBlob.name === undefined ? "blob" : fileOrBlob.name; @@ -35,39 +34,39 @@ qq.Identify = function(fileOrBlob, log) { log("First pass: check type attribute of blob object."); - if (this.isPreviewableSync()) { - log("Second pass: check for magic bytes in file header."); - - qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) { - qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) { - if (isIdentifiable(bytes, hex)) { - // Safari is the only supported browser that can deal with TIFFs natively, - // so, if this is a TIFF and the UA isn't Safari, declare this file "non-previewable". - if (mime !== "image/tiff" || qq.supportedFeatures.tiffPreviews) { - previewable = true; - identifier.success(mime); + return new Promise(function(resolve, reject) { + if (self.isPreviewableSync()) { + log("Second pass: check for magic bytes in file header."); + + qq.readBlobToHex(fileOrBlob, 0, 4).then(function(hex) { + qq.each(self.PREVIEWABLE_MIME_TYPES, function(mime, bytes) { + if (isIdentifiable(bytes, hex)) { + // Safari is the only supported browser that can deal with TIFFs natively, + // so, if this is a TIFF and the UA isn't Safari, declare this file "non-previewable". + if (mime !== "image/tiff" || qq.supportedFeatures.tiffPreviews) { + previewable = true; + resolve(mime); + } + + return false; } + }); - return false; + log(qq.format("'{}' is {} able to be rendered in this browser", name, previewable ? "" : "NOT")); + + if (!previewable) { + reject(); } + }, + function() { + log("Error reading file w/ name '" + name + "'. Not able to be rendered in this browser."); + reject(); }); - - log(qq.format("'{}' is {} able to be rendered in this browser", name, previewable ? "" : "NOT")); - - if (!previewable) { - identifier.failure(); - } - }, - function() { - log("Error reading file w/ name '" + name + "'. Not able to be rendered in this browser."); - identifier.failure(); - }); - } - else { - identifier.failure(); - } - - return identifier; + } + else { + reject(); + } + }); }, /** From b1954f47307a49c2d3b735d9c37a5ae935c2444d Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 12:01:16 +1100 Subject: [PATCH 21/73] refactor: renderImageToCanvas to use Promise --- client/js/image-support/megapix-image.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/js/image-support/megapix-image.js b/client/js/image-support/megapix-image.js index 57aa9aea8..c542b35c9 100644 --- a/client/js/image-support/megapix-image.js +++ b/client/js/image-support/megapix-image.js @@ -110,7 +110,6 @@ width = options.width, height = options.height, ctx = canvas.getContext("2d"), - promise = new qq.Promise(), modifiedDimensions; ctx.save(); @@ -190,9 +189,8 @@ } canvas.qqImageRendered && canvas.qqImageRendered(); - promise.success(); - return promise; + return Promise.resolve(); } function renderImageToCanvasWithCustomResizer(resizeInfo) { From 4a2367d3bf8dede716e4f61413bf9bb43f4ad9dc Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 12:04:31 +1100 Subject: [PATCH 22/73] refactor: traverseFileTree to use Promise --- client/js/dnd.js | 70 +++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/client/js/dnd.js b/client/js/dnd.js index 126df5250..26d37c746 100644 --- a/client/js/dnd.js +++ b/client/js/dnd.js @@ -30,47 +30,45 @@ qq.DragAndDrop = function(o) { } function traverseFileTree(entry) { - var parseEntryPromise = new qq.Promise(); - - if (entry.isFile) { - entry.file(function(file) { - file.qqPath = extractDirectoryPath(entry); - droppedFiles.push(file); - parseEntryPromise.success(); - }, - function(fileError) { - options.callbacks.dropLog("Problem parsing '" + entry.fullPath + "'. FileError code " + fileError.code + ".", "error"); - parseEntryPromise.failure(); - }); - } - else if (entry.isDirectory) { - getFilesInDirectory(entry).then( - function allEntriesRead(entries) { - var entriesLeft = entries.length; + return new Promise(function(resolve, reject) { + if (entry.isFile) { + entry.file(function(file) { + file.qqPath = extractDirectoryPath(entry); + droppedFiles.push(file); + resolve(); + }, + function(fileError) { + options.callbacks.dropLog("Problem parsing '" + entry.fullPath + "'. FileError code " + fileError.code + ".", "error"); + reject(); + }); + } + else if (entry.isDirectory) { + getFilesInDirectory(entry).then( + function allEntriesRead(entries) { + var entriesLeft = entries.length; - qq.each(entries, function(idx, entry) { - traverseFileTree(entry).done(function() { - entriesLeft -= 1; + qq.each(entries, function(idx, entry) { + traverseFileTree(entry).done(function() { + entriesLeft -= 1; - if (entriesLeft === 0) { - parseEntryPromise.success(); - } + if (entriesLeft === 0) { + resolve(); + } + }); }); - }); - if (!entries.length) { - parseEntryPromise.success(); - } - }, - - function readFailure(fileError) { - options.callbacks.dropLog("Problem parsing '" + entry.fullPath + "'. FileError code " + fileError.code + ".", "error"); - parseEntryPromise.failure(); - } - ); - } + if (!entries.length) { + resolve(); + } + }, - return parseEntryPromise; + function readFailure(fileError) { + options.callbacks.dropLog("Problem parsing '" + entry.fullPath + "'. FileError code " + fileError.code + ".", "error"); + reject(); + } + ); + } + }); } function extractDirectoryPath(entry) { From 75feb04ada20f2bd5cc5f2533291bc8611501cdc Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 12:06:05 +1100 Subject: [PATCH 23/73] refactor: handleDataTransfer to use Promise --- client/js/dnd.js | 71 ++++++++++++++++++++++++------------------------ 1 file changed, 35 insertions(+), 36 deletions(-) diff --git a/client/js/dnd.js b/client/js/dnd.js index 26d37c746..053934e09 100644 --- a/client/js/dnd.js +++ b/client/js/dnd.js @@ -113,52 +113,51 @@ qq.DragAndDrop = function(o) { } function handleDataTransfer(dataTransfer, uploadDropZone) { - var pendingFolderPromises = [], - handleDataTransferPromise = new qq.Promise(); + var pendingFolderPromises = []; options.callbacks.processingDroppedFiles(); uploadDropZone.dropDisabled(true); - if (dataTransfer.files.length > 1 && !options.allowMultipleItems) { - options.callbacks.processingDroppedFilesComplete([]); - options.callbacks.dropError("tooManyFilesError", ""); - uploadDropZone.dropDisabled(false); - handleDataTransferPromise.failure(); - } - else { - droppedFiles = []; + return new Promise(function(resolve, reject) { + if (dataTransfer.files.length > 1 && !options.allowMultipleItems) { + options.callbacks.processingDroppedFilesComplete([]); + options.callbacks.dropError("tooManyFilesError", ""); + uploadDropZone.dropDisabled(false); + reject(); + } + else { + droppedFiles = []; - if (qq.isFolderDropSupported(dataTransfer)) { - qq.each(dataTransfer.items, function(idx, item) { - var entry = item.webkitGetAsEntry(); + if (qq.isFolderDropSupported(dataTransfer)) { + qq.each(dataTransfer.items, function(idx, item) { + var entry = item.webkitGetAsEntry(); - if (entry) { - //due to a bug in Chrome's File System API impl - #149735 - if (entry.isFile) { - droppedFiles.push(item.getAsFile()); - } + if (entry) { + //due to a bug in Chrome's File System API impl - #149735 + if (entry.isFile) { + droppedFiles.push(item.getAsFile()); + } - else { - pendingFolderPromises.push(traverseFileTree(entry).done(function() { - pendingFolderPromises.pop(); - if (pendingFolderPromises.length === 0) { - handleDataTransferPromise.success(); - } - })); + else { + pendingFolderPromises.push(traverseFileTree(entry).done(function() { + pendingFolderPromises.pop(); + if (pendingFolderPromises.length === 0) { + resolve(); + } + })); + } } - } - }); - } - else { - droppedFiles = dataTransfer.files; - } + }); + } + else { + droppedFiles = dataTransfer.files; + } - if (pendingFolderPromises.length === 0) { - handleDataTransferPromise.success(); + if (pendingFolderPromises.length === 0) { + resolve(); + } } - } - - return handleDataTransferPromise; + }); } function setupDropzone(dropArea) { From bf2e80ba699bd0c76e331c15e78a6ad66b7894c0 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 12:09:24 +1100 Subject: [PATCH 24/73] refactor: getFilesInDirectory to use Promise --- client/js/dnd.js | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/client/js/dnd.js b/client/js/dnd.js index 053934e09..acf590a6b 100644 --- a/client/js/dnd.js +++ b/client/js/dnd.js @@ -88,28 +88,26 @@ qq.DragAndDrop = function(o) { } // Promissory. Guaranteed to read all files in the root of the passed directory. - function getFilesInDirectory(entry, reader, accumEntries, existingPromise) { - var promise = existingPromise || new qq.Promise(), + function getFilesInDirectory(entry, reader, accumEntries) { + var promise = existingPromise, dirReader = reader || entry.createReader(); - dirReader.readEntries( - function readSuccess(entries) { - var newEntries = accumEntries ? accumEntries.concat(entries) : entries; - - if (entries.length) { - setTimeout(function() { // prevent stack overflow, however unlikely - getFilesInDirectory(entry, dirReader, newEntries, promise); - }, 0); - } - else { - promise.success(newEntries); - } - }, + return new Promise(function(resolve, reject) { + dirReader.readEntries( + function readSuccess(entries) { + var newEntries = accumEntries ? accumEntries.concat(entries) : entries; - promise.failure - ); + if (entries.length) { + getFilesInDirectory(entry, dirReader, newEntries).then(resolve, reject); + } + else { + resolve(newEntries); + } + }, - return promise; + reject + ); + }); } function handleDataTransfer(dataTransfer, uploadDropZone) { From 3a7c5648957edc9ee7da7c0b952f561afe238f94 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 13:05:25 +1100 Subject: [PATCH 25/73] refactor: _onComplete to use Promise --- .../uploader.basic.api.js | 91 ++++++++++--------- client/js/uploader.api.js | 7 +- 2 files changed, 50 insertions(+), 48 deletions(-) diff --git a/client/js/non-traditional-common/uploader.basic.api.js b/client/js/non-traditional-common/uploader.basic.api.js index 71a43d637..98daa3a5f 100644 --- a/client/js/non-traditional-common/uploader.basic.api.js +++ b/client/js/non-traditional-common/uploader.basic.api.js @@ -24,7 +24,7 @@ * @param name Name of the associated item * @param result Object created from the server's parsed JSON response. * @param xhr Associated XmlHttpRequest, if this was used to send the request. - * @returns {boolean || qq.Promise} true/false if success can be determined immediately, otherwise a `qq.Promise` + * @returns {boolean || Promise} true/false if success can be determined immediately, otherwise a `Promise` * if we need to ask the server. * @private */ @@ -36,44 +36,8 @@ successCustomHeaders = this._options.uploadSuccess.customHeaders, successMethod = this._options.uploadSuccess.method, cors = this._options.cors, - promise = new qq.Promise(), uploadSuccessParams = this._uploadSuccessParamsStore.get(id), fileParams = this._paramsStore.get(id), - - // If we are waiting for confirmation from the local server, and have received it, - // include properties from the local server response in the `response` parameter - // sent to the `onComplete` callback, delegate to the parent `_onComplete`, and - // fulfill the associated promise. - onSuccessFromServer = function(successRequestResult) { - delete self._failedSuccessRequestCallbacks[id]; - qq.extend(result, successRequestResult); - qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs); - promise.success(successRequestResult); - }, - - // If the upload success request fails, attempt to re-send the success request (via the core retry code). - // The entire upload may be restarted if the server returns a "reset" property with a value of true as well. - onFailureFromServer = function(successRequestResult) { - var callback = submitSuccessRequest; - - qq.extend(result, successRequestResult); - - if (result && result.reset) { - callback = null; - } - - if (!callback) { - delete self._failedSuccessRequestCallbacks[id]; - } - else { - self._failedSuccessRequestCallbacks[id] = callback; - } - - if (!self._onAutoRetry(id, name, result, xhr, callback)) { - qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs); - promise.failure(successRequestResult); - } - }, submitSuccessRequest, successAjaxRequester; @@ -93,14 +57,51 @@ // include any params associated with the file fileParams && qq.extend(uploadSuccessParams, fileParams, true); - submitSuccessRequest = qq.bind(function() { - successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams) - .then(onSuccessFromServer, onFailureFromServer); - }, self); - - submitSuccessRequest(); - - return promise; + return new Promise(function(resolve, reject) { + submitSuccessRequest = qq.bind(function() { + successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams) + .then( + // If we are waiting for confirmation from the local server, and have received it, + // include properties from the local server response in the `response` parameter + // sent to the `onComplete` callback, delegate to the parent `_onComplete`, and + // resolve the associated promise. + function(successRequestResult) { + delete self._failedSuccessRequestCallbacks[id]; + qq.extend(result, successRequestResult); + qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs); + resolve(successRequestResult); + }, + // If the upload success request fails, attempt to re-send the success request (via the core retry code). + // The entire upload may be restarted if the server returns a "reset" property with a value of true as well. + function(successRequestResult) { + var callback = submitSuccessRequest, + error; + + qq.extend(result, successRequestResult); + + if (result && result.reset) { + callback = null; + } + + if (!callback) { + delete self._failedSuccessRequestCallbacks[id]; + } + else { + self._failedSuccessRequestCallbacks[id] = callback; + } + + if (!self._onAutoRetry(id, name, result, xhr, callback)) { + qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs); + error = new Error("Success request failed"); + error.response = successRequestResult; + reject(error); + } + } + ); + }, self); + + submitSuccessRequest(); + }); } // If we are not asking the local server about the file, just delegate to the parent `_onComplete`. diff --git a/client/js/uploader.api.js b/client/js/uploader.api.js index d1ced64b4..97c05816b 100644 --- a/client/js/uploader.api.js +++ b/client/js/uploader.api.js @@ -385,11 +385,12 @@ } // The parent may need to perform some async operation before we can accurately determine the status of the upload. - if (parentRetVal instanceof qq.Promise) { - parentRetVal.done(function(newResult) { + if (parentRetVal instanceof Promise) { + parentRetVal.then(function(newResult) { completeUpload(newResult); + }, function(error) { + completeUpload(error.response); }); - } else { completeUpload(result); From bce7cf9dbd780e78161234f1f216a6b98b1f46de Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 15:00:52 +1100 Subject: [PATCH 26/73] refactor: getWidthHeight to use Promise --- client/js/image-support/validation.image.js | 67 ++++++++++----------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/client/js/image-support/validation.image.js b/client/js/image-support/validation.image.js index 9c0679999..04e3900cf 100644 --- a/client/js/image-support/validation.image.js +++ b/client/js/image-support/validation.image.js @@ -27,41 +27,38 @@ qq.ImageValidation = function(blob, log) { } /** - * @returns {qq.Promise} The promise is a failure if we can't obtain the width & height. - * Otherwise, `success` is called on the returned promise with an object containing - * `width` and `height` properties. + * @returns {Promise} The promise is rejected if we can't obtain the width & height. + * Otherwise it is resolved with an object `{width: number, height: number}`. */ function getWidthHeight() { - var sizeDetermination = new qq.Promise(); - - new qq.Identify(blob, log).isPreviewable().then(function() { - var image = new Image(), - url = window.URL && window.URL.createObjectURL ? window.URL : - window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : - null; - - if (url) { - image.onerror = function() { - log("Cannot determine dimensions for image. May be too large.", "error"); - sizeDetermination.failure(); - }; - - image.onload = function() { - sizeDetermination.success({ - width: this.width, - height: this.height - }); - }; - - image.src = url.createObjectURL(blob); - } - else { - log("No createObjectURL function available to generate image URL!", "error"); - sizeDetermination.failure(); - } - }, sizeDetermination.failure); - - return sizeDetermination; + return new Promise(function(resolve, reject) { + new qq.Identify(blob, log).isPreviewable().then(function() { + var image = new Image(), + url = window.URL && window.URL.createObjectURL ? window.URL : + window.webkitURL && window.webkitURL.createObjectURL ? window.webkitURL : + null; + + if (url) { + image.onerror = function() { + log("Cannot determine dimensions for image. May be too large.", "error"); + reject(); + }; + + image.onload = function() { + resolve({ + width: this.width, + height: this.height + }); + }; + + image.src = url.createObjectURL(blob); + } + else { + log("No createObjectURL function available to generate image URL!", "error"); + reject(); + } + }, reject); + }); } /** @@ -123,7 +120,9 @@ qq.ImageValidation = function(blob, log) { else { validationEffort.success(); } - }, validationEffort.success); + }, function() { + validationEffort.success(); + }); } else { validationEffort.success(); From 3417d6e975a24a7ac39603a3de2d7da43e8df106 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 15:08:59 +1100 Subject: [PATCH 27/73] refactor: qq.ImageValidation.validate to use Promise --- client/js/image-support/validation.image.js | 26 +++++++++------------ client/js/uploader.basic.api.js | 3 ++- test/unit/validation.image.js | 3 ++- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/client/js/image-support/validation.image.js b/client/js/image-support/validation.image.js index 04e3900cf..89c6584a8 100644 --- a/client/js/image-support/validation.image.js +++ b/client/js/image-support/validation.image.js @@ -101,33 +101,29 @@ qq.ImageValidation = function(blob, log) { * Validate the associated blob. * * @param limits - * @returns {qq.Promise} `success` is called on the promise is the image is valid or - * if the blob is not an image, or if the image is not verifiable. - * Otherwise, `failure` with the name of the failing limit. + * @returns {Promise} Resolved if the image is valid or if the blob is + * not an image, or if the image is not verifiable. Otherwise, it is + * rejected with an error with a `failingLimit: string` property . */ this.validate = function(limits) { - var validationEffort = new qq.Promise(); - log("Attempting to validate image."); if (hasNonZeroLimits(limits)) { - getWidthHeight().then(function(dimensions) { - var failingLimit = getFailingLimit(limits, dimensions); + return getWidthHeight().then(function(dimensions) { + var failingLimit = getFailingLimit(limits, dimensions), + error; if (failingLimit) { - validationEffort.failure(failingLimit); - } - else { - validationEffort.success(); + error = new Error(qq.format("Invalid image, failing limit: {}", failingLimit)); + error.failingLimit = failingLimit; + throw error; } }, function() { - validationEffort.success(); + // Not being an image is considered valid. }); } else { - validationEffort.success(); + return Promise.resolve(); } - - return validationEffort; }; }; diff --git a/client/js/uploader.basic.api.js b/client/js/uploader.basic.api.js index 6eaf4919d..97172788d 100644 --- a/client/js/uploader.basic.api.js +++ b/client/js/uploader.basic.api.js @@ -1935,7 +1935,8 @@ if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) { new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then( validityChecker.success, - function(errorCode) { + function(error) { + var errorCode = error.failingLimit; self._itemError(errorCode + "ImageError", name, file); validityChecker.failure(); } diff --git a/test/unit/validation.image.js b/test/unit/validation.image.js index 62498673c..7dc5a01c9 100644 --- a/test/unit/validation.image.js +++ b/test/unit/validation.image.js @@ -27,7 +27,8 @@ if (qq.supportedFeatures.imageValidation && qqtest.canDownloadFileAsBlob) { done(); }, - function(code) { + function(error) { + var code = error.failingLimit; assert.equal(code, expectedErrorCode); done(); }); From 59e134ec6bc0e5fbcdb3c00dd21e6a3d1242adc0 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 15:12:29 +1100 Subject: [PATCH 28/73] refactor: qq.ImageGenerator dummyExif to use Promise --- client/js/image-support/image.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/js/image-support/image.js b/client/js/image-support/image.js index 62a93c9c1..545170852 100644 --- a/client/js/image-support/image.js +++ b/client/js/image-support/image.js @@ -152,7 +152,7 @@ qq.ImageGenerator = function(log) { // replace the orient task with a dummy promise that "succeeds" immediately. var dummyExif = { parse: function() { - return new qq.Promise().success(); + return Promise.resolve(); } }, exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif, From 5e10cbb6fef8450096476c8385573277ed3cf7ed Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 16:00:03 +1100 Subject: [PATCH 29/73] refactor: registerThumbnailRenderedListener to use Promise --- client/js/image-support/image.js | 214 +++++++++++++++++-------------- 1 file changed, 116 insertions(+), 98 deletions(-) diff --git a/client/js/image-support/image.js b/client/js/image-support/image.js index 545170852..4021736c9 100644 --- a/client/js/image-support/image.js +++ b/client/js/image-support/image.js @@ -83,123 +83,137 @@ qq.ImageGenerator = function(log) { return false; } - function registerImgLoadListeners(img, promise) { - img.onload = function() { - img.onload = null; - img.onerror = null; - promise.success(img); - }; - - img.onerror = function() { - img.onload = null; - img.onerror = null; - log("Problem drawing thumbnail!", "error"); - promise.failure(img, "Problem drawing thumbnail!"); - }; + function registerImgLoadListeners(img) { + return new Promise(function(resolve, reject) { + img.onload = function() { + img.onload = null; + img.onerror = null; + resolve(img); + }; + + img.onerror = function() { + var error = new Error("Problem drawing thumbnail!"); + error.img = img; + img.onload = null; + img.onerror = null; + log("Problem drawing thumbnail!", "error"); + reject(error); + }; + }); } - function registerCanvasDrawImageListener(canvas, promise) { - // The image is drawn on the canvas by a third-party library, - // and we want to know when this is completed. Since the library - // may invoke drawImage many times in a loop, we need to be called - // back when the image is fully rendered. So, we are expecting the - // code that draws this image to follow a convention that involves a - // function attached to the canvas instance be invoked when it is done. - canvas.qqImageRendered = function() { - promise.success(canvas); - }; + function registerCanvasDrawImageListener(canvas) { + return new Promise(function(resolve) { + // The image is drawn on the canvas by a third-party library, + // and we want to know when this is completed. Since the library + // may invoke drawImage many times in a loop, we need to be called + // back when the image is fully rendered. So, we are expecting the + // code that draws this image to follow a convention that involves a + // function attached to the canvas instance be invoked when it is done. + canvas.qqImageRendered = function() { + resolve(canvas); + }; + }); } - // Fulfills a `qq.Promise` when an image has been drawn onto the target, - // whether that is a or an . The attempt is considered a - // failure if the target is not an or a , or if the drawing - // attempt was not successful. - function registerThumbnailRenderedListener(imgOrCanvas, promise) { - var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas); + // Returns a `Promise` that is resolved when an image has been drawn onto + // the target, whether that is a or an . The attempt is + // considered a failure if the target is not an or a , or if + // the drawing attempt was not successful. + function registerThumbnailRenderedListener(imgOrCanvas) { + var registered = isImg(imgOrCanvas) || isCanvas(imgOrCanvas), + promise, + error; if (isImg(imgOrCanvas)) { - registerImgLoadListeners(imgOrCanvas, promise); + promise = registerImgLoadListeners(imgOrCanvas); } else if (isCanvas(imgOrCanvas)) { - registerCanvasDrawImageListener(imgOrCanvas, promise); + promise = registerCanvasDrawImageListener(imgOrCanvas); } else { - promise.failure(imgOrCanvas); - log(qq.format("Element container of type {} is not supported!", imgOrCanvas.tagName), "error"); + error = new Error(qq.format("Element container of type {} is not supported!", imgOrCanvas.tagName)); + error.imgOrCanvas = imgOrCanvas; + promise = Promise.reject(error); + log(error.message, "error"); } - return registered; + return { registered: registered, promise: promise }; } // Draw a preview iff the current UA can natively display it. // Also rotate the image if necessary. function draw(fileOrBlob, container, options) { - var drawPreview = new qq.Promise(), - identifier = new qq.Identify(fileOrBlob, log), - maxSize = options.maxSize, - // jshint eqnull:true - orient = options.orient == null ? true : options.orient, - megapixErrorHandler = function() { - container.onerror = null; - container.onload = null; - log("Could not render preview, file may be too large!", "error"); - drawPreview.failure(container, "Browser cannot render image!"); - }; - - identifier.isPreviewable().then( - function(mime) { - // If options explicitly specify that Orientation is not desired, - // replace the orient task with a dummy promise that "succeeds" immediately. - var dummyExif = { - parse: function() { - return Promise.resolve(); - } - }, - exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif, - mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler); - - if (registerThumbnailRenderedListener(container, drawPreview)) { - exif.parse().then( - function(exif) { - var orientation = exif && exif.Orientation; - - mpImg.render(container, { - maxWidth: maxSize, - maxHeight: maxSize, - orientation: orientation, - mime: mime, - resize: options.customResizeFunction - }); + return new Promise(function(resolve, reject) { + var identifier = new qq.Identify(fileOrBlob, log), + maxSize = options.maxSize, + // jshint eqnull:true + orient = options.orient == null ? true : options.orient, + megapixErrorHandler = function() { + var error = new Error("Browser cannot render image!"); + error.container = container; + container.onerror = null; + container.onload = null; + log("Could not render preview, file may be too large!", "error"); + reject(error); + }; + + identifier.isPreviewable().then( + function(mime) { + // If options explicitly specify that Orientation is not desired, + // replace the orient task with a dummy promise that "succeeds" immediately. + var dummyExif = { + parse: function() { + return Promise.resolve(); + } }, - - function(error) { - log(qq.format("EXIF data could not be parsed ({}). Assuming orientation = 1.", error.message)); - - mpImg.render(container, { - maxWidth: maxSize, - maxHeight: maxSize, - mime: mime, - resize: options.customResizeFunction - }); - } - ); + exif = orient ? new qq.Exif(fileOrBlob, log) : dummyExif, + mpImg = new qq.MegaPixImage(fileOrBlob, megapixErrorHandler), + thumbnailRenderedListenerResult = registerThumbnailRenderedListener(container); + + thumbnailRenderedListenerResult.promise.then(resolve, reject); + + if (thumbnailRenderedListenerResult.registered) { + exif.parse().then( + function(exif) { + var orientation = exif && exif.Orientation; + + mpImg.render(container, { + maxWidth: maxSize, + maxHeight: maxSize, + orientation: orientation, + mime: mime, + resize: options.customResizeFunction + }); + }, + + function(error) { + log(qq.format("EXIF data could not be parsed ({}). Assuming orientation = 1.", error.message)); + + mpImg.render(container, { + maxWidth: maxSize, + maxHeight: maxSize, + mime: mime, + resize: options.customResizeFunction + }); + } + ); + } + }, + + function() { + var error = new Error("Not previewable"); + error.container = container; + log("Not previewable"); + reject(error); } - }, - - function() { - log("Not previewable"); - drawPreview.failure(container, "Not previewable"); - } - ); - - return drawPreview; + ); + }); } function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) { var tempImg = new Image(), - tempImgRender = new qq.Promise(); - - registerThumbnailRenderedListener(tempImg, tempImgRender); + tempImgRender = registerThumbnailRenderedListener(tempImg).promise; if (isCrossOrigin(url)) { tempImg.crossOrigin = "anonymous"; @@ -209,7 +223,7 @@ qq.ImageGenerator = function(log) { tempImgRender.then( function rendered() { - registerThumbnailRenderedListener(canvasOrImg, draw); + registerThumbnailRenderedListener(canvasOrImg).promise.then(draw.success, draw.failure); var mpImg = new qq.MegaPixImage(tempImg); mpImg.render(canvasOrImg, { @@ -225,7 +239,7 @@ qq.ImageGenerator = function(log) { } function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) { - registerThumbnailRenderedListener(img, draw); + registerThumbnailRenderedListener(img).promise.then(draw.success, draw.failure); // NOTE: The fact that maxWidth/height is set on the thumbnail for scaled images // that must drop back to CSS is known and exploited by the templating module. // In this module, we pre-render "waiting" thumbs for all files immediately after they @@ -275,8 +289,12 @@ qq.ImageGenerator = function(log) { drawOnCanvasOrImgFromUrl(url, container, draw, maxSize); } // container is an img & no scaling: just set the src attr to the passed url - else if (registerThumbnailRenderedListener(container, draw)) { - container.src = url; + else { + var thumbnailRenderedListenerResult = registerThumbnailRenderedListener(container); + thumbnailRenderedListenerResult.promise.then(draw.success, draw.failure); + if (thumbnailRenderedListenerResult.registered) { + container.src = url; + } } return draw; From 027ae2106bac09f3f36fe084fa825c7a1e161b68 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 16:06:00 +1100 Subject: [PATCH 30/73] refactor: lint --- client/js/dnd.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/client/js/dnd.js b/client/js/dnd.js index acf590a6b..23fed2200 100644 --- a/client/js/dnd.js +++ b/client/js/dnd.js @@ -89,8 +89,7 @@ qq.DragAndDrop = function(o) { // Promissory. Guaranteed to read all files in the root of the passed directory. function getFilesInDirectory(entry, reader, accumEntries) { - var promise = existingPromise, - dirReader = reader || entry.createReader(); + var dirReader = reader || entry.createReader(); return new Promise(function(resolve, reject) { dirReader.readEntries( From 765f9c33e695834d8ffca3ced0abc2b633bc12d4 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 16:09:03 +1100 Subject: [PATCH 31/73] refactor: drawFromUrl to use Promise --- client/js/image-support/image.js | 78 +++++++++++++++++--------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/client/js/image-support/image.js b/client/js/image-support/image.js index 4021736c9..ce9f02723 100644 --- a/client/js/image-support/image.js +++ b/client/js/image-support/image.js @@ -211,35 +211,38 @@ qq.ImageGenerator = function(log) { }); } - function drawOnCanvasOrImgFromUrl(url, canvasOrImg, draw, maxSize, customResizeFunction) { - var tempImg = new Image(), - tempImgRender = registerThumbnailRenderedListener(tempImg).promise; + function drawOnCanvasOrImgFromUrl(url, canvasOrImg, maxSize, customResizeFunction) { + return new Promise(function(resolve, reject) { + var tempImg = new Image(), + tempImgRender = registerThumbnailRenderedListener(tempImg).promise; - if (isCrossOrigin(url)) { - tempImg.crossOrigin = "anonymous"; - } + if (isCrossOrigin(url)) { + tempImg.crossOrigin = "anonymous"; + } - tempImg.src = url; + tempImg.src = url; - tempImgRender.then( - function rendered() { - registerThumbnailRenderedListener(canvasOrImg).promise.then(draw.success, draw.failure); + tempImgRender.then( + function rendered() { + registerThumbnailRenderedListener(canvasOrImg).promise.then(resolve, reject); - var mpImg = new qq.MegaPixImage(tempImg); - mpImg.render(canvasOrImg, { - maxWidth: maxSize, - maxHeight: maxSize, - mime: determineMimeOfFileName(url), - resize: customResizeFunction - }); - }, + var mpImg = new qq.MegaPixImage(tempImg); + mpImg.render(canvasOrImg, { + maxWidth: maxSize, + maxHeight: maxSize, + mime: determineMimeOfFileName(url), + resize: customResizeFunction + }); + }, - draw.failure - ); + reject + ); + }); } - function drawOnImgFromUrlWithCssScaling(url, img, draw, maxSize) { - registerThumbnailRenderedListener(img).promise.then(draw.success, draw.failure); + function drawOnImgFromUrlWithCssScaling(url, img, maxSize) { + var promise = registerThumbnailRenderedListener(img).promise; + // NOTE: The fact that maxWidth/height is set on the thumbnail for scaled images // that must drop back to CSS is known and exploited by the templating module. // In this module, we pre-render "waiting" thumbs for all files immediately after they @@ -250,6 +253,7 @@ qq.ImageGenerator = function(log) { }); img.src = url; + return promise; } // Draw a (server-hosted) thumbnail given a URL. @@ -261,8 +265,7 @@ qq.ImageGenerator = function(log) { // which is required to scale a cross-origin image using & // then export it back to an . function drawFromUrl(url, container, options) { - var draw = new qq.Promise(), - scale = options.scale, + var scale = options.scale, maxSize = scale ? options.maxSize : null; // container is an img, scaling needed @@ -274,30 +277,30 @@ qq.ImageGenerator = function(log) { // but we must fall back to scaling via CSS/styles // if this is a cross-origin image and the UA doesn't support CORS. if (isCrossOrigin(url) && !isImgCorsSupported()) { - drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize); + return drawOnImgFromUrlWithCssScaling(url, container, maxSize); } else { - drawOnCanvasOrImgFromUrl(url, container, draw, maxSize); + return drawOnCanvasOrImgFromUrl(url, container, maxSize); } } else { - drawOnImgFromUrlWithCssScaling(url, container, draw, maxSize); + return drawOnImgFromUrlWithCssScaling(url, container, maxSize); } } // container is a canvas, scaling optional else if (isCanvas(container)) { - drawOnCanvasOrImgFromUrl(url, container, draw, maxSize); + return drawOnCanvasOrImgFromUrl(url, container, maxSize); } // container is an img & no scaling: just set the src attr to the passed url else { - var thumbnailRenderedListenerResult = registerThumbnailRenderedListener(container); - thumbnailRenderedListenerResult.promise.then(draw.success, draw.failure); - if (thumbnailRenderedListenerResult.registered) { - container.src = url; - } + return new Promise(function(resolve, reject) { + var thumbnailRenderedListenerResult = registerThumbnailRenderedListener(container); + thumbnailRenderedListenerResult.promise.then(resolve, reject); + if (thumbnailRenderedListenerResult.registered) { + container.src = url; + } + }); } - - return draw; } qq.extend(this, { @@ -312,9 +315,12 @@ qq.ImageGenerator = function(log) { * @returns qq.Promise fulfilled when the preview has been drawn, or the attempt has failed */ generate: function(fileBlobOrUrl, container, options) { + var promise = new qq.Promise(); + if (qq.isString(fileBlobOrUrl)) { log("Attempting to update thumbnail based on server response."); - return drawFromUrl(fileBlobOrUrl, container, options || {}); + drawFromUrl(fileBlobOrUrl, container, options || {}).then(promise.success, promise.failure); + return promise; } else { log("Attempting to draw client-side image preview."); From 183641255d36eba8d8352c5aec6e5a45f11b344c Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 16:15:06 +1100 Subject: [PATCH 32/73] refactor: qq.ImageGenerator.generate to use Promise --- client/js/image-support/image.js | 8 +++----- client/js/uploader.basic.api.js | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/client/js/image-support/image.js b/client/js/image-support/image.js index ce9f02723..388b9c176 100644 --- a/client/js/image-support/image.js +++ b/client/js/image-support/image.js @@ -133,7 +133,7 @@ qq.ImageGenerator = function(log) { } else { error = new Error(qq.format("Element container of type {} is not supported!", imgOrCanvas.tagName)); - error.imgOrCanvas = imgOrCanvas; + error.container = imgOrCanvas; promise = Promise.reject(error); log(error.message, "error"); } @@ -312,15 +312,13 @@ qq.ImageGenerator = function(log) { * @param fileBlobOrUrl a `File`, `Blob`, or a URL pointing to the image * @param container or to contain the preview * @param options possible properties include `maxSize` (int), `orient` (bool - default true), resize` (bool - default true), and `customResizeFunction`. - * @returns qq.Promise fulfilled when the preview has been drawn, or the attempt has failed + * @returns {Promise} resolved when the preview has been drawn, or the attempt has failed */ generate: function(fileBlobOrUrl, container, options) { - var promise = new qq.Promise(); if (qq.isString(fileBlobOrUrl)) { log("Attempting to update thumbnail based on server response."); - drawFromUrl(fileBlobOrUrl, container, options || {}).then(promise.success, promise.failure); - return promise; + return drawFromUrl(fileBlobOrUrl, container, options || {}); } else { log("Attempting to draw client-side image preview."); diff --git a/client/js/uploader.basic.api.js b/client/js/uploader.basic.api.js index 97172788d..52ad8bac8 100644 --- a/client/js/uploader.basic.api.js +++ b/client/js/uploader.basic.api.js @@ -198,8 +198,8 @@ promiseToReturn.success(modifiedContainer); }, - function failure(container, reason) { - promiseToReturn.failure({container: container, error: reason || "Problem generating thumbnail"}); + function failure(error) { + promiseToReturn.failure({container: error.container, error: error.message || "Problem generating thumbnail"}); } ); } From acaf7f3a3ae10569204e1c2721e20b54bdbb32d3 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 18:59:09 +1100 Subject: [PATCH 33/73] refactor: qq.s3.AbortMultipartAjaxRequester getHeaders to use Promise --- .../js/s3/multipart.abort.ajax.requester.js | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/client/js/s3/multipart.abort.ajax.requester.js b/client/js/s3/multipart.abort.ajax.requester.js index 973e28d0e..e800779a2 100644 --- a/client/js/s3/multipart.abort.ajax.requester.js +++ b/client/js/s3/multipart.abort.ajax.requester.js @@ -34,26 +34,36 @@ qq.s3.AbortMultipartAjaxRequester = function(o) { /** * Attach all required headers (including Authorization) to the "Abort" request. This is a promissory function - * that will fulfill the associated promise once all headers have been attached or when an error has occurred that + * that will resolve the associated promise once all headers have been attached or when an error has occurred that * prevents headers from being attached. * * @param id Associated file ID * @param uploadId ID of the associated upload, according to AWS - * @returns {qq.Promise} + * @returns {Promise} */ function getHeaders(id, uploadId) { var headers = {}, - promise = new qq.Promise(), bucket = options.getBucket(id), host = options.getHost(id), signatureConstructor = getSignatureAjaxRequester.constructStringToSign (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_ABORT, bucket, host, options.getKey(id)) .withUploadId(uploadId); - // Ask the local server to sign the request. Use this signature to form the Authorization header. - getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure); - - return promise; + return new Promise(function(resolve, reject) { + // Ask the local server to sign the request. Use this signature to form the Authorization header. + getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then( + function (signedPolicy, updatedAccessKey, updatedSessionToken) { + resolve({ + signedPolicy: signedPolicy, + updatedAccessKey: updatedAccessKey, + updatedSessionToken: updatedSessionToken + }); + }, + function (reason) { + reject(new Error(reason)); + } + ); + }); } /** From 3d3bc7cc046428c52016aa584633a7d5c3549cc2 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 19:07:25 +1100 Subject: [PATCH 34/73] refactor: qq.s3.RequestSigner getEncodedHashedPayload to use Promise --- client/js/s3/request-signer.js | 47 ++++++++++++++++----------------- test/unit/s3/chunked-uploads.js | 18 ++++++++----- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/client/js/s3/request-signer.js b/client/js/s3/request-signer.js index cccc531fd..25f78b499 100644 --- a/client/js/s3/request-signer.js +++ b/client/js/s3/request-signer.js @@ -152,31 +152,30 @@ qq.s3.RequestSigner = function(o) { }, getEncodedHashedPayload: function(body) { - var promise = new qq.Promise(), - reader; - - if (qq.isBlob(body)) { - // TODO hash blob in webworker if this becomes a notable perf issue - reader = new FileReader(); - reader.onloadend = function(e) { - if (e.target.readyState === FileReader.DONE) { - if (e.target.error) { - promise.failure(e.target.error); - } - else { - var wordArray = qq.CryptoJS.lib.WordArray.create(e.target.result); - promise.success(qq.CryptoJS.SHA256(wordArray).toString()); + return new Promise(function(resolve, reject) { + var reader; + + if (qq.isBlob(body)) { + // TODO hash blob in webworker if this becomes a notable perf issue + reader = new FileReader(); + reader.onloadend = function(e) { + if (e.target.readyState === FileReader.DONE) { + if (e.target.error) { + reject(e.target.error); + } + else { + var wordArray = qq.CryptoJS.lib.WordArray.create(e.target.result); + resolve(qq.CryptoJS.SHA256(wordArray).toString()); + } } - } - }; - reader.readAsArrayBuffer(body); - } - else { - body = body || ""; - promise.success(qq.CryptoJS.SHA256(body).toString()); - } - - return promise; + }; + reader.readAsArrayBuffer(body); + } + else { + body = body || ""; + resolve(qq.CryptoJS.SHA256(body).toString()); + } + }); }, getScope: function(date, region) { diff --git a/test/unit/s3/chunked-uploads.js b/test/unit/s3/chunked-uploads.js index 61b86a1f1..99318ac54 100644 --- a/test/unit/s3/chunked-uploads.js +++ b/test/unit/s3/chunked-uploads.js @@ -24,12 +24,14 @@ if (qqtest.canDownloadFileAsBlob) { fileTestHelper.mockXhr(); uploader.addFiles({name: "test.jpg", blob: blob}); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - initiateSignatureRequest = fileTestHelper.getRequests()[0]; - initiateToSign = JSON.parse(initiateSignatureRequest.requestBody); + initiateSignatureRequest = fileTestHelper.getRequests()[0]; + initiateToSign = JSON.parse(initiateSignatureRequest.requestBody); - callback(initiateSignatureRequest, initiateToSign, uploadRequest); + callback(initiateSignatureRequest, initiateToSign, uploadRequest); + }, 0); }); }, testSignatureEndoint = "/signature", @@ -810,11 +812,13 @@ if (qqtest.canDownloadFileAsBlob) { fileTestHelper.mockXhr(); uploader.addFiles({name: "test.jpg", blob: blob}); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - uploadRequest = fileTestHelper.getRequests()[0]; + uploadRequest = fileTestHelper.getRequests()[0]; - callback(uploadRequest); + callback(uploadRequest); + }, 0); }); }, testSecretKey = "testSecrtKey", From befcefe75c3540b4565dd155a1882b96d00467ed Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 19:25:33 +1100 Subject: [PATCH 35/73] refactor: qq.s3.RequestSigner getStringToSignArtifacts to use Promise --- client/js/s3/request-signer.js | 33 +- test/unit/s3/cdn/generic-chunked.js | 86 ++-- test/unit/s3/chunked-uploads.js | 704 +++++++++++++++------------- 3 files changed, 429 insertions(+), 394 deletions(-) diff --git a/client/js/s3/request-signer.js b/client/js/s3/request-signer.js index 25f78b499..2cd06db71 100644 --- a/client/js/s3/request-signer.js +++ b/client/js/s3/request-signer.js @@ -322,8 +322,7 @@ qq.s3.RequestSigner = function(o) { } function getStringToSignArtifacts(id, version, requestInfo) { - var promise = new qq.Promise(), - method = "POST", + var method = "POST", headerNames = [], headersStr = "", now = new Date(), @@ -398,23 +397,21 @@ qq.s3.RequestSigner = function(o) { endOfUrl = requestInfo.key + "?" + endOfUrl; - if (version === 4) { - v4.getEncodedHashedPayload(requestInfo.content).then(function(hashedContent) { - requestInfo.headers["x-amz-content-sha256"] = hashedContent; - requestInfo.headers.Host = requestInfo.host; - requestInfo.headers["x-amz-date"] = qq.s3.util.getV4PolicyDate(now, options.signatureSpec.drift); - requestInfo.hashedContent = hashedContent; + return new Promise(function(resolve, reject) { + if (version === 4) { + v4.getEncodedHashedPayload(requestInfo.content).then(function(hashedContent) { + requestInfo.headers["x-amz-content-sha256"] = hashedContent; + requestInfo.headers.Host = requestInfo.host; + requestInfo.headers["x-amz-date"] = qq.s3.util.getV4PolicyDate(now, options.signatureSpec.drift); + requestInfo.hashedContent = hashedContent; - promise.success(generateStringToSign(requestInfo)); - }, function (err) { - promise.failure(err); - }); - } - else { - promise.success(generateStringToSign(requestInfo)); - } - - return promise; + resolve(generateStringToSign(requestInfo)); + }, reject); + } + else { + resolve(generateStringToSign(requestInfo)); + } + }); } function determineSignatureClientSide(id, toBeSigned, signatureEffort, updatedAccessKey, updatedSessionToken) { diff --git a/test/unit/s3/cdn/generic-chunked.js b/test/unit/s3/cdn/generic-chunked.js index 8fdac18a1..dc84d0392 100644 --- a/test/unit/s3/cdn/generic-chunked.js +++ b/test/unit/s3/cdn/generic-chunked.js @@ -33,55 +33,59 @@ if (qqtest.canDownloadFileAsBlob) { fileTestHelper.mockXhr(); uploader.addFiles({name: "test.jpg", blob: blob}); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - - initiateSignatureRequest = fileTestHelper.getRequests()[0]; - initiateToSign = JSON.parse(initiateSignatureRequest.requestBody); - - // signature request for initiate multipart upload - assert.ok(initiateToSign.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?uploads") > 0); - initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // initiate multipart upload request - initiateRequest = fileTestHelper.getRequests()[1]; - initiateRequest.respond(200, null, "123"); - - // signature request for upload part 1 - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - // upload part 1 request - uploadPartRequest = fileTestHelper.getRequests()[2]; - uploadPartRequest.respond(200, {ETag: "etag1"}, null); + initiateSignatureRequest = fileTestHelper.getRequests()[0]; + initiateToSign = JSON.parse(initiateSignatureRequest.requestBody); - setTimeout(function() { - // signature request for upload part 2 - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + // signature request for initiate multipart upload + assert.ok(initiateToSign.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?uploads") > 0); + initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - // upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[4]; - uploadPartRequest.respond(200, {ETag: "etag2"}, null); + // initiate multipart upload request + initiateRequest = fileTestHelper.getRequests()[1]; + initiateRequest.respond(200, null, "123"); setTimeout(function() { - // signature request for multipart complete - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + // signature request for upload part 1 + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); - // multipart complete request - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - multipartCompleteRequest.respond(200, null, "mybucket" + uploader.getKey(0) + ""); + // upload part 1 request + uploadPartRequest = fileTestHelper.getRequests()[2]; + uploadPartRequest.respond(200, {ETag: "etag1"}, null); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - - done(); + // signature request for upload part 2 + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[4]; + uploadPartRequest.respond(200, {ETag: "etag2"}, null); + + setTimeout(function() { + // signature request for multipart complete + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // multipart complete request + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + multipartCompleteRequest.respond(200, null, "mybucket" + uploader.getKey(0) + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + + done(); + }, 0); + }, 0); }, 0); }, 0); }, 0); diff --git a/test/unit/s3/chunked-uploads.js b/test/unit/s3/chunked-uploads.js index 99318ac54..bea7c0185 100644 --- a/test/unit/s3/chunked-uploads.js +++ b/test/unit/s3/chunked-uploads.js @@ -338,82 +338,84 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(initiateRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); initiateRequest.respond(200, null, "123"); - // signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 4); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; - assert.equal(uploadPartSignatureRequest1.method, "POST"); - assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); - assert.equal(uploadPartSignatureRequest1.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers); - assert.equal(uploadPartToSign1.headers.indexOf("PUT"), 0); - assert.ok(uploadPartToSign1.headers.indexOf("x-amz-date:") > 0); - assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // upload part 1 request - uploadPartRequest = fileTestHelper.getRequests()[2]; - assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); - - assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); - - assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); - uploadPartRequest.respond(200, {ETag: "etag1"}, null); - setTimeout(function() { - // signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 6); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; - assert.equal(uploadPartSignatureRequest2.method, "POST"); - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - assert.equal(uploadPartSignatureRequest2.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers); - assert.equal(uploadPartToSign2.headers.indexOf("PUT"), 0); - assert.ok(uploadPartToSign2.headers.indexOf("x-amz-date:") > 0); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[4]; + // signature request for upload part 1 + assert.equal(fileTestHelper.getRequests().length, 4); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; + assert.equal(uploadPartSignatureRequest1.method, "POST"); + assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); + assert.equal(uploadPartSignatureRequest1.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers); + assert.equal(uploadPartToSign1.headers.indexOf("PUT"), 0); + assert.ok(uploadPartToSign1.headers.indexOf("x-amz-date:") > 0); + assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // upload part 1 request + uploadPartRequest = fileTestHelper.getRequests()[2]; assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); - uploadPartRequest.respond(200, {ETag: "etag2"}, null); + uploadPartRequest.respond(200, {ETag: "etag1"}, null); setTimeout(function() { - // signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 7); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; - assert.equal(uploadCompleteSignatureRequest.method, "POST"); - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - assert.equal(uploadCompleteSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers); - assert.equal(uploadCompleteToSign.headers.indexOf("POST"), 0); - assert.ok(uploadCompleteToSign.headers.indexOf("x-amz-date:") > 0); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // multipart complete request - assert.equal(fileTestHelper.getRequests().length, 8); - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - assert.equal(multipartCompleteRequest.method, "POST"); - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); - assert.equal(multipartCompleteRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); - assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + // signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 6); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; + assert.equal(uploadPartSignatureRequest2.method, "POST"); + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + assert.equal(uploadPartSignatureRequest2.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers); + assert.equal(uploadPartToSign2.headers.indexOf("PUT"), 0); + assert.ok(uploadPartToSign2.headers.indexOf("x-amz-date:") > 0); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[4]; + assert.equal(uploadPartRequest.method, "PUT"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); + + assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); + + assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); + uploadPartRequest.respond(200, {ETag: "etag2"}, null); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + // signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 7); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; + assert.equal(uploadCompleteSignatureRequest.method, "POST"); + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + assert.equal(uploadCompleteSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers); + assert.equal(uploadCompleteToSign.headers.indexOf("POST"), 0); + assert.ok(uploadCompleteToSign.headers.indexOf("x-amz-date:") > 0); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // multipart complete request + assert.equal(fileTestHelper.getRequests().length, 8); + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + assert.equal(multipartCompleteRequest.method, "POST"); + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); + assert.equal(multipartCompleteRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); + assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + done(); + }, 0); }, 0); }, 0); }, 0); @@ -456,49 +458,51 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(initiateRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME], qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE); initiateRequest.respond(200, null, "123"); - // signature request for upload part 1 - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers.indexOf(qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME + ":" + qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE) < 0); - assert.ok(uploadPartToSign1.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) < 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // upload part 1 request - uploadPartRequest = fileTestHelper.getRequests()[2]; - assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]); - assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); - uploadPartRequest.respond(200, {ETag: "etag1"}, null); - - setTimeout(function () { - // signature request for upload part 2 - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf(qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME + ":" + qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE) < 0); - assert.ok(uploadPartToSign2.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) < 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[4]; + setTimeout(function() { + // signature request for upload part 1 + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers.indexOf(qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME + ":" + qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE) < 0); + assert.ok(uploadPartToSign1.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) < 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // upload part 1 request + uploadPartRequest = fileTestHelper.getRequests()[2]; assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]); assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); uploadPartRequest.respond(200, {ETag: "etag1"}, null); setTimeout(function () { - // signature request for multipart complete - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf(qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME + ":" + qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE) < 0); - assert.ok(uploadCompleteToSign.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) < 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // multipart complete request - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - assert.ok(!multipartCompleteRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]); - assert.ok(!multipartCompleteRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + // signature request for upload part 2 + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf(qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME + ":" + qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE) < 0); + assert.ok(uploadPartToSign2.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) < 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[4]; + assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]); + assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); + uploadPartRequest.respond(200, {ETag: "etag1"}, null); setTimeout(function () { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + // signature request for multipart complete + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf(qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME + ":" + qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE) < 0); + assert.ok(uploadCompleteToSign.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) < 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // multipart complete request + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + assert.ok(!multipartCompleteRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]); + assert.ok(!multipartCompleteRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + + setTimeout(function () { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + }, 0); }, 0); }, 0); }, 0); @@ -552,194 +556,212 @@ if (qqtest.canDownloadFileAsBlob) { setTimeout(function() { assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); uploader.retry(0); - assert.equal(fileTestHelper.getRequests().length, 2); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful initiate signature request - initiateSignatureRequest = fileTestHelper.getRequests()[1]; - assert.equal(initiateSignatureRequest.url, testSignatureEndoint); - assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploads") > 0); - initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // failing initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 3); - initiateRequest = fileTestHelper.getRequests()[2]; - assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); - initiateRequest.respond(200, null, ""); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 3); - uploader.retry(0); + assert.equal(fileTestHelper.getRequests().length, 2); assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); // successful initiate signature request - assert.equal(fileTestHelper.getRequests().length, 4); - initiateSignatureRequest = fileTestHelper.getRequests()[3]; + initiateSignatureRequest = fileTestHelper.getRequests()[1]; assert.equal(initiateSignatureRequest.url, testSignatureEndoint); assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploads") > 0); initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - // successful initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 5); - initiateRequest = fileTestHelper.getRequests()[4]; + // failing initiate multipart upload request + assert.equal(fileTestHelper.getRequests().length, 3); + initiateRequest = fileTestHelper.getRequests()[2]; assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); - initiateRequest.respond(200, null, "123"); - - // failed signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 7); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[6]; - assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({invalid: true})); + initiateRequest.respond(200, null, ""); setTimeout(function() { assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 7); + assert.equal(fileTestHelper.getRequests().length, 3); uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 9); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[8]; - assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // failing upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 9); - uploadPartRequest = fileTestHelper.getRequests()[7]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - uploadPartRequest.respond(404, {ETag: "etag1"}, null); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 9); - uploader.retry(0); assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - // successful signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 11); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[10]; - assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + // successful initiate signature request + assert.equal(fileTestHelper.getRequests().length, 4); + initiateSignatureRequest = fileTestHelper.getRequests()[3]; + assert.equal(initiateSignatureRequest.url, testSignatureEndoint); + assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploads") > 0); + initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - // successful upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 11); - uploadPartRequest = fileTestHelper.getRequests()[9]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - uploadPartRequest.respond(200, {ETag: "etag1_a"}, null); + // successful initiate multipart upload request + assert.equal(fileTestHelper.getRequests().length, 5); + initiateRequest = fileTestHelper.getRequests()[4]; + assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); + initiateRequest.respond(200, null, "123"); setTimeout(function() { - // failing signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 13); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[12]; - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(404, null, JSON.stringify({signature: "thesignature"})); + // failed signature request for upload part 1 + assert.equal(fileTestHelper.getRequests().length, 7); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[6]; + assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({invalid: true})); setTimeout(function() { assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 13); + assert.equal(fileTestHelper.getRequests().length, 7); uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 15); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[14]; - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - setTimeout(function() { - // failing upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[13]; - assert.equal(fileTestHelper.getRequests().length, 15); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - uploadPartRequest.respond(404, {ETag: "etag2"}, null); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for upload part 1 + assert.equal(fileTestHelper.getRequests().length, 9); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[8]; + assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // failing upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 9); + uploadPartRequest = fileTestHelper.getRequests()[7]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); + uploadPartRequest.respond(404, {ETag: "etag1"}, null); setTimeout(function() { assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 15); + assert.equal(fileTestHelper.getRequests().length, 9); uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 17); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[16]; - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // successful upload part 2 request - assert.equal(fileTestHelper.getRequests().length, 17); - uploadPartRequest = fileTestHelper.getRequests()[15]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - uploadPartRequest.respond(200, {ETag: "etag2_a"}, null); - setTimeout(function() { - // failing signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 18); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[17]; - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(400, null, JSON.stringify({signature: "thesignature"})); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for upload part 1 + assert.equal(fileTestHelper.getRequests().length, 11); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[10]; + assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // successful upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 11); + uploadPartRequest = fileTestHelper.getRequests()[9]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); + uploadPartRequest.respond(200, {ETag: "etag1_a"}, null); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 18); - uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 19); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[18]; - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // failing multipart complete request - assert.equal(fileTestHelper.getRequests().length, 20); - multipartCompleteRequest = fileTestHelper.getRequests()[19]; - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + uploader.getKey(0) + ""); + // failing signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 13); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[12]; + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(404, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 20); + assert.equal(fileTestHelper.getRequests().length, 13); uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 21); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[20]; - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - setTimeout(function() { - // successful multipart complete request - assert.equal(fileTestHelper.getRequests().length, 22); - multipartCompleteRequest = fileTestHelper.getRequests()[21]; - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + // successful signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 15); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[14]; + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - done(); + setTimeout(function() { + // failing upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[13]; + assert.equal(fileTestHelper.getRequests().length, 15); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + uploadPartRequest.respond(404, {ETag: "etag2"}, null); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 15); + uploader.retry(0); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 17); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[16]; + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // successful upload part 2 request + assert.equal(fileTestHelper.getRequests().length, 17); + uploadPartRequest = fileTestHelper.getRequests()[15]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + uploadPartRequest.respond(200, {ETag: "etag2_a"}, null); + + setTimeout(function() { + // failing signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 18); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[17]; + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(400, null, JSON.stringify({signature: "thesignature"})); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 18); + uploader.retry(0); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 19); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[18]; + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // failing multipart complete request + assert.equal(fileTestHelper.getRequests().length, 20); + multipartCompleteRequest = fileTestHelper.getRequests()[19]; + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); + multipartCompleteRequest.respond(200, null, "" + uploader.getKey(0) + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 20); + uploader.retry(0); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 21); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[20]; + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + setTimeout(function() { + // successful multipart complete request + assert.equal(fileTestHelper.getRequests().length, 22); + multipartCompleteRequest = fileTestHelper.getRequests()[21]; + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + + done(); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); }, 0); }, 0); }, 0); @@ -856,45 +878,47 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(initiateRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "Initiate MP request Authorization header invalid"); initiateRequest.respond(200, null, "123"); - // upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 2); - uploadPartRequest = fileTestHelper.getRequests()[1]; - assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); - - assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); - - assert.equal(uploadPartRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "Upload part 1 request Authorization header is invalid"); - uploadPartRequest.respond(200, {ETag: "etag1"}, null); - - setTimeout(function() { - // upload part 2 request - assert.equal(fileTestHelper.getRequests().length, 3); - uploadPartRequest = fileTestHelper.getRequests()[2]; + setTimeout(function () { + // upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 2); + uploadPartRequest = fileTestHelper.getRequests()[1]; assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); - assert.equal(uploadPartRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "Upload part 2 request Authorization header is invalid"); - uploadPartRequest.respond(200, {ETag: "etag2"}, null); + assert.equal(uploadPartRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "Upload part 1 request Authorization header is invalid"); + uploadPartRequest.respond(200, {ETag: "etag1"}, null); setTimeout(function() { - // multipart complete request - assert.equal(fileTestHelper.getRequests().length, 4); - multipartCompleteRequest = fileTestHelper.getRequests()[3]; - assert.equal(multipartCompleteRequest.method, "POST"); - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); - assert.equal(multipartCompleteRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "MP complete request Authorization header is invalid"); - assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + // upload part 2 request + assert.equal(fileTestHelper.getRequests().length, 3); + uploadPartRequest = fileTestHelper.getRequests()[2]; + assert.equal(uploadPartRequest.method, "PUT"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); + + assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); + + assert.equal(uploadPartRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "Upload part 2 request Authorization header is invalid"); + uploadPartRequest.respond(200, {ETag: "etag2"}, null); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + // multipart complete request + assert.equal(fileTestHelper.getRequests().length, 4); + multipartCompleteRequest = fileTestHelper.getRequests()[3]; + assert.equal(multipartCompleteRequest.method, "POST"); + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); + assert.equal(multipartCompleteRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "MP complete request Authorization header is invalid"); + assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + done(); + }, 0); }, 0); }, 0); }, 0); @@ -928,74 +952,84 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); assert.equal(fileTestHelper.getRequests().length, 1); uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 2); - initiateRequest = fileTestHelper.getRequests()[1]; - assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); - initiateRequest.respond(200, null, "123"); - - // failing upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 3); - uploadPartRequest = fileTestHelper.getRequests()[2]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - uploadPartRequest.respond(404, {ETag: "etag1"}, null); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 3); - uploader.retry(0); assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - // successful upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 4); - uploadPartRequest = fileTestHelper.getRequests()[3]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - uploadPartRequest.respond(200, {ETag: "etag1_a"}, null); + // successful initiate multipart upload request + assert.equal(fileTestHelper.getRequests().length, 2); + initiateRequest = fileTestHelper.getRequests()[1]; + assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); + initiateRequest.respond(200, null, "123"); setTimeout(function() { - // failing upload part 2 request - assert.equal(fileTestHelper.getRequests().length, 5); - uploadPartRequest = fileTestHelper.getRequests()[4]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - uploadPartRequest.respond(404, {ETag: "etag2"}, null); + // failing upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 3); + uploadPartRequest = fileTestHelper.getRequests()[2]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); + uploadPartRequest.respond(404, {ETag: "etag1"}, null); setTimeout(function() { assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 5); + assert.equal(fileTestHelper.getRequests().length, 3); uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful upload part 2 request - assert.equal(fileTestHelper.getRequests().length, 6); - uploadPartRequest = fileTestHelper.getRequests()[5]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - uploadPartRequest.respond(200, {ETag: "etag2_a"}, null); - setTimeout(function() { - // failing multipart complete request - assert.equal(fileTestHelper.getRequests().length, 7); - multipartCompleteRequest = fileTestHelper.getRequests()[6]; - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + uploader.getKey(0) + ""); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 7); - uploader.retry(0); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + // successful upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 4); + uploadPartRequest = fileTestHelper.getRequests()[3]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); + uploadPartRequest.respond(200, {ETag: "etag1_a"}, null); - // successful multipart complete request - assert.equal(fileTestHelper.getRequests().length, 8); - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + setTimeout(function() { + // failing upload part 2 request + assert.equal(fileTestHelper.getRequests().length, 5); + uploadPartRequest = fileTestHelper.getRequests()[4]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + uploadPartRequest.respond(404, {ETag: "etag2"}, null); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 5); + uploader.retry(0); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful upload part 2 request + assert.equal(fileTestHelper.getRequests().length, 6); + uploadPartRequest = fileTestHelper.getRequests()[5]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + uploadPartRequest.respond(200, {ETag: "etag2_a"}, null); + + setTimeout(function() { + // failing multipart complete request + assert.equal(fileTestHelper.getRequests().length, 7); + multipartCompleteRequest = fileTestHelper.getRequests()[6]; + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); + multipartCompleteRequest.respond(200, null, "" + uploader.getKey(0) + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 7); + uploader.retry(0); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful multipart complete request + assert.equal(fileTestHelper.getRequests().length, 8); + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); }, 0); }, 0); }, 0); From 01e9b598a0a6dd2a679eb0f4ce835428b4e7bfa0 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 19:27:45 +1100 Subject: [PATCH 36/73] refactor: qq.s3.RequestSigner getToSign to use Promise --- client/js/s3/request-signer.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/client/js/s3/request-signer.js b/client/js/s3/request-signer.js index 2cd06db71..2e12551db 100644 --- a/client/js/s3/request-signer.js +++ b/client/js/s3/request-signer.js @@ -572,7 +572,6 @@ qq.s3.RequestSigner = function(o) { getToSign: function(id) { var sessionToken = credentialsProvider.get().sessionToken, - promise = new qq.Promise(), adjustedDate = new Date(Date.now() + options.signatureSpec.drift); headers["x-amz-date"] = adjustedDate.toUTCString(); @@ -581,7 +580,7 @@ qq.s3.RequestSigner = function(o) { headers[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = sessionToken; } - getStringToSignArtifacts(id, options.signatureSpec.version, { + return getStringToSignArtifacts(id, options.signatureSpec.version, { bucket: bucket, content: content, contentType: contentType, @@ -593,7 +592,7 @@ qq.s3.RequestSigner = function(o) { uploadId: uploadId }).then(function(_artifacts_) { artifacts = _artifacts_; - promise.success({ + return { headers: (function() { if (contentType) { headers["Content-Type"] = contentType; @@ -607,12 +606,8 @@ qq.s3.RequestSigner = function(o) { signedHeaders: artifacts.signedHeaders, stringToSign: artifacts.toSign, stringToSignRaw: artifacts.toSignRaw - }); - }, function (err) { - promise.failure(err); + }; }); - - return promise; }, getHeaders: function() { From 91133ce04a1b27a82140e4fa558cd36dc20a27ed Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 19:33:14 +1100 Subject: [PATCH 37/73] refactor: qq.s3.FormUploadHandler createForm to use Promise --- client/js/s3/s3.form.upload.handler.js | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/client/js/s3/s3.form.upload.handler.js b/client/js/s3/s3.form.upload.handler.js index 70c95867f..29365cabc 100644 --- a/client/js/s3/s3.form.upload.handler.js +++ b/client/js/s3/s3.form.upload.handler.js @@ -110,27 +110,22 @@ qq.s3.FormUploadHandler = function(options, proxy) { * Creates form, that will be submitted to iframe */ function createForm(id, iframe) { - var promise = new qq.Promise(), - method = "POST", + var method = "POST", endpoint = options.endpointStore.get(id), fileName = getName(id); - generateAwsParams(id).then(function(params) { - var form = handler._initFormForUpload({ + return generateAwsParams(id).then(function(params) { + return handler._initFormForUpload({ method: method, endpoint: endpoint, params: params, paramsInBody: true, targetName: iframe.name }); - - promise.success(form); }, function(error) { - promise.failure(error.message); - handleFinishedUpload(id, iframe, fileName, {error: error.message}); + handleFinishedUpload(id, iframe); + throw error; }); - - return promise; } function handleUpload(id) { @@ -175,7 +170,9 @@ qq.s3.FormUploadHandler = function(options, proxy) { log("Sending upload request for " + id); form.submit(); qq(form).remove(); - }, promise.failure); + }, function (error) { + promise.failure(error.message); + }); return promise; } From b6119eb2db4ff0dfb58e954568ce8519bca4213b Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 19:37:19 +1100 Subject: [PATCH 38/73] refactor: qq.s3.FormUploadHandler handleUpload to use Promise --- client/js/s3/s3.form.upload.handler.js | 94 ++++++++++++-------------- 1 file changed, 42 insertions(+), 52 deletions(-) diff --git a/client/js/s3/s3.form.upload.handler.js b/client/js/s3/s3.form.upload.handler.js index 29365cabc..2ae7680ab 100644 --- a/client/js/s3/s3.form.upload.handler.js +++ b/client/js/s3/s3.form.upload.handler.js @@ -131,50 +131,52 @@ qq.s3.FormUploadHandler = function(options, proxy) { function handleUpload(id) { var iframe = handler._createIframe(id), input = handler.getInput(id), - promise = new qq.Promise(); + error; - createForm(id, iframe).then(function(form) { - form.appendChild(input); + return new Promise(function(resolve, reject) { + createForm(id, iframe).then(function(form) { + form.appendChild(input); - // Register a callback when the response comes in from S3 - handler._attachLoadEvent(iframe, function(response) { - log("iframe loaded"); + // Register a callback when the response comes in from S3 + handler._attachLoadEvent(iframe, function(response) { + log("iframe loaded"); - // If the common response handler has determined success or failure immediately - if (response) { - // If there is something fundamentally wrong with the response (such as iframe content is not accessible) - if (response.success === false) { - log("Amazon likely rejected the upload request", "error"); - promise.failure(response); - } - } - // The generic response (iframe onload) handler was not able to make a determination regarding the success of the request - else { - response = {}; - response.success = isValidResponse(id, iframe); - - // If the more specific response handle detected a problem with the response from S3 - if (response.success === false) { - log("A success response was received by Amazon, but it was invalid in some way.", "error"); - promise.failure(response); + // If the common response handler has determined success or failure immediately + if (response) { + // If there is something fundamentally wrong with the response (such as iframe content is not accessible) + if (response.success === false) { + error = new Error("Amazon likely rejected the upload request"); + error.response = response; + log(error.message, "error"); + reject(error); + } } + // The generic response (iframe onload) handler was not able to make a determination regarding the success of the request else { - qq.extend(response, qq.s3.util.parseIframeResponse(iframe)); - promise.success(response); + response = {}; + response.success = isValidResponse(id, iframe); + + // If the more specific response handle detected a problem with the response from S3 + if (response.success === false) { + error = new Error("A success response was received by Amazon, but it was invalid in some way."); + error.response = response; + log(error.message, "error"); + reject(error); + } + else { + qq.extend(response, qq.s3.util.parseIframeResponse(iframe)); + resolve(response); + } } - } - handleFinishedUpload(id, iframe); - }); + handleFinishedUpload(id, iframe); + }); - log("Sending upload request for " + id); - form.submit(); - qq(form).remove(); - }, function (error) { - promise.failure(error.message); + log("Sending upload request for " + id); + form.submit(); + qq(form).remove(); + }, reject); }); - - return promise; } function handleFinishedUpload(id, iframe) { @@ -204,20 +206,12 @@ qq.s3.FormUploadHandler = function(options, proxy) { return new Promise(function(resolve, reject) { if (handler.getThirdPartyFileId(id)) { if (handler._getFileState(id).bucket) { - handleUpload(id).then(resolve, function (response) { - var error = new Error("Upload failed"); - error.response = response; - reject(error); - }); + handleUpload(id).then(resolve, reject); } else { onGetBucket(id).then(function(bucket) { handler._getFileState(id).bucket = bucket; - handleUpload(id).then(resolve, function (response) { - var error = new Error("Upload failed"); - error.response = response; - reject(error); - }); + handleUpload(id).then(resolve, reject); }); } } @@ -228,16 +222,12 @@ qq.s3.FormUploadHandler = function(options, proxy) { onGetBucket(id).then(function(bucket) { handler._getFileState(id).bucket = bucket; handler._setThirdPartyFileId(id, key); - handleUpload(id).then(resolve, function (response) { - var error = new Error("Upload failed"); - error.response = response; - reject(error); - }); + handleUpload(id).then(resolve, reject); }, function(errorReason) { - reject(new Promise(errorReason)); + reject(new Error(errorReason)); }); }, function(errorReason) { - reject(new Promise(errorReason)); + reject(new Error(errorReason)); }); } }); From bd764f259c6d1e8e416c90706f3df12a16972843 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 20:11:26 +1100 Subject: [PATCH 39/73] refactor: qq.s3.XhrUploadHandler initHeaders to use Promise --- client/js/s3/s3.xhr.upload.handler.js | 25 +- test/unit/s3/cdn/generic-chunked.js | 54 +-- test/unit/s3/chunked-uploads.js | 622 ++++++++++++++------------ 3 files changed, 370 insertions(+), 331 deletions(-) diff --git a/client/js/s3/s3.xhr.upload.handler.js b/client/js/s3/s3.xhr.upload.handler.js index 00dabdddf..ecadd553d 100755 --- a/client/js/s3/s3.xhr.upload.handler.js +++ b/client/js/s3/s3.xhr.upload.handler.js @@ -74,30 +74,33 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { /** * Determines headers that must be attached to the chunked (Multipart Upload) request. One of these headers is an * Authorization value, which must be determined by asking the local server to sign the request first. So, this - * function returns a promise. Once all headers are determined, the `success` method of the promise is called with - * the headers object. If there was some problem determining the headers, we delegate to the caller's `failure` - * callback. + * function returns a promise. Once all headers are determined, the promise is resolved with + * the headers object. If there was some problem determining the headers, we reject the promise. * * @param id File ID * @param chunkIdx Index of the chunk to PUT - * @returns {qq.Promise} + * @returns {Promise} */ initHeaders: function(id, chunkIdx, blob) { var headers = {}, bucket = upload.bucket.getName(id), host = upload.host.getName(id), key = upload.key.urlSafe(id), - promise = new qq.Promise(), signatureConstructor = requesters.restSignature.constructStringToSign (requesters.restSignature.REQUEST_TYPE.MULTIPART_UPLOAD, bucket, host, key) .withPartNum(chunkIdx + 1) .withContent(blob) .withUploadId(handler._getPersistableData(id).uploadId); - // Ask the local server to sign the request. Use this signature to form the Authorization header. - requesters.restSignature.getSignature(id + "." + chunkIdx, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure); - - return promise; + return new Promise(function(resolve, reject) { + // Ask the local server to sign the request. Use this signature to form the Authorization header. + requesters.restSignature.getSignature(id + "." + chunkIdx, {signatureConstructor: signatureConstructor}).then( + function (headers, endOfUrl) { + resolve({headers: headers, endOfUrl: endOfUrl}); + }, function() { + reject(); + }); + }); }, put: function(id, chunkIdx) { @@ -108,7 +111,9 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { // Add appropriate headers to the multipart upload request. // Once these have been determined (asynchronously) attach the headers and send the chunk. - chunked.initHeaders(id, chunkIdx, chunkData.blob).then(function(headers, endOfUrl) { + chunked.initHeaders(id, chunkIdx, chunkData.blob).then(function(info) { + var headers = info.headers, + endOfUrl = info.endOfUrl; if (xhr._cancelled) { log(qq.format("Upload of item {}.{} cancelled. Upload will not start after successful signature request.", id, chunkIdx)); promise.failure({error: "Chunk upload cancelled"}); diff --git a/test/unit/s3/cdn/generic-chunked.js b/test/unit/s3/cdn/generic-chunked.js index dc84d0392..d9b2112a1 100644 --- a/test/unit/s3/cdn/generic-chunked.js +++ b/test/unit/s3/cdn/generic-chunked.js @@ -54,36 +54,40 @@ if (qqtest.canDownloadFileAsBlob) { assert.ok(uploadPartToSign1.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); - // upload part 1 request - uploadPartRequest = fileTestHelper.getRequests()[2]; - uploadPartRequest.respond(200, {ETag: "etag1"}, null); - setTimeout(function() { - // signature request for upload part 2 - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[4]; - uploadPartRequest.respond(200, {ETag: "etag2"}, null); + // upload part 1 request + uploadPartRequest = fileTestHelper.getRequests()[2]; + uploadPartRequest.respond(200, {ETag: "etag1"}, null); setTimeout(function() { - // signature request for multipart complete - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // multipart complete request - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - multipartCompleteRequest.respond(200, null, "mybucket" + uploader.getKey(0) + ""); + // signature request for upload part 2 + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - - done(); + // upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[4]; + uploadPartRequest.respond(200, {ETag: "etag2"}, null); + + setTimeout(function() { + // signature request for multipart complete + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // multipart complete request + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + multipartCompleteRequest.respond(200, null, "mybucket" + uploader.getKey(0) + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + + done(); + }, 0); + }, 0); }, 0); }, 0); }, 0); diff --git a/test/unit/s3/chunked-uploads.js b/test/unit/s3/chunked-uploads.js index bea7c0185..bab0c2442 100644 --- a/test/unit/s3/chunked-uploads.js +++ b/test/unit/s3/chunked-uploads.js @@ -124,7 +124,7 @@ if (qqtest.canDownloadFileAsBlob) { assert.ok(initiateToSign.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - setTimeout(function() { + setTimeout(function() { // initiate multipart upload request assert.equal(fileTestHelper.getRequests().length, 2); initiateRequest = fileTestHelper.getRequests()[1]; @@ -158,40 +158,11 @@ if (qqtest.canDownloadFileAsBlob) { assert.ok(uploadPartToSign1.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); - // upload part 1 request - uploadPartRequest = fileTestHelper.getRequests()[2]; - assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); - - assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); - - var authParts = uploadPartRequest.requestHeaders.Authorization.split(";"); - assert.equal(authParts.length, 3); - assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); - assert.equal(authParts[1], "x-amz-content-sha256"); - assert.equal(authParts[2], "x-amz-date,Signature=thesignature"); - uploadPartRequest.respond(200, {ETag: "etag1"}, null); - setTimeout(function() { - // signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 6); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; - assert.equal(uploadPartSignatureRequest2.method, "POST"); - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint + "?v4=true"); - assert.equal(uploadPartSignatureRequest2.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers); - assert.equal(uploadPartToSign2.headers.indexOf("AWS4-HMAC-SHA256"), 0); - assert.ok(uploadPartToSign2.headers.indexOf("/us-east-1/s3/aws4_request") > 0); - assert.equal(uploadPartToSign2.headers.split("\n").length, 12); - assert.ok(uploadPartToSign2.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[4]; + // upload part 1 request + uploadPartRequest = fileTestHelper.getRequests()[2]; assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); @@ -201,46 +172,79 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); assert.equal(authParts[1], "x-amz-content-sha256"); assert.equal(authParts[2], "x-amz-date,Signature=thesignature"); - uploadPartRequest.respond(200, {ETag: "etag2"}, null); + uploadPartRequest.respond(200, {ETag: "etag1"}, null); setTimeout(function() { - // signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 7); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; - assert.equal(uploadCompleteSignatureRequest.method, "POST"); - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint + "?v4=true"); - assert.equal(uploadCompleteSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers); - assert.equal(uploadCompleteToSign.headers.indexOf("AWS4-HMAC-SHA256"), 0); - assert.ok(uploadCompleteToSign.headers.indexOf("/us-east-1/s3/aws4_request") > 0); - assert.equal(uploadCompleteToSign.headers.split("\n").length, 12); - assert.ok(uploadCompleteToSign.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + // signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 6); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; + assert.equal(uploadPartSignatureRequest2.method, "POST"); + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint + "?v4=true"); + assert.equal(uploadPartSignatureRequest2.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers); + assert.equal(uploadPartToSign2.headers.indexOf("AWS4-HMAC-SHA256"), 0); + assert.ok(uploadPartToSign2.headers.indexOf("/us-east-1/s3/aws4_request") > 0); + assert.equal(uploadPartToSign2.headers.split("\n").length, 12); + assert.ok(uploadPartToSign2.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - // multipart complete request - assert.equal(fileTestHelper.getRequests().length, 8); - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - assert.equal(multipartCompleteRequest.method, "POST"); - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); + // upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[4]; + assert.equal(uploadPartRequest.method, "PUT"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); + + assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); - authParts = multipartCompleteRequest.requestHeaders.Authorization.split(";"); + var authParts = uploadPartRequest.requestHeaders.Authorization.split(";"); assert.equal(authParts.length, 3); assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); assert.equal(authParts[1], "x-amz-content-sha256"); assert.equal(authParts[2], "x-amz-date,Signature=thesignature"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + uploadPartRequest.respond(200, {ETag: "etag2"}, null); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + // signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 7); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; + assert.equal(uploadCompleteSignatureRequest.method, "POST"); + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint + "?v4=true"); + assert.equal(uploadCompleteSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers); + assert.equal(uploadCompleteToSign.headers.indexOf("AWS4-HMAC-SHA256"), 0); + assert.ok(uploadCompleteToSign.headers.indexOf("/us-east-1/s3/aws4_request") > 0); + assert.equal(uploadCompleteToSign.headers.split("\n").length, 12); + assert.ok(uploadCompleteToSign.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - done(); + setTimeout(function() { + // multipart complete request + assert.equal(fileTestHelper.getRequests().length, 8); + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + assert.equal(multipartCompleteRequest.method, "POST"); + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); + + authParts = multipartCompleteRequest.requestHeaders.Authorization.split(";"); + assert.equal(authParts.length, 3); + assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); + assert.equal(authParts[1], "x-amz-content-sha256"); + assert.equal(authParts[2], "x-amz-date,Signature=thesignature"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + + done(); + }, 0); + }, 0); }, 0); }, 0); }, 0); - }, 100); + }, 0); }, 100); }, 0); }); @@ -352,69 +356,75 @@ if (qqtest.canDownloadFileAsBlob) { assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); - // upload part 1 request - uploadPartRequest = fileTestHelper.getRequests()[2]; - assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); - - assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); - - assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); - uploadPartRequest.respond(200, {ETag: "etag1"}, null); - setTimeout(function() { - // signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 6); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; - assert.equal(uploadPartSignatureRequest2.method, "POST"); - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - assert.equal(uploadPartSignatureRequest2.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers); - assert.equal(uploadPartToSign2.headers.indexOf("PUT"), 0); - assert.ok(uploadPartToSign2.headers.indexOf("x-amz-date:") > 0); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[4]; + // upload part 1 request + uploadPartRequest = fileTestHelper.getRequests()[2]; assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); - uploadPartRequest.respond(200, {ETag: "etag2"}, null); + uploadPartRequest.respond(200, {ETag: "etag1"}, null); setTimeout(function() { - // signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 7); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; - assert.equal(uploadCompleteSignatureRequest.method, "POST"); - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - assert.equal(uploadCompleteSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers); - assert.equal(uploadCompleteToSign.headers.indexOf("POST"), 0); - assert.ok(uploadCompleteToSign.headers.indexOf("x-amz-date:") > 0); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // multipart complete request - assert.equal(fileTestHelper.getRequests().length, 8); - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - assert.equal(multipartCompleteRequest.method, "POST"); - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); - assert.equal(multipartCompleteRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); - assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + // signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 6); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; + assert.equal(uploadPartSignatureRequest2.method, "POST"); + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + assert.equal(uploadPartSignatureRequest2.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers); + assert.equal(uploadPartToSign2.headers.indexOf("PUT"), 0); + assert.ok(uploadPartToSign2.headers.indexOf("x-amz-date:") > 0); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + // upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[4]; + assert.equal(uploadPartRequest.method, "PUT"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); + + assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); + + assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); + uploadPartRequest.respond(200, {ETag: "etag2"}, null); + + setTimeout(function() { + // signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 7); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; + assert.equal(uploadCompleteSignatureRequest.method, "POST"); + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + assert.equal(uploadCompleteSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers); + assert.equal(uploadCompleteToSign.headers.indexOf("POST"), 0); + assert.ok(uploadCompleteToSign.headers.indexOf("x-amz-date:") > 0); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + setTimeout(function() { + // multipart complete request + assert.equal(fileTestHelper.getRequests().length, 8); + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + assert.equal(multipartCompleteRequest.method, "POST"); + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); + assert.equal(multipartCompleteRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); + assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + done(); + }, 0); + }, 0); + }, 0); }, 0); }, 0); }, 0); @@ -452,56 +462,64 @@ if (qqtest.canDownloadFileAsBlob) { assert.ok(initiateToSign.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) > 0); initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - // initiate multipart upload request - initiateRequest = fileTestHelper.getRequests()[1]; - assert.equal(initiateRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME], qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE); - assert.equal(initiateRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME], qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE); - initiateRequest.respond(200, null, "123"); - setTimeout(function() { - // signature request for upload part 1 - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers.indexOf(qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME + ":" + qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE) < 0); - assert.ok(uploadPartToSign1.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) < 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // upload part 1 request - uploadPartRequest = fileTestHelper.getRequests()[2]; - assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]); - assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); - uploadPartRequest.respond(200, {ETag: "etag1"}, null); - - setTimeout(function () { - // signature request for upload part 2 - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf(qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME + ":" + qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE) < 0); - assert.ok(uploadPartToSign2.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) < 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[4]; - assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]); - assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); - uploadPartRequest.respond(200, {ETag: "etag1"}, null); + // initiate multipart upload request + initiateRequest = fileTestHelper.getRequests()[1]; + assert.equal(initiateRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME], qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE); + assert.equal(initiateRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME], qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE); + initiateRequest.respond(200, null, "123"); - setTimeout(function () { - // signature request for multipart complete - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf(qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME + ":" + qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE) < 0); - assert.ok(uploadCompleteToSign.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) < 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + setTimeout(function() { + // signature request for upload part 1 + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers.indexOf(qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME + ":" + qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE) < 0); + assert.ok(uploadPartToSign1.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) < 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); - // multipart complete request - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - assert.ok(!multipartCompleteRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]); - assert.ok(!multipartCompleteRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + setTimeout(function() { + // upload part 1 request + uploadPartRequest = fileTestHelper.getRequests()[2]; + assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]); + assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); + uploadPartRequest.respond(200, {ETag: "etag1"}, null); setTimeout(function () { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + // signature request for upload part 2 + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf(qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME + ":" + qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE) < 0); + assert.ok(uploadPartToSign2.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) < 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + + setTimeout(function() { + // upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[4]; + assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]); + assert.ok(!uploadPartRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); + uploadPartRequest.respond(200, {ETag: "etag1"}, null); + + setTimeout(function () { + // signature request for multipart complete + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf(qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME + ":" + qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE) < 0); + assert.ok(uploadCompleteToSign.headers.indexOf(qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME + ":" + qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE) < 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + setTimeout(function () { + // multipart complete request + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + assert.ok(!multipartCompleteRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]); + assert.ok(!multipartCompleteRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + + setTimeout(function () { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + }, 0); + }, 0); + }, 0); + }, 0); }, 0); }, 0); }, 0); @@ -566,193 +584,205 @@ if (qqtest.canDownloadFileAsBlob) { assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploads") > 0); initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - // failing initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 3); - initiateRequest = fileTestHelper.getRequests()[2]; - assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); - initiateRequest.respond(200, null, ""); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + // failing initiate multipart upload request assert.equal(fileTestHelper.getRequests().length, 3); - uploader.retry(0); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful initiate signature request - assert.equal(fileTestHelper.getRequests().length, 4); - initiateSignatureRequest = fileTestHelper.getRequests()[3]; - assert.equal(initiateSignatureRequest.url, testSignatureEndoint); - assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploads") > 0); - initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // successful initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 5); - initiateRequest = fileTestHelper.getRequests()[4]; - assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); - initiateRequest.respond(200, null, "123"); + initiateRequest = fileTestHelper.getRequests()[2]; + assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); + initiateRequest.respond(200, null, ""); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 3); + uploader.retry(0); setTimeout(function() { - // failed signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 7); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[6]; - assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({invalid: true})); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful initiate signature request + assert.equal(fileTestHelper.getRequests().length, 4); + initiateSignatureRequest = fileTestHelper.getRequests()[3]; + assert.equal(initiateSignatureRequest.url, testSignatureEndoint); + assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploads") > 0); + initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 7); - uploader.retry(0); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + // successful initiate multipart upload request + assert.equal(fileTestHelper.getRequests().length, 5); + initiateRequest = fileTestHelper.getRequests()[4]; + assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); + initiateRequest.respond(200, null, "123"); - // successful signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 9); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[8]; + setTimeout(function() { + // failed signature request for upload part 1 + assert.equal(fileTestHelper.getRequests().length, 7); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[6]; assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // failing upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 9); - uploadPartRequest = fileTestHelper.getRequests()[7]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - uploadPartRequest.respond(404, {ETag: "etag1"}, null); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({invalid: true})); setTimeout(function() { assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 9); + assert.equal(fileTestHelper.getRequests().length, 7); uploader.retry(0); setTimeout(function() { assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); // successful signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 11); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[10]; + assert.equal(fileTestHelper.getRequests().length, 9); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[8]; assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); - // successful upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 11); - uploadPartRequest = fileTestHelper.getRequests()[9]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - uploadPartRequest.respond(200, {ETag: "etag1_a"}, null); - setTimeout(function() { - // failing signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 13); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[12]; - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(404, null, JSON.stringify({signature: "thesignature"})); + // failing upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 9); + uploadPartRequest = fileTestHelper.getRequests()[7]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); + uploadPartRequest.respond(404, {ETag: "etag1"}, null); setTimeout(function() { assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 13); + assert.equal(fileTestHelper.getRequests().length, 9); uploader.retry(0); setTimeout(function() { assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - // successful signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 15); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[14]; - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + // successful signature request for upload part 1 + assert.equal(fileTestHelper.getRequests().length, 11); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[10]; + assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - // failing upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[13]; - assert.equal(fileTestHelper.getRequests().length, 15); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - uploadPartRequest.respond(404, {ETag: "etag2"}, null); + // successful upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 11); + uploadPartRequest = fileTestHelper.getRequests()[9]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); + uploadPartRequest.respond(200, {ETag: "etag1_a"}, null); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 15); - uploader.retry(0); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 17); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[16]; - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // successful upload part 2 request - assert.equal(fileTestHelper.getRequests().length, 17); - uploadPartRequest = fileTestHelper.getRequests()[15]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - uploadPartRequest.respond(200, {ETag: "etag2_a"}, null); + // failing signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 13); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[12]; + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(404, null, JSON.stringify({signature: "thesignature"})); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 13); + uploader.retry(0); setTimeout(function() { - // failing signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 18); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[17]; - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(400, null, JSON.stringify({signature: "thesignature"})); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 15); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[14]; + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 18); - uploader.retry(0); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 19); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[18]; - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // failing multipart complete request - assert.equal(fileTestHelper.getRequests().length, 20); - multipartCompleteRequest = fileTestHelper.getRequests()[19]; - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + uploader.getKey(0) + ""); + // failing upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[13]; + assert.equal(fileTestHelper.getRequests().length, 15); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + uploadPartRequest.respond(404, {ETag: "etag2"}, null); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 15); + uploader.retry(0); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - assert.equal(fileTestHelper.getRequests().length, 20); - uploader.retry(0); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - // successful signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 21); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[20]; - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + // successful signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 17); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[16]; + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + + setTimeout(function() { + // successful upload part 2 request + assert.equal(fileTestHelper.getRequests().length, 17); + uploadPartRequest = fileTestHelper.getRequests()[15]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + uploadPartRequest.respond(200, {ETag: "etag2_a"}, null); setTimeout(function() { - // successful multipart complete request - assert.equal(fileTestHelper.getRequests().length, 22); - multipartCompleteRequest = fileTestHelper.getRequests()[21]; - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + // failing signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 18); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[17]; + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(400, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - - done(); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 18); + uploader.retry(0); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 19); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[18]; + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + setTimeout(function() { + // failing multipart complete request + assert.equal(fileTestHelper.getRequests().length, 20); + multipartCompleteRequest = fileTestHelper.getRequests()[19]; + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); + multipartCompleteRequest.respond(200, null, "" + uploader.getKey(0) + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 20); + uploader.retry(0); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 21); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[20]; + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + setTimeout(function() { + // successful multipart complete request + assert.equal(fileTestHelper.getRequests().length, 22); + multipartCompleteRequest = fileTestHelper.getRequests()[21]; + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); + assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + + done(); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); + }, 0); }, 0); }, 0); }, 0); From 8d2b6fb9ece002e22ec31c57ca5e7a63f753a0d8 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 21:21:22 +1100 Subject: [PATCH 40/73] refactor: qq.s3.XhrUploadHandler put to use Promise --- client/js/azure/azure.xhr.upload.handler.js | 1 + .../js/s3/multipart.abort.ajax.requester.js | 4 +- client/js/s3/s3.form.upload.handler.js | 8 +- client/js/s3/s3.xhr.upload.handler.js | 188 +++++++++--------- .../upload.handler.controller.js | 2 +- 5 files changed, 108 insertions(+), 95 deletions(-) diff --git a/client/js/azure/azure.xhr.upload.handler.js b/client/js/azure/azure.xhr.upload.handler.js index 22b1c6214..bd10af5fe 100644 --- a/client/js/azure/azure.xhr.upload.handler.js +++ b/client/js/azure/azure.xhr.upload.handler.js @@ -133,6 +133,7 @@ qq.azure.XhrUploadHandler = function(spec, proxy) { errorMsg = "Problem sending file to Azure", error = new Error(errorMsg); + error.error = errorMsg; error.azureError = azureError && azureError.message; error.reset = xhr.status === 403; diff --git a/client/js/s3/multipart.abort.ajax.requester.js b/client/js/s3/multipart.abort.ajax.requester.js index e800779a2..bc9d1cb12 100644 --- a/client/js/s3/multipart.abort.ajax.requester.js +++ b/client/js/s3/multipart.abort.ajax.requester.js @@ -60,7 +60,9 @@ qq.s3.AbortMultipartAjaxRequester = function(o) { }); }, function (reason) { - reject(new Error(reason)); + var error = new Error("Faild to get signature"); + error.error = reason; + reject(error); } ); }); diff --git a/client/js/s3/s3.form.upload.handler.js b/client/js/s3/s3.form.upload.handler.js index 2ae7680ab..61812d7a0 100644 --- a/client/js/s3/s3.form.upload.handler.js +++ b/client/js/s3/s3.form.upload.handler.js @@ -224,10 +224,14 @@ qq.s3.FormUploadHandler = function(options, proxy) { handler._setThirdPartyFileId(id, key); handleUpload(id).then(resolve, reject); }, function(errorReason) { - reject(new Error(errorReason)); + var error = new Error("Failed to get bucket"); + error.error = errorReason; + reject(error); }); }, function(errorReason) { - reject(new Error(errorReason)); + var error = new Error("Failed to get key name"); + error.error = errorReason; + reject(error); }); } }); diff --git a/client/js/s3/s3.xhr.upload.handler.js b/client/js/s3/s3.xhr.upload.handler.js index ecadd553d..c17629013 100755 --- a/client/js/s3/s3.xhr.upload.handler.js +++ b/client/js/s3/s3.xhr.upload.handler.js @@ -106,63 +106,66 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { put: function(id, chunkIdx) { var xhr = handler._createXhr(id, chunkIdx), chunkData = handler._getChunkData(id, chunkIdx), - domain = spec.endpointStore.get(id), - promise = new qq.Promise(); + domain = spec.endpointStore.get(id); - // Add appropriate headers to the multipart upload request. - // Once these have been determined (asynchronously) attach the headers and send the chunk. - chunked.initHeaders(id, chunkIdx, chunkData.blob).then(function(info) { - var headers = info.headers, - endOfUrl = info.endOfUrl; - if (xhr._cancelled) { - log(qq.format("Upload of item {}.{} cancelled. Upload will not start after successful signature request.", id, chunkIdx)); - promise.failure({error: "Chunk upload cancelled"}); - } - else { - var url = domain + "/" + endOfUrl; - handler._registerProgressHandler(id, chunkIdx, chunkData.size); - upload.track(id, xhr, chunkIdx).then(promise.success, promise.failure); - xhr.open("PUT", url, true); - - var hasContentType = false; - qq.each(headers, function(name, val) { - if (name === "Content-Type") { - hasContentType = true; - } + return new Promise(function(resolve, reject) { + // Add appropriate headers to the multipart upload request. + // Once these have been determined (asynchronously) attach the headers and send the chunk. + chunked.initHeaders(id, chunkIdx, chunkData.blob).then(function(info) { + var headers = info.headers, + endOfUrl = info.endOfUrl, + error; + if (xhr._cancelled) { + error = new Error(qq.format("Upload of item {}.{} cancelled. Upload will not start after successful signature request.", id, chunkIdx)); + log(error.message); + reject(error); + } + else { + var url = domain + "/" + endOfUrl; + handler._registerProgressHandler(id, chunkIdx, chunkData.size); + upload.track(id, xhr, chunkIdx).then(resolve, reject); + xhr.open("PUT", url, true); + + var hasContentType = false; + qq.each(headers, function(name, val) { + if (name === "Content-Type") { + hasContentType = true; + } - xhr.setRequestHeader(name, val); - }); + xhr.setRequestHeader(name, val); + }); - // Workaround for IE Edge - if (!hasContentType) { - xhr.setRequestHeader("Content-Type", ""); - } + // Workaround for IE Edge + if (!hasContentType) { + xhr.setRequestHeader("Content-Type", ""); + } - xhr.send(chunkData.blob); - } - }, function() { - promise.failure({error: "Problem signing the chunk!"}, xhr); + xhr.send(chunkData.blob); + } + }, function() { + var error = new Error("Problem signing the chunk!"); + error.xhr = xhr; + reject(xhr); + }); }); - - return promise; }, send: function(id, chunkIdx) { - var promise = new qq.Promise(); - - chunked.setup(id).then( - // The "Initiate" request succeeded. We are ready to send the first chunk. - function() { - chunked.put(id, chunkIdx).then(promise.success, promise.failure); - }, - - // We were unable to initiate the chunked upload process. - function(errorMessage, xhr) { - promise.failure({error: errorMessage}, xhr); - } - ); + return new Promise(function(resolve, reject) { + chunked.setup(id).then( + // The "Initiate" request succeeded. We are ready to send the first chunk. + function() { + chunked.put(id, chunkIdx).then(resolve, reject); + }, - return promise; + // We were unable to initiate the chunked upload process. + function(errorMessage, xhr) { + var error = new Error(errorMessage); + error.xhr = xhr; + reject(error); + } + ); + }); }, /** @@ -318,20 +321,20 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { }, send: function(id) { - var promise = new qq.Promise(), - xhr = handler._createXhr(id), + var xhr = handler._createXhr(id), fileOrBlob = handler.getFile(id); handler._registerProgressHandler(id); - upload.track(id, xhr).then(promise.success, promise.failure); - // Delegate to a function the sets up the XHR request and notifies us when it is ready to be sent, along w/ the payload. - simple.setup(id, xhr, fileOrBlob).then(function(toSend) { - log("Sending upload request for " + id); - xhr.send(toSend); - }, promise.failure); + return new Promise(function(resolve, reject) { + upload.track(id, xhr).then(resolve, reject); - return promise; + // Delegate to a function the sets up the XHR request and notifies us when it is ready to be sent, along w/ the payload. + simple.setup(id, xhr, fileOrBlob).then(function(toSend) { + log("Sending upload request for " + id); + xhr.send(toSend); + }, reject); + }); }, /** @@ -557,53 +560,56 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { upload.host.promise(id).then(function() { /* jshint eqnull:true */ if (optChunkIdx == null) { - simple.send(id).then(function(response, xhr) { - resolve({response: response, xhr: xhr}); - }, function(errorObject, xhr) { - var error = new Error(errorObject.error); - error.xhr = xhr; - reject(error); - }); + simple.send(id).then(resolve, reject); } else { - chunked.send(id, optChunkIdx).then(function(response, xhr) { - resolve({response: response, xhr: xhr}); - }, function(errorObject, xhr) { - var error = new Error(errorObject.error); - error.xhr = xhr; - reject(error); - }); + chunked.send(id, optChunkIdx).then(resolve, reject); } }); }); }, function(errorReason) { - reject(new Error(errorReason)); + var error = new Error(errorReason); + error.error = errorReason + reject(error); }); }); }, track: function(id, xhr, optChunkIdx) { - var promise = new qq.Promise(); - - xhr.onreadystatechange = function() { - if (xhr.readyState === 4) { - var result; - - /* jshint eqnull:true */ - if (optChunkIdx == null) { - result = upload.done(id, xhr); - promise[result.success ? "success" : "failure"](result.response, xhr); - } - else { - chunked.done(id, xhr, optChunkIdx); - result = upload.done(id, xhr); - promise[result.success ? "success" : "failure"](result.response, xhr); + return new Promise(function(resolve, reject) { + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + var result, + error; + + /* jshint eqnull:true */ + if (optChunkIdx == null) { + result = upload.done(id, xhr); + if (result.success) { + resolve({response: result.response, xhr: xhr}); + } else { + error = new Error(); + error.response = result.response; + error.xhr = xhr; + reject(error); + } + } + else { + chunked.done(id, xhr, optChunkIdx); + result = upload.done(id, xhr); + if (result.success) { + resolve({response: result.response, xhr: xhr}); + } else { + error = new Error(); + error.response = result.response; + error.xhr = xhr; + reject(error); + } + } } - } - }; - - return promise; + }; + }); } }; diff --git a/client/js/upload-handler/upload.handler.controller.js b/client/js/upload-handler/upload.handler.controller.js index ee4275c5e..6434163c6 100644 --- a/client/js/upload-handler/upload.handler.controller.js +++ b/client/js/upload-handler/upload.handler.controller.js @@ -418,7 +418,7 @@ qq.UploadHandlerController = function(o, namespace) { var optXhr = error.xhr; log("Simple upload request failed for " + id); - var responseToReport = upload.normalizeResponse({ error: error.message, azureError: error.azureError }, false); + var responseToReport = upload.normalizeResponse({error: error.error, azureError: error.azureError}, false); if (!options.onAutoRetry(id, name, responseToReport, optXhr)) { upload.cleanup(id, responseToReport, optXhr); From 529051150f0a8ca9630e11bf53306d3e9d4ce269 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 21:27:00 +1100 Subject: [PATCH 41/73] refactor: qq.s3.XhrUploadHandler setup to use Promise --- client/js/s3/s3.xhr.upload.handler.js | 71 +++++++++++++-------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/client/js/s3/s3.xhr.upload.handler.js b/client/js/s3/s3.xhr.upload.handler.js index c17629013..8cdb96c06 100755 --- a/client/js/s3/s3.xhr.upload.handler.js +++ b/client/js/s3/s3.xhr.upload.handler.js @@ -157,13 +157,7 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { function() { chunked.put(id, chunkIdx).then(resolve, reject); }, - - // We were unable to initiate the chunked upload process. - function(errorMessage, xhr) { - var error = new Error(errorMessage); - error.xhr = xhr; - reject(error); - } + reject ); }); }, @@ -173,38 +167,39 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { * initiated. * * @param id Associated file ID - * @returns {qq.Promise} A promise that is fulfilled when the initiate request has been sent and the response has been parsed. + * @returns {Promise} A promise that is resolved when the initiate request has been sent and the response has been parsed. */ setup: function(id) { - var promise = new qq.Promise(), - uploadId = handler._getPersistableData(id).uploadId, - uploadIdPromise = new qq.Promise(); - - if (!uploadId) { - handler._getPersistableData(id).uploadId = uploadIdPromise; - requesters.initiateMultipart.send(id).then( - function(uploadId) { - handler._getPersistableData(id).uploadId = uploadId; - uploadIdPromise.success(uploadId); - promise.success(uploadId); - }, - function(errorMsg, xhr) { - handler._getPersistableData(id).uploadId = null; - promise.failure(errorMsg, xhr); - uploadIdPromise.failure(errorMsg, xhr); - } - ); - } - else if (uploadId instanceof qq.Promise) { - uploadId.then(function(uploadId) { - promise.success(uploadId); - }); - } - else { - promise.success(uploadId); - } - - return promise; + return new Promise(function(setupResolve, setupReject) { + var uploadId = handler._getPersistableData(id).uploadId; + + if (!uploadId) { + handler._getPersistableData(id).uploadId = new Promise(function(resolve, reject) { + requesters.initiateMultipart.send(id).then( + function(uploadId) { + handler._getPersistableData(id).uploadId = uploadId; + resolve(uploadId); + setupResolve(uploadId); + }, + function(errorMsg, xhr) { + var error = new Error(errorMsg); + error.xhr = xhr; + handler._getPersistableData(id).uploadId = null; + setupReject(error); + reject(error); + } + ); + }); + } + else if (uploadId instanceof Promise) { + uploadId.then(function(uploadId) { + setupResolve(uploadId); + }); + } + else { + setupResolve(uploadId); + } + }); } }, @@ -570,7 +565,7 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { }, function(errorReason) { var error = new Error(errorReason); - error.error = errorReason + error.error = errorReason; reject(error); }); }); From f8aeaa5861a9390f1c0486aa1fbd15184a7b7859 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Mon, 26 Mar 2018 21:30:29 +1100 Subject: [PATCH 42/73] refactor: qq.s3.XhrUploadHandler bucket.promise to use Promise --- client/js/s3/s3.xhr.upload.handler.js | 31 +++++++++++++++------------ 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/client/js/s3/s3.xhr.upload.handler.js b/client/js/s3/s3.xhr.upload.handler.js index 8cdb96c06..a0ce45ef0 100755 --- a/client/js/s3/s3.xhr.upload.handler.js +++ b/client/js/s3/s3.xhr.upload.handler.js @@ -384,20 +384,23 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { */ bucket: { promise: function(id) { - var promise = new qq.Promise(), - cachedBucket = handler._getFileState(id).bucket; + var cachedBucket = handler._getFileState(id).bucket; - if (cachedBucket) { - promise.success(cachedBucket); - } - else { - onGetBucket(id).then(function(bucket) { - handler._getFileState(id).bucket = bucket; - promise.success(bucket); - }, promise.failure); - } - - return promise; + return new Promise(function(resolve, reject) { + if (cachedBucket) { + resolve(cachedBucket); + } + else { + onGetBucket(id).then(function(bucket) { + handler._getFileState(id).bucket = bucket; + resolve(bucket); + }, function(errorReason) { + var error = new Error("Failed to get bucket"); + error.error = errorReason; + reject(error); + }); + } + }); }, getName: function(id) { @@ -561,7 +564,7 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { chunked.send(id, optChunkIdx).then(resolve, reject); } }); - }); + }, reject); }, function(errorReason) { var error = new Error(errorReason); From 1df0ccfceb0490defaba8260b00331edba842889 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 09:03:55 +1100 Subject: [PATCH 43/73] refactor: qq.s3.XhrUploadHandler.setup to use Promise --- client/js/s3/s3.xhr.upload.handler.js | 50 ++++++++++++--------------- client/js/s3/util.js | 11 +++--- 2 files changed, 27 insertions(+), 34 deletions(-) diff --git a/client/js/s3/s3.xhr.upload.handler.js b/client/js/s3/s3.xhr.upload.handler.js index a0ce45ef0..250106bc3 100755 --- a/client/js/s3/s3.xhr.upload.handler.js +++ b/client/js/s3/s3.xhr.upload.handler.js @@ -286,7 +286,7 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { * due to some error. * * @param id File ID - * @returns {qq.Promise} + * @returns {Promise} */ initParams: function(id) { /*jshint -W040 */ @@ -343,15 +343,14 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { * @param id File ID * @param xhr XMLHttpRequest to use for the upload * @param fileOrBlob `File` or `Blob` to send - * @returns {qq.Promise} + * @returns {Promise} */ setup: function(id, xhr, fileOrBlob) { var formData = new FormData(), endpoint = endpointStore.get(id), - url = endpoint, - promise = new qq.Promise(); + url = endpoint; - simple.initParams(id).then( + return simple.initParams(id).then( // Success - all params determined function(awsParams) { xhr.open("POST", url, true); @@ -361,16 +360,8 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { // AWS requires the file field be named "file". formData.append("file", fileOrBlob); - promise.success(formData); - }, - - // Failure - we couldn't determine some params (likely the signature) - function(error) { - promise.failure({error: error.message}); - } - ); - - return promise; + return formData; + }); } }, @@ -410,20 +401,23 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { host: { promise: function(id) { - var promise = new qq.Promise(), - cachedHost = handler._getFileState(id).host; - - if (cachedHost) { - promise.success(cachedHost); - } - else { - onGetHost(id).then(function(host) { - handler._getFileState(id).host = host; - promise.success(host); - }, promise.failure); - } + var cachedHost = handler._getFileState(id).host; - return promise; + return new Promise(function(resolve, reject) { + if (cachedHost) { + resolve(cachedHost); + } + else { + onGetHost(id).then(function(host) { + handler._getFileState(id).host = host; + resolve(host); + }, function(errorReason) { + var error = new Error("Failed to get host"); + error.error = errorReason; + reject(error); + }); + } + }); }, getName: function(id) { diff --git a/client/js/s3/util.js b/client/js/s3/util.js index c65a63ffb..a360d5167 100644 --- a/client/js/s3/util.js +++ b/client/js/s3/util.js @@ -338,12 +338,11 @@ qq.s3.util = qq.s3.util || (function() { resolve(awsParams); }, function(errorMessage) { - errorMessage = errorMessage || "Can't continue further with request to S3 as we did not receive " + - "a valid signature and policy from the server."; - - log("Policy signing failed. " + errorMessage, "error"); - - reject(new Error(errorMessage)); + var error = new Error(errorMessage || "Can't continue further with request to S3 as we did not receive " + + "a valid signature and policy from the server."); + error.error = errorMessage; + log("Policy signing failed. " + error.message, "error"); + reject(error); } ); }); From 52bd7dd9ef8608a42be3c2bb626057a4d9d212b3 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 10:34:22 +1100 Subject: [PATCH 44/73] refactor: Uploader getKey to return Promise --- client/js/azure/uploader.basic.js | 4 +- .../uploader.basic.api.js | 86 +- .../js/s3/multipart.abort.ajax.requester.js | 46 +- .../s3/multipart.complete.ajax.requester.js | 87 +- .../s3/multipart.initiate.ajax.requester.js | 58 +- client/js/s3/s3.xhr.upload.handler.js | 125 ++- client/js/s3/uploader.basic.js | 30 +- test/unit/s3/cdn/generic-chunked.js | 74 +- test/unit/s3/chunked-uploads.js | 936 +++++++++--------- test/unit/s3/serverless-uploads.js | 72 +- test/unit/s3/simple-file-uploads.js | 178 ++-- 11 files changed, 870 insertions(+), 826 deletions(-) diff --git a/client/js/azure/uploader.basic.js b/client/js/azure/uploader.basic.js index 66eb06d31..f5b24337a 100644 --- a/client/js/azure/uploader.basic.js +++ b/client/js/azure/uploader.basic.js @@ -77,12 +77,12 @@ }, _getEndpointSpecificParams: function(id) { - return { + return Promise.resolve({ blob: this.getBlobName(id), uuid: this.getUuid(id), name: this.getName(id), container: this._endpointStore.get(id) - }; + }); }, _createUploadHandler: function() { diff --git a/client/js/non-traditional-common/uploader.basic.api.js b/client/js/non-traditional-common/uploader.basic.api.js index 98daa3a5f..1fec08307 100644 --- a/client/js/non-traditional-common/uploader.basic.api.js +++ b/client/js/non-traditional-common/uploader.basic.api.js @@ -51,56 +51,58 @@ log: qq.bind(this.log, this) }); - // combine custom params and default params - qq.extend(uploadSuccessParams, self._getEndpointSpecificParams(id, result, xhr), true); + return new Promise(function(resolve, reject) { + self._getEndpointSpecificParams(id, result, xhr).then(function(endpointSpecificParams) { + // combine custom params and default params + qq.extend(uploadSuccessParams, endpointSpecificParams, true); - // include any params associated with the file - fileParams && qq.extend(uploadSuccessParams, fileParams, true); + // include any params associated with the file + fileParams && qq.extend(uploadSuccessParams, fileParams, true); - return new Promise(function(resolve, reject) { - submitSuccessRequest = qq.bind(function() { - successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams) - .then( - // If we are waiting for confirmation from the local server, and have received it, - // include properties from the local server response in the `response` parameter - // sent to the `onComplete` callback, delegate to the parent `_onComplete`, and - // resolve the associated promise. - function(successRequestResult) { - delete self._failedSuccessRequestCallbacks[id]; - qq.extend(result, successRequestResult); - qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs); - resolve(successRequestResult); - }, - // If the upload success request fails, attempt to re-send the success request (via the core retry code). - // The entire upload may be restarted if the server returns a "reset" property with a value of true as well. - function(successRequestResult) { - var callback = submitSuccessRequest, - error; + submitSuccessRequest = qq.bind(function() { + successAjaxRequester.sendSuccessRequest(id, uploadSuccessParams) + .then( + // If we are waiting for confirmation from the local server, and have received it, + // include properties from the local server response in the `response` parameter + // sent to the `onComplete` callback, delegate to the parent `_onComplete`, and + // resolve the associated promise. + function(successRequestResult) { + delete self._failedSuccessRequestCallbacks[id]; + qq.extend(result, successRequestResult); + qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs); + resolve(successRequestResult); + }, + // If the upload success request fails, attempt to re-send the success request (via the core retry code). + // The entire upload may be restarted if the server returns a "reset" property with a value of true as well. + function(successRequestResult) { + var callback = submitSuccessRequest, + error; - qq.extend(result, successRequestResult); + qq.extend(result, successRequestResult); - if (result && result.reset) { - callback = null; - } + if (result && result.reset) { + callback = null; + } - if (!callback) { - delete self._failedSuccessRequestCallbacks[id]; - } - else { - self._failedSuccessRequestCallbacks[id] = callback; - } + if (!callback) { + delete self._failedSuccessRequestCallbacks[id]; + } + else { + self._failedSuccessRequestCallbacks[id] = callback; + } - if (!self._onAutoRetry(id, name, result, xhr, callback)) { - qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs); - error = new Error("Success request failed"); - error.response = successRequestResult; - reject(error); + if (!self._onAutoRetry(id, name, result, xhr, callback)) { + qq.FineUploaderBasic.prototype._onComplete.apply(self, onCompleteArgs); + error = new Error("Success request failed"); + error.response = successRequestResult; + reject(error); + } } - } - ); - }, self); + ); + }, self); - submitSuccessRequest(); + submitSuccessRequest(); + }); }); } diff --git a/client/js/s3/multipart.abort.ajax.requester.js b/client/js/s3/multipart.abort.ajax.requester.js index bc9d1cb12..e4ff97ea5 100644 --- a/client/js/s3/multipart.abort.ajax.requester.js +++ b/client/js/s3/multipart.abort.ajax.requester.js @@ -42,29 +42,31 @@ qq.s3.AbortMultipartAjaxRequester = function(o) { * @returns {Promise} */ function getHeaders(id, uploadId) { - var headers = {}, - bucket = options.getBucket(id), - host = options.getHost(id), - signatureConstructor = getSignatureAjaxRequester.constructStringToSign - (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_ABORT, bucket, host, options.getKey(id)) - .withUploadId(uploadId); - return new Promise(function(resolve, reject) { - // Ask the local server to sign the request. Use this signature to form the Authorization header. - getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then( - function (signedPolicy, updatedAccessKey, updatedSessionToken) { - resolve({ - signedPolicy: signedPolicy, - updatedAccessKey: updatedAccessKey, - updatedSessionToken: updatedSessionToken - }); - }, - function (reason) { - var error = new Error("Faild to get signature"); - error.error = reason; - reject(error); - } - ); + options.getKey(id).then(function(key) { + var headers = {}, + bucket = options.getBucket(id), + host = options.getHost(id), + signatureConstructor = getSignatureAjaxRequester.constructStringToSign + (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_ABORT, bucket, host, key) + .withUploadId(uploadId); + + // Ask the local server to sign the request. Use this signature to form the Authorization header. + getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then( + function (signedPolicy, updatedAccessKey, updatedSessionToken) { + resolve({ + signedPolicy: signedPolicy, + updatedAccessKey: updatedAccessKey, + updatedSessionToken: updatedSessionToken + }); + }, + function (reason) { + var error = new Error("Faild to get signature"); + error.error = reason; + reject(error); + } + ); + }); }); } diff --git a/client/js/s3/multipart.complete.ajax.requester.js b/client/js/s3/multipart.complete.ajax.requester.js index d07d36862..e83548ca3 100644 --- a/client/js/s3/multipart.complete.ajax.requester.js +++ b/client/js/s3/multipart.complete.ajax.requester.js @@ -42,18 +42,21 @@ qq.s3.CompleteMultipartAjaxRequester = function(o) { * @returns {qq.Promise} */ function getHeaders(id, uploadId, body) { - var headers = {}, - promise = new qq.Promise(), - bucket = options.getBucket(id), - host = options.getHost(id), - signatureConstructor = getSignatureAjaxRequester.constructStringToSign - (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_COMPLETE, bucket, host, options.getKey(id)) - .withUploadId(uploadId) - .withContent(body) - .withContentType("application/xml; charset=UTF-8"); - - // Ask the local server to sign the request. Use this signature to form the Authorization header. - getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure); + var promise = new qq.Promise(); + + options.getKey(id).then(function(key) { + var headers = {}, + bucket = options.getBucket(id), + host = options.getHost(id), + signatureConstructor = getSignatureAjaxRequester.constructStringToSign + (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_COMPLETE, bucket, host, key) + .withUploadId(uploadId) + .withContent(body) + .withContentType("application/xml; charset=UTF-8"); + + // Ask the local server to sign the request. Use this signature to form the Authorization header. + getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure); + }); return promise; } @@ -67,44 +70,46 @@ qq.s3.CompleteMultipartAjaxRequester = function(o) { * @param isError A boolean indicating success or failure according to the base ajax requester (primarily based on status code). */ function handleCompleteRequestComplete(id, xhr, isError) { - var promise = pendingCompleteRequests[id], - domParser = new DOMParser(), - bucket = options.getBucket(id), - key = options.getKey(id), - responseDoc = domParser.parseFromString(xhr.responseText, "application/xml"), - bucketEls = responseDoc.getElementsByTagName("Bucket"), - keyEls = responseDoc.getElementsByTagName("Key"); + var promise = pendingCompleteRequests[id]; - delete pendingCompleteRequests[id]; + options.getKey(id).then(function(key) { + var domParser = new DOMParser(), + bucket = options.getBucket(id), + responseDoc = domParser.parseFromString(xhr.responseText, "application/xml"), + bucketEls = responseDoc.getElementsByTagName("Bucket"), + keyEls = responseDoc.getElementsByTagName("Key"); - options.log(qq.format("Complete response status {}, body = {}", xhr.status, xhr.responseText)); + delete pendingCompleteRequests[id]; - // If the base requester has determine this a failure, give up. - if (isError) { - options.log(qq.format("Complete Multipart Upload request for {} failed with status {}.", id, xhr.status), "error"); - } - else { - // Make sure the correct bucket and key has been specified in the XML response from AWS. - if (bucketEls.length && keyEls.length) { - if (bucketEls[0].textContent !== bucket) { + options.log(qq.format("Complete response status {}, body = {}", xhr.status, xhr.responseText)); + + // If the base requester has determine this a failure, give up. + if (isError) { + options.log(qq.format("Complete Multipart Upload request for {} failed with status {}.", id, xhr.status), "error"); + } + else { + // Make sure the correct bucket and key has been specified in the XML response from AWS. + if (bucketEls.length && keyEls.length) { + if (bucketEls[0].textContent !== bucket) { + isError = true; + options.log(qq.format("Wrong bucket in response to Complete Multipart Upload request for {}.", id), "error"); + } + + // TODO Compare key name from response w/ expected key name if AWS ever fixes the encoding of key names in this response. + } + else { isError = true; - options.log(qq.format("Wrong bucket in response to Complete Multipart Upload request for {}.", id), "error"); + options.log(qq.format("Missing bucket and/or key in response to Complete Multipart Upload request for {}.", id), "error"); } + } - // TODO Compare key name from response w/ expected key name if AWS ever fixes the encoding of key names in this response. + if (isError) { + promise.failure("Problem combining the file parts!", xhr); } else { - isError = true; - options.log(qq.format("Missing bucket and/or key in response to Complete Multipart Upload request for {}.", id), "error"); + promise.success({}, xhr); } - } - - if (isError) { - promise.failure("Problem combining the file parts!", xhr); - } - else { - promise.success({}, xhr); - } + }); } /** diff --git a/client/js/s3/multipart.initiate.ajax.requester.js b/client/js/s3/multipart.initiate.ajax.requester.js index 52aa65dc3..31f3303f7 100644 --- a/client/js/s3/multipart.initiate.ajax.requester.js +++ b/client/js/s3/multipart.initiate.ajax.requester.js @@ -49,41 +49,43 @@ qq.s3.InitiateMultipartAjaxRequester = function(o) { * @returns {qq.Promise} */ function getHeaders(id) { - var bucket = options.getBucket(id), - host = options.getHost(id), - headers = {}, - promise = new qq.Promise(), - key = options.getKey(id), - signatureConstructor; + var promise = new qq.Promise(); - headers["x-amz-acl"] = options.aclStore.get(id); + options.getKey(id).then(function(key) { + var bucket = options.getBucket(id), + host = options.getHost(id), + headers = {}, + signatureConstructor; - if (options.reducedRedundancy) { - headers[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE; - } - - if (options.serverSideEncryption) { - headers[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE; - } + headers["x-amz-acl"] = options.aclStore.get(id); - headers[qq.s3.util.AWS_PARAM_PREFIX + options.filenameParam] = encodeURIComponent(options.getName(id)); - - qq.each(options.paramsStore.get(id), function(name, val) { - if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, name) >= 0) { - headers[name] = val; + if (options.reducedRedundancy) { + headers[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME] = qq.s3.util.REDUCED_REDUNDANCY_PARAM_VALUE; } - else { - headers[qq.s3.util.AWS_PARAM_PREFIX + name] = encodeURIComponent(val); + + if (options.serverSideEncryption) { + headers[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME] = qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_VALUE; } - }); - signatureConstructor = getSignatureAjaxRequester.constructStringToSign - (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_INITIATE, bucket, host, key) - .withContentType(options.getContentType(id)) - .withHeaders(headers); + headers[qq.s3.util.AWS_PARAM_PREFIX + options.filenameParam] = encodeURIComponent(options.getName(id)); + + qq.each(options.paramsStore.get(id), function(name, val) { + if (qq.indexOf(qq.s3.util.UNPREFIXED_PARAM_NAMES, name) >= 0) { + headers[name] = val; + } + else { + headers[qq.s3.util.AWS_PARAM_PREFIX + name] = encodeURIComponent(val); + } + }); - // Ask the local server to sign the request. Use this signature to form the Authorization header. - getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure); + signatureConstructor = getSignatureAjaxRequester.constructStringToSign + (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_INITIATE, bucket, host, key) + .withContentType(options.getContentType(id)) + .withHeaders(headers); + + // Ask the local server to sign the request. Use this signature to form the Authorization header. + getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure); + }); return promise; } diff --git a/client/js/s3/s3.xhr.upload.handler.js b/client/js/s3/s3.xhr.upload.handler.js index 250106bc3..5010e509d 100755 --- a/client/js/s3/s3.xhr.upload.handler.js +++ b/client/js/s3/s3.xhr.upload.handler.js @@ -82,24 +82,25 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { * @returns {Promise} */ initHeaders: function(id, chunkIdx, blob) { - var headers = {}, - bucket = upload.bucket.getName(id), - host = upload.host.getName(id), - key = upload.key.urlSafe(id), - signatureConstructor = requesters.restSignature.constructStringToSign - (requesters.restSignature.REQUEST_TYPE.MULTIPART_UPLOAD, bucket, host, key) - .withPartNum(chunkIdx + 1) - .withContent(blob) - .withUploadId(handler._getPersistableData(id).uploadId); - return new Promise(function(resolve, reject) { - // Ask the local server to sign the request. Use this signature to form the Authorization header. - requesters.restSignature.getSignature(id + "." + chunkIdx, {signatureConstructor: signatureConstructor}).then( - function (headers, endOfUrl) { - resolve({headers: headers, endOfUrl: endOfUrl}); - }, function() { - reject(); - }); + upload.key.urlSafe(id).then(function(key) { + var headers = {}, + bucket = upload.bucket.getName(id), + host = upload.host.getName(id), + signatureConstructor = requesters.restSignature.constructStringToSign + (requesters.restSignature.REQUEST_TYPE.MULTIPART_UPLOAD, bucket, host, key) + .withPartNum(chunkIdx + 1) + .withContent(blob) + .withUploadId(handler._getPersistableData(id).uploadId); + + // Ask the local server to sign the request. Use this signature to form the Authorization header. + requesters.restSignature.getSignature(id + "." + chunkIdx, {signatureConstructor: signatureConstructor}).then( + function (headers, endOfUrl) { + resolve({headers: headers, endOfUrl: endOfUrl}); + }, function() { + reject(); + }); + }); }); }, @@ -293,26 +294,28 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { var customParams = paramsStore.get(id); customParams[filenameParam] = getName(id); - return qq.s3.util.generateAwsParams({ - endpoint: endpointStore.get(id), - clockDrift: clockDrift, - params: customParams, - type: handler._getMimeType(id), - bucket: upload.bucket.getName(id), - key: handler.getThirdPartyFileId(id), - accessKey: credentialsProvider.get().accessKey, - sessionToken: credentialsProvider.get().sessionToken, - acl: aclStore.get(id), - expectedStatus: expectedStatus, - minFileSize: validation.minSizeLimit, - maxFileSize: validation.maxSizeLimit, - reducedRedundancy: reducedRedundancy, - region: region, - serverSideEncryption: serverSideEncryption, - signatureVersion: signature.version, - log: log - }, - qq.bind(requesters.policySignature.getSignature, this, id)); + return (handler.getThirdPartyFileId(id) || Promise.resolve(undefined)).then(function(thirdPartyFileId) { + return qq.s3.util.generateAwsParams({ + endpoint: endpointStore.get(id), + clockDrift: clockDrift, + params: customParams, + type: handler._getMimeType(id), + bucket: upload.bucket.getName(id), + key: thirdPartyFileId, + accessKey: credentialsProvider.get().accessKey, + sessionToken: credentialsProvider.get().sessionToken, + acl: aclStore.get(id), + expectedStatus: expectedStatus, + minFileSize: validation.minSizeLimit, + maxFileSize: validation.maxSizeLimit, + reducedRedundancy: reducedRedundancy, + region: region, + serverSideEncryption: serverSideEncryption, + signatureVersion: signature.version, + log: log + }, + qq.bind(requesters.policySignature.getSignature, this, id)); + }); }, send: function(id) { @@ -442,36 +445,33 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { key: { promise: function(id) { - var promise = new qq.Promise(), - key = handler.getThirdPartyFileId(id); + var key = handler.getThirdPartyFileId(id); /* jshint eqnull:true */ if (key == null) { - handler._setThirdPartyFileId(id, promise); - onGetKeyName(id, getName(id)).then( - function(keyName) { - handler._setThirdPartyFileId(id, keyName); - promise.success(keyName); - }, - function(errorReason) { - handler._setThirdPartyFileId(id, null); - promise.failure(errorReason); - } - ); - } - else if (qq.isGenericPromise(key)) { - key.then(promise.success, promise.failure); - } - else { - promise.success(key); + key = new Promise(function(resolve, reject) { + onGetKeyName(id, getName(id)).then( + function(keyName) { + resolve(keyName); + }, + function(errorReason) { + handler._setThirdPartyFileId(id, null); + var error = new Error(errorReason); + error.error = errorReason; + reject(error); + } + ); + }); + handler._setThirdPartyFileId(id, key); } - return promise; + return key; }, urlSafe: function(id) { - var encodedKey = handler.getThirdPartyFileId(id); - return qq.s3.util.uriEscapePath(encodedKey); + return handler.getThirdPartyFileId(id).then(function(encodedKey) { + return qq.s3.util.uriEscapePath(encodedKey); + }); } }, @@ -559,12 +559,7 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { } }); }, reject); - }, - function(errorReason) { - var error = new Error(errorReason); - error.error = errorReason; - reject(error); - }); + }, reject); }); }, diff --git a/client/js/s3/uploader.basic.js b/client/js/s3/uploader.basic.js index e3c82c6bf..a8999c948 100644 --- a/client/js/s3/uploader.basic.js +++ b/client/js/s3/uploader.basic.js @@ -405,21 +405,25 @@ }, _getEndpointSpecificParams: function(id, response, maybeXhr) { - var params = { - key: this.getKey(id), - uuid: this.getUuid(id), - name: this.getName(id), - bucket: this.getBucket(id) - }; + var self = this; + + return this.getKey(id).then(function(key) { + var params = { + key: key, + uuid: self.getUuid(id), + name: self.getName(id), + bucket: self.getBucket(id) + }; - if (maybeXhr && maybeXhr.getResponseHeader("ETag")) { - params.etag = maybeXhr.getResponseHeader("ETag"); - } - else if (response.etag) { - params.etag = response.etag; - } + if (maybeXhr && maybeXhr.getResponseHeader("ETag")) { + params.etag = maybeXhr.getResponseHeader("ETag"); + } + else if (response.etag) { + params.etag = response.etag; + } - return params; + return params; + }); }, // Hooks into the base internal `_onSubmitDelete` to add key and bucket params to the delete file request. diff --git a/test/unit/s3/cdn/generic-chunked.js b/test/unit/s3/cdn/generic-chunked.js index d9b2112a1..763c0eea6 100644 --- a/test/unit/s3/cdn/generic-chunked.js +++ b/test/unit/s3/cdn/generic-chunked.js @@ -39,59 +39,61 @@ if (qqtest.canDownloadFileAsBlob) { initiateSignatureRequest = fileTestHelper.getRequests()[0]; initiateToSign = JSON.parse(initiateSignatureRequest.requestBody); - // signature request for initiate multipart upload - assert.ok(initiateToSign.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?uploads") > 0); - initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + uploader.getKey(0).then(function(key0) { + // signature request for initiate multipart upload + assert.ok(initiateToSign.headers.indexOf("/mybucket/" + key0 + "?uploads") > 0); + initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - // initiate multipart upload request - initiateRequest = fileTestHelper.getRequests()[1]; - initiateRequest.respond(200, null, "123"); - - setTimeout(function() { - // signature request for upload part 1 - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + // initiate multipart upload request + initiateRequest = fileTestHelper.getRequests()[1]; + initiateRequest.respond(200, null, "123"); setTimeout(function() { - // upload part 1 request - uploadPartRequest = fileTestHelper.getRequests()[2]; - uploadPartRequest.respond(200, {ETag: "etag1"}, null); + // signature request for upload part 1 + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers.indexOf("/mybucket/" + key0 + "?partNumber=1&uploadId=123") > 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - // signature request for upload part 2 - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + // upload part 1 request + uploadPartRequest = fileTestHelper.getRequests()[2]; + uploadPartRequest.respond(200, {ETag: "etag1"}, null); setTimeout(function() { - // upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[4]; - uploadPartRequest.respond(200, {ETag: "etag2"}, null); + // signature request for upload part 2 + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/mybucket/" + key0 + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - // signature request for multipart complete - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/mybucket/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // multipart complete request - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - multipartCompleteRequest.respond(200, null, "mybucket" + uploader.getKey(0) + ""); + // upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[4]; + uploadPartRequest.respond(200, {ETag: "etag2"}, null); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + // signature request for multipart complete + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/mybucket/" + key0 + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + // multipart complete request + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + multipartCompleteRequest.respond(200, null, "mybucket" + key0 + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + done(); + }, 0); }, 0); }, 0); }, 0); }, 0); }, 0); - }, 0); + }); }, 0); }); }, diff --git a/test/unit/s3/chunked-uploads.js b/test/unit/s3/chunked-uploads.js index bab0c2442..0c2ce8dcd 100644 --- a/test/unit/s3/chunked-uploads.js +++ b/test/unit/s3/chunked-uploads.js @@ -124,129 +124,131 @@ if (qqtest.canDownloadFileAsBlob) { assert.ok(initiateToSign.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - setTimeout(function() { - // initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 2); - initiateRequest = fileTestHelper.getRequests()[1]; - assert.equal(initiateRequest.method, "POST"); - assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); - assert.equal(initiateRequest.requestHeaders["x-amz-meta-qqfilename"], uploader.getName(0)); - assert.equal(initiateRequest.requestHeaders["x-amz-acl"], "private"); - assert.ok(initiateRequest.requestHeaders["x-amz-date"]); - assert.equal(initiateRequest.requestHeaders.Authorization.indexOf("AWS4-HMAC-SHA256 Credential=testAccessKey/"), 0); - var authParts = initiateRequest.requestHeaders.Authorization.split(";"); - assert.equal(authParts.length, 5); - assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); - assert.equal(authParts[1], "x-amz-acl"); - assert.equal(authParts[2], "x-amz-content-sha256"); - assert.equal(authParts[3], "x-amz-date"); - assert.equal(authParts[4], "x-amz-meta-qqfilename,Signature=thesignature"); - initiateRequest.respond(200, null, "123"); - + uploader.getKey(0).then(function(key0) { setTimeout(function() { - // signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 4); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; - assert.equal(uploadPartSignatureRequest1.method, "POST"); - assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint + "?v4=true"); - assert.equal(uploadPartSignatureRequest1.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers); - assert.equal(uploadPartToSign1.headers.indexOf("AWS4-HMAC-SHA256"), 0); - assert.ok(uploadPartToSign1.headers.indexOf("/us-east-1/s3/aws4_request") > 0); - assert.equal(uploadPartToSign1.headers.split("\n").length, 12); - assert.ok(uploadPartToSign1.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + // initiate multipart upload request + assert.equal(fileTestHelper.getRequests().length, 2); + initiateRequest = fileTestHelper.getRequests()[1]; + assert.equal(initiateRequest.method, "POST"); + assert.equal(initiateRequest.url, testS3Endpoint + "/" + key0 + "?uploads"); + assert.equal(initiateRequest.requestHeaders["x-amz-meta-qqfilename"], uploader.getName(0)); + assert.equal(initiateRequest.requestHeaders["x-amz-acl"], "private"); + assert.ok(initiateRequest.requestHeaders["x-amz-date"]); + assert.equal(initiateRequest.requestHeaders.Authorization.indexOf("AWS4-HMAC-SHA256 Credential=testAccessKey/"), 0); + var authParts = initiateRequest.requestHeaders.Authorization.split(";"); + assert.equal(authParts.length, 5); + assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); + assert.equal(authParts[1], "x-amz-acl"); + assert.equal(authParts[2], "x-amz-content-sha256"); + assert.equal(authParts[3], "x-amz-date"); + assert.equal(authParts[4], "x-amz-meta-qqfilename,Signature=thesignature"); + initiateRequest.respond(200, null, "123"); setTimeout(function() { - // upload part 1 request - uploadPartRequest = fileTestHelper.getRequests()[2]; - assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); - - assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); - - var authParts = uploadPartRequest.requestHeaders.Authorization.split(";"); - assert.equal(authParts.length, 3); - assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); - assert.equal(authParts[1], "x-amz-content-sha256"); - assert.equal(authParts[2], "x-amz-date,Signature=thesignature"); - uploadPartRequest.respond(200, {ETag: "etag1"}, null); + // signature request for upload part 1 + assert.equal(fileTestHelper.getRequests().length, 4); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; + assert.equal(uploadPartSignatureRequest1.method, "POST"); + assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint + "?v4=true"); + assert.equal(uploadPartSignatureRequest1.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers); + assert.equal(uploadPartToSign1.headers.indexOf("AWS4-HMAC-SHA256"), 0); + assert.ok(uploadPartToSign1.headers.indexOf("/us-east-1/s3/aws4_request") > 0); + assert.equal(uploadPartToSign1.headers.split("\n").length, 12); + assert.ok(uploadPartToSign1.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - // signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 6); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; - assert.equal(uploadPartSignatureRequest2.method, "POST"); - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint + "?v4=true"); - assert.equal(uploadPartSignatureRequest2.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers); - assert.equal(uploadPartToSign2.headers.indexOf("AWS4-HMAC-SHA256"), 0); - assert.ok(uploadPartToSign2.headers.indexOf("/us-east-1/s3/aws4_request") > 0); - assert.equal(uploadPartToSign2.headers.split("\n").length, 12); - assert.ok(uploadPartToSign2.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + // upload part 1 request + uploadPartRequest = fileTestHelper.getRequests()[2]; + assert.equal(uploadPartRequest.method, "PUT"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=1&uploadId=123"); + assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); + + assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); + + var authParts = uploadPartRequest.requestHeaders.Authorization.split(";"); + assert.equal(authParts.length, 3); + assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); + assert.equal(authParts[1], "x-amz-content-sha256"); + assert.equal(authParts[2], "x-amz-date,Signature=thesignature"); + uploadPartRequest.respond(200, {ETag: "etag1"}, null); setTimeout(function() { - // upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[4]; - assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); + // signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 6); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; + assert.equal(uploadPartSignatureRequest2.method, "POST"); + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint + "?v4=true"); + assert.equal(uploadPartSignatureRequest2.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers); + assert.equal(uploadPartToSign2.headers.indexOf("AWS4-HMAC-SHA256"), 0); + assert.ok(uploadPartToSign2.headers.indexOf("/us-east-1/s3/aws4_request") > 0); + assert.equal(uploadPartToSign2.headers.split("\n").length, 12); + assert.ok(uploadPartToSign2.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); + setTimeout(function() { + // upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[4]; + assert.equal(uploadPartRequest.method, "PUT"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=2&uploadId=123"); + assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); - var authParts = uploadPartRequest.requestHeaders.Authorization.split(";"); - assert.equal(authParts.length, 3); - assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); - assert.equal(authParts[1], "x-amz-content-sha256"); - assert.equal(authParts[2], "x-amz-date,Signature=thesignature"); - uploadPartRequest.respond(200, {ETag: "etag2"}, null); + assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); - setTimeout(function() { - // signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 7); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; - assert.equal(uploadCompleteSignatureRequest.method, "POST"); - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint + "?v4=true"); - assert.equal(uploadCompleteSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers); - assert.equal(uploadCompleteToSign.headers.indexOf("AWS4-HMAC-SHA256"), 0); - assert.ok(uploadCompleteToSign.headers.indexOf("/us-east-1/s3/aws4_request") > 0); - assert.equal(uploadCompleteToSign.headers.split("\n").length, 12); - assert.ok(uploadCompleteToSign.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + var authParts = uploadPartRequest.requestHeaders.Authorization.split(";"); + assert.equal(authParts.length, 3); + assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); + assert.equal(authParts[1], "x-amz-content-sha256"); + assert.equal(authParts[2], "x-amz-date,Signature=thesignature"); + uploadPartRequest.respond(200, {ETag: "etag2"}, null); setTimeout(function() { - // multipart complete request - assert.equal(fileTestHelper.getRequests().length, 8); - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - assert.equal(multipartCompleteRequest.method, "POST"); - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); - - authParts = multipartCompleteRequest.requestHeaders.Authorization.split(";"); - assert.equal(authParts.length, 3); - assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); - assert.equal(authParts[1], "x-amz-content-sha256"); - assert.equal(authParts[2], "x-amz-date,Signature=thesignature"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + // signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 7); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; + assert.equal(uploadCompleteSignatureRequest.method, "POST"); + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint + "?v4=true"); + assert.equal(uploadCompleteSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers); + assert.equal(uploadCompleteToSign.headers.indexOf("AWS4-HMAC-SHA256"), 0); + assert.ok(uploadCompleteToSign.headers.indexOf("/us-east-1/s3/aws4_request") > 0); + assert.equal(uploadCompleteToSign.headers.split("\n").length, 12); + assert.ok(uploadCompleteToSign.headers.indexOf("host:mytestbucket.s3.amazonaws.com")); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + // multipart complete request + assert.equal(fileTestHelper.getRequests().length, 8); + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + assert.equal(multipartCompleteRequest.method, "POST"); + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + key0 + "?uploadId=123"); + assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); + + authParts = multipartCompleteRequest.requestHeaders.Authorization.split(";"); + assert.equal(authParts.length, 3); + assert.equal(authParts[0].split(",")[1], "SignedHeaders=host"); + assert.equal(authParts[1], "x-amz-content-sha256"); + assert.equal(authParts[2], "x-amz-date,Signature=thesignature"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + key0 + ""); - done(); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + + done(); + }, 0); }, 0); }, 0); }, 0); }, 0); }, 0); - }, 0); - }, 100); - }, 0); + }, 100); + }, 0); + }); }); }); }); @@ -318,117 +320,119 @@ if (qqtest.canDownloadFileAsBlob) { uploadCompleteToSign, multipartCompleteRequest; - // signature request for initiate multipart upload - assert.equal(initiateSignatureRequest.url, testSignatureEndoint); - assert.equal(initiateSignatureRequest.method, "POST"); - assert.equal(initiateSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - assert.ok(initiateToSign.headers); - assert.equal(initiateToSign.headers.indexOf("POST"), 0); - assert.ok(initiateToSign.headers.indexOf("image/jpeg") > 0); - assert.ok(initiateToSign.headers.indexOf("x-amz-acl:private") > 0); - assert.ok(initiateToSign.headers.indexOf("x-amz-date:") > 0); - assert.ok(initiateToSign.headers.indexOf("x-amz-meta-qqfilename:" + uploader.getName(0)) > 0); - assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploads") > 0); - initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 2); - initiateRequest = fileTestHelper.getRequests()[1]; - assert.equal(initiateRequest.method, "POST"); - assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); - assert.equal(initiateRequest.requestHeaders["x-amz-meta-qqfilename"], uploader.getName(0)); - assert.equal(initiateRequest.requestHeaders["x-amz-acl"], "private"); - assert.ok(initiateRequest.requestHeaders["x-amz-date"]); - assert.equal(initiateRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); - initiateRequest.respond(200, null, "123"); + uploader.getKey(0).then(function(key0) { + // signature request for initiate multipart upload + assert.equal(initiateSignatureRequest.url, testSignatureEndoint); + assert.equal(initiateSignatureRequest.method, "POST"); + assert.equal(initiateSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + assert.ok(initiateToSign.headers); + assert.equal(initiateToSign.headers.indexOf("POST"), 0); + assert.ok(initiateToSign.headers.indexOf("image/jpeg") > 0); + assert.ok(initiateToSign.headers.indexOf("x-amz-acl:private") > 0); + assert.ok(initiateToSign.headers.indexOf("x-amz-date:") > 0); + assert.ok(initiateToSign.headers.indexOf("x-amz-meta-qqfilename:" + uploader.getName(0)) > 0); + assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + key0 + "?uploads") > 0); + initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - setTimeout(function() { - // signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 4); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; - assert.equal(uploadPartSignatureRequest1.method, "POST"); - assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); - assert.equal(uploadPartSignatureRequest1.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers); - assert.equal(uploadPartToSign1.headers.indexOf("PUT"), 0); - assert.ok(uploadPartToSign1.headers.indexOf("x-amz-date:") > 0); - assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + // initiate multipart upload request + assert.equal(fileTestHelper.getRequests().length, 2); + initiateRequest = fileTestHelper.getRequests()[1]; + assert.equal(initiateRequest.method, "POST"); + assert.equal(initiateRequest.url, testS3Endpoint + "/" + key0 + "?uploads"); + assert.equal(initiateRequest.requestHeaders["x-amz-meta-qqfilename"], uploader.getName(0)); + assert.equal(initiateRequest.requestHeaders["x-amz-acl"], "private"); + assert.ok(initiateRequest.requestHeaders["x-amz-date"]); + assert.equal(initiateRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); + initiateRequest.respond(200, null, "123"); setTimeout(function() { - // upload part 1 request - uploadPartRequest = fileTestHelper.getRequests()[2]; - assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); + // signature request for upload part 1 + assert.equal(fileTestHelper.getRequests().length, 4); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; + assert.equal(uploadPartSignatureRequest1.method, "POST"); + assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); + assert.equal(uploadPartSignatureRequest1.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers); + assert.equal(uploadPartToSign1.headers.indexOf("PUT"), 0); + assert.ok(uploadPartToSign1.headers.indexOf("x-amz-date:") > 0); + assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + key0 + "?partNumber=1&uploadId=123") > 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); - assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); + setTimeout(function() { + // upload part 1 request + uploadPartRequest = fileTestHelper.getRequests()[2]; + assert.equal(uploadPartRequest.method, "PUT"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=1&uploadId=123"); + assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); - assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); - uploadPartRequest.respond(200, {ETag: "etag1"}, null); + assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); - setTimeout(function() { - // signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 6); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; - assert.equal(uploadPartSignatureRequest2.method, "POST"); - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - assert.equal(uploadPartSignatureRequest2.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers); - assert.equal(uploadPartToSign2.headers.indexOf("PUT"), 0); - assert.ok(uploadPartToSign2.headers.indexOf("x-amz-date:") > 0); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); + uploadPartRequest.respond(200, {ETag: "etag1"}, null); setTimeout(function() { - // upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[4]; - assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); + // signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 6); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; + assert.equal(uploadPartSignatureRequest2.method, "POST"); + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + assert.equal(uploadPartSignatureRequest2.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers); + assert.equal(uploadPartToSign2.headers.indexOf("PUT"), 0); + assert.ok(uploadPartToSign2.headers.indexOf("x-amz-date:") > 0); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + key0 + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); + setTimeout(function() { + // upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[4]; + assert.equal(uploadPartRequest.method, "PUT"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=2&uploadId=123"); + assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); - assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); - uploadPartRequest.respond(200, {ETag: "etag2"}, null); + assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); - setTimeout(function() { - // signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 7); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; - assert.equal(uploadCompleteSignatureRequest.method, "POST"); - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - assert.equal(uploadCompleteSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers); - assert.equal(uploadCompleteToSign.headers.indexOf("POST"), 0); - assert.ok(uploadCompleteToSign.headers.indexOf("x-amz-date:") > 0); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); + uploadPartRequest.respond(200, {ETag: "etag2"}, null); setTimeout(function() { - // multipart complete request - assert.equal(fileTestHelper.getRequests().length, 8); - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - assert.equal(multipartCompleteRequest.method, "POST"); - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); - assert.equal(multipartCompleteRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); - assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + // signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 7); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; + assert.equal(uploadCompleteSignatureRequest.method, "POST"); + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + assert.equal(uploadCompleteSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers); + assert.equal(uploadCompleteToSign.headers.indexOf("POST"), 0); + assert.ok(uploadCompleteToSign.headers.indexOf("x-amz-date:") > 0); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + key0 + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + // multipart complete request + assert.equal(fileTestHelper.getRequests().length, 8); + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + assert.equal(multipartCompleteRequest.method, "POST"); + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + key0 + "?uploadId=123"); + assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); + assert.equal(multipartCompleteRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); + assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + key0 + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + done(); + }, 0); }, 0); }, 0); }, 0); }, 0); }, 0); }, 0); - }, 0); + }); }); }); @@ -512,11 +516,13 @@ if (qqtest.canDownloadFileAsBlob) { multipartCompleteRequest = fileTestHelper.getRequests()[7]; assert.ok(!multipartCompleteRequest.requestHeaders[qq.s3.util.SERVER_SIDE_ENCRYPTION_PARAM_NAME]); assert.ok(!multipartCompleteRequest.requestHeaders[qq.s3.util.REDUCED_REDUNDANCY_PARAM_NAME]); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + uploader.getKey(0).then(function(key0) { + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + key0 + ""); - setTimeout(function () { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - }, 0); + setTimeout(function () { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + }, 0); + }); }, 0); }, 0); }, 0); @@ -571,212 +577,214 @@ if (qqtest.canDownloadFileAsBlob) { initiateSignatureRequest.respond(200, null, JSON.stringify({invalid: true})); assert.equal(fileTestHelper.getRequests().length, 1); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); - uploader.retry(0); + uploader.getKey(0).then(function(key0) { setTimeout(function() { - assert.equal(fileTestHelper.getRequests().length, 2); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful initiate signature request - initiateSignatureRequest = fileTestHelper.getRequests()[1]; - assert.equal(initiateSignatureRequest.url, testSignatureEndoint); - assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploads") > 0); - initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + uploader.retry(0); setTimeout(function() { - // failing initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 3); - initiateRequest = fileTestHelper.getRequests()[2]; - assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); - initiateRequest.respond(200, null, ""); + assert.equal(fileTestHelper.getRequests().length, 2); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful initiate signature request + initiateSignatureRequest = fileTestHelper.getRequests()[1]; + assert.equal(initiateSignatureRequest.url, testSignatureEndoint); + assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + key0 + "?uploads") > 0); + initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + // failing initiate multipart upload request assert.equal(fileTestHelper.getRequests().length, 3); - uploader.retry(0); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful initiate signature request - assert.equal(fileTestHelper.getRequests().length, 4); - initiateSignatureRequest = fileTestHelper.getRequests()[3]; - assert.equal(initiateSignatureRequest.url, testSignatureEndoint); - assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploads") > 0); - initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + initiateRequest = fileTestHelper.getRequests()[2]; + assert.equal(initiateRequest.url, testS3Endpoint + "/" + key0 + "?uploads"); + initiateRequest.respond(200, null, ""); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 3); + uploader.retry(0); setTimeout(function() { - // successful initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 5); - initiateRequest = fileTestHelper.getRequests()[4]; - assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); - initiateRequest.respond(200, null, "123"); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful initiate signature request + assert.equal(fileTestHelper.getRequests().length, 4); + initiateSignatureRequest = fileTestHelper.getRequests()[3]; + assert.equal(initiateSignatureRequest.url, testSignatureEndoint); + assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + key0 + "?uploads") > 0); + initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - // failed signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 7); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[6]; - assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({invalid: true})); + // successful initiate multipart upload request + assert.equal(fileTestHelper.getRequests().length, 5); + initiateRequest = fileTestHelper.getRequests()[4]; + assert.equal(initiateRequest.url, testS3Endpoint + "/" + key0 + "?uploads"); + initiateRequest.respond(200, null, "123"); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + // failed signature request for upload part 1 assert.equal(fileTestHelper.getRequests().length, 7); - uploader.retry(0); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 9); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[8]; - assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[6]; + assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + key0 + "?partNumber=1&uploadId=123") > 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({invalid: true})); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 7); + uploader.retry(0); setTimeout(function() { - // failing upload part 1 request + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for upload part 1 assert.equal(fileTestHelper.getRequests().length, 9); - uploadPartRequest = fileTestHelper.getRequests()[7]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - uploadPartRequest.respond(404, {ETag: "etag1"}, null); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[8]; + assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + key0 + "?partNumber=1&uploadId=123") > 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + // failing upload part 1 request assert.equal(fileTestHelper.getRequests().length, 9); - uploader.retry(0); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 11); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[10]; - assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + uploadPartRequest = fileTestHelper.getRequests()[7]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=1&uploadId=123"); + uploadPartRequest.respond(404, {ETag: "etag1"}, null); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 9); + uploader.retry(0); setTimeout(function() { - // successful upload part 1 request + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for upload part 1 assert.equal(fileTestHelper.getRequests().length, 11); - uploadPartRequest = fileTestHelper.getRequests()[9]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - uploadPartRequest.respond(200, {ETag: "etag1_a"}, null); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[10]; + assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + key0 + "?partNumber=1&uploadId=123") > 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - // failing signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 13); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[12]; - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(404, null, JSON.stringify({signature: "thesignature"})); + // successful upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 11); + uploadPartRequest = fileTestHelper.getRequests()[9]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=1&uploadId=123"); + uploadPartRequest.respond(200, {ETag: "etag1_a"}, null); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + // failing signature request for upload part 2 assert.equal(fileTestHelper.getRequests().length, 13); - uploader.retry(0); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 15); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[14]; - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[12]; + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + key0 + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(404, null, JSON.stringify({signature: "thesignature"})); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 13); + uploader.retry(0); setTimeout(function() { - // failing upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[13]; + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for upload part 2 assert.equal(fileTestHelper.getRequests().length, 15); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - uploadPartRequest.respond(404, {ETag: "etag2"}, null); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[14]; + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + key0 + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + // failing upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[13]; assert.equal(fileTestHelper.getRequests().length, 15); - uploader.retry(0); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 17); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[16]; - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=2&uploadId=123"); + uploadPartRequest.respond(404, {ETag: "etag2"}, null); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 15); + uploader.retry(0); setTimeout(function() { - // successful upload part 2 request + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for upload part 2 assert.equal(fileTestHelper.getRequests().length, 17); - uploadPartRequest = fileTestHelper.getRequests()[15]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - uploadPartRequest.respond(200, {ETag: "etag2_a"}, null); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[16]; + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + key0 + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - // failing signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 18); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[17]; - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(400, null, JSON.stringify({signature: "thesignature"})); + // successful upload part 2 request + assert.equal(fileTestHelper.getRequests().length, 17); + uploadPartRequest = fileTestHelper.getRequests()[15]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=2&uploadId=123"); + uploadPartRequest.respond(200, {ETag: "etag2_a"}, null); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + // failing signature request for multipart complete assert.equal(fileTestHelper.getRequests().length, 18); - uploader.retry(0); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 19); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[18]; - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[17]; + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + key0 + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(400, null, JSON.stringify({signature: "thesignature"})); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 18); + uploader.retry(0); setTimeout(function() { - // failing multipart complete request - assert.equal(fileTestHelper.getRequests().length, 20); - multipartCompleteRequest = fileTestHelper.getRequests()[19]; - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + uploader.getKey(0) + ""); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 19); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[18]; + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + key0 + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + // failing multipart complete request assert.equal(fileTestHelper.getRequests().length, 20); - uploader.retry(0); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 21); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[20]; - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + uploader.getKey(0) + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + multipartCompleteRequest = fileTestHelper.getRequests()[19]; + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + key0 + "?uploadId=123"); + assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); + multipartCompleteRequest.respond(200, null, "" + key0 + ""); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 20); + uploader.retry(0); setTimeout(function() { - // successful multipart complete request - assert.equal(fileTestHelper.getRequests().length, 22); - multipartCompleteRequest = fileTestHelper.getRequests()[21]; - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + // successful signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 21); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[20]; + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + key0 + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - done(); + setTimeout(function() { + // successful multipart complete request + assert.equal(fileTestHelper.getRequests().length, 22); + multipartCompleteRequest = fileTestHelper.getRequests()[21]; + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + key0 + "?uploadId=123"); + assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + key0 + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + + done(); + }, 0); }, 0); }, 0); }, 0); @@ -804,7 +812,7 @@ if (qqtest.canDownloadFileAsBlob) { }, 0); }, 0); }, 0); - }, 0); + }); }); }); @@ -897,61 +905,63 @@ if (qqtest.canDownloadFileAsBlob) { initiateRequest, multipartCompleteRequest; - // initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 1); - initiateRequest = fileTestHelper.getRequests()[0]; - assert.equal(initiateRequest.method, "POST"); - assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); - assert.equal(initiateRequest.requestHeaders["x-amz-meta-qqfilename"], uploader.getName(0)); - assert.equal(initiateRequest.requestHeaders["x-amz-acl"], "private"); - assert.ok(initiateRequest.requestHeaders["x-amz-date"]); - assert.equal(initiateRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "Initiate MP request Authorization header invalid"); - initiateRequest.respond(200, null, "123"); - - setTimeout(function () { - // upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 2); - uploadPartRequest = fileTestHelper.getRequests()[1]; - assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); - - assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); - - assert.equal(uploadPartRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "Upload part 1 request Authorization header is invalid"); - uploadPartRequest.respond(200, {ETag: "etag1"}, null); + uploader.getKey(0).then(function(key0) { + // initiate multipart upload request + assert.equal(fileTestHelper.getRequests().length, 1); + initiateRequest = fileTestHelper.getRequests()[0]; + assert.equal(initiateRequest.method, "POST"); + assert.equal(initiateRequest.url, testS3Endpoint + "/" + key0 + "?uploads"); + assert.equal(initiateRequest.requestHeaders["x-amz-meta-qqfilename"], uploader.getName(0)); + assert.equal(initiateRequest.requestHeaders["x-amz-acl"], "private"); + assert.ok(initiateRequest.requestHeaders["x-amz-date"]); + assert.equal(initiateRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "Initiate MP request Authorization header invalid"); + initiateRequest.respond(200, null, "123"); - setTimeout(function() { - // upload part 2 request - assert.equal(fileTestHelper.getRequests().length, 3); - uploadPartRequest = fileTestHelper.getRequests()[2]; + setTimeout(function () { + // upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 2); + uploadPartRequest = fileTestHelper.getRequests()[1]; assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=1&uploadId=123"); assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); - assert.equal(uploadPartRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "Upload part 2 request Authorization header is invalid"); - uploadPartRequest.respond(200, {ETag: "etag2"}, null); + assert.equal(uploadPartRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "Upload part 1 request Authorization header is invalid"); + uploadPartRequest.respond(200, {ETag: "etag1"}, null); setTimeout(function() { - // multipart complete request - assert.equal(fileTestHelper.getRequests().length, 4); - multipartCompleteRequest = fileTestHelper.getRequests()[3]; - assert.equal(multipartCompleteRequest.method, "POST"); - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); - assert.equal(multipartCompleteRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "MP complete request Authorization header is invalid"); - assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + // upload part 2 request + assert.equal(fileTestHelper.getRequests().length, 3); + uploadPartRequest = fileTestHelper.getRequests()[2]; + assert.equal(uploadPartRequest.method, "PUT"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=2&uploadId=123"); + assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); + + assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); + + assert.equal(uploadPartRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "Upload part 2 request Authorization header is invalid"); + uploadPartRequest.respond(200, {ETag: "etag2"}, null); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + // multipart complete request + assert.equal(fileTestHelper.getRequests().length, 4); + multipartCompleteRequest = fileTestHelper.getRequests()[3]; + assert.equal(multipartCompleteRequest.method, "POST"); + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + key0 + "?uploadId=123"); + assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); + assert.equal(multipartCompleteRequest.requestHeaders.Authorization.indexOf("AWS " + testAccessKey + ":"), 0, "MP complete request Authorization header is invalid"); + assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + key0 + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + done(); + }, 0); }, 0); }, 0); }, 0); - }, 0); + }); }); }); @@ -972,89 +982,91 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - // failing initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 1); - initiateRequest = fileTestHelper.getRequests()[0]; - assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); - initiateRequest.respond(200, null, ""); - - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + uploader.getKey(0).then(function(key0) { + // failing initiate multipart upload request assert.equal(fileTestHelper.getRequests().length, 1); - uploader.retry(0); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 2); - initiateRequest = fileTestHelper.getRequests()[1]; - assert.equal(initiateRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploads"); - initiateRequest.respond(200, null, "123"); + initiateRequest = fileTestHelper.getRequests()[0]; + assert.equal(initiateRequest.url, testS3Endpoint + "/" + key0 + "?uploads"); + initiateRequest.respond(200, null, ""); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 1); + uploader.retry(0); setTimeout(function() { - // failing upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 3); - uploadPartRequest = fileTestHelper.getRequests()[2]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - uploadPartRequest.respond(404, {ETag: "etag1"}, null); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful initiate multipart upload request + assert.equal(fileTestHelper.getRequests().length, 2); + initiateRequest = fileTestHelper.getRequests()[1]; + assert.equal(initiateRequest.url, testS3Endpoint + "/" + key0 + "?uploads"); + initiateRequest.respond(200, null, "123"); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + // failing upload part 1 request assert.equal(fileTestHelper.getRequests().length, 3); - uploader.retry(0); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful upload part 1 request - assert.equal(fileTestHelper.getRequests().length, 4); - uploadPartRequest = fileTestHelper.getRequests()[3]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=1&uploadId=123"); - uploadPartRequest.respond(200, {ETag: "etag1_a"}, null); + uploadPartRequest = fileTestHelper.getRequests()[2]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=1&uploadId=123"); + uploadPartRequest.respond(404, {ETag: "etag1"}, null); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 3); + uploader.retry(0); setTimeout(function() { - // failing upload part 2 request - assert.equal(fileTestHelper.getRequests().length, 5); - uploadPartRequest = fileTestHelper.getRequests()[4]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - uploadPartRequest.respond(404, {ETag: "etag2"}, null); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful upload part 1 request + assert.equal(fileTestHelper.getRequests().length, 4); + uploadPartRequest = fileTestHelper.getRequests()[3]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=1&uploadId=123"); + uploadPartRequest.respond(200, {ETag: "etag1_a"}, null); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + // failing upload part 2 request assert.equal(fileTestHelper.getRequests().length, 5); - uploader.retry(0); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - - // successful upload part 2 request - assert.equal(fileTestHelper.getRequests().length, 6); - uploadPartRequest = fileTestHelper.getRequests()[5]; - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?partNumber=2&uploadId=123"); - uploadPartRequest.respond(200, {ETag: "etag2_a"}, null); + uploadPartRequest = fileTestHelper.getRequests()[4]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=2&uploadId=123"); + uploadPartRequest.respond(404, {ETag: "etag2"}, null); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 5); + uploader.retry(0); setTimeout(function() { - // failing multipart complete request - assert.equal(fileTestHelper.getRequests().length, 7); - multipartCompleteRequest = fileTestHelper.getRequests()[6]; - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + uploader.getKey(0) + ""); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + + // successful upload part 2 request + assert.equal(fileTestHelper.getRequests().length, 6); + uploadPartRequest = fileTestHelper.getRequests()[5]; + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=2&uploadId=123"); + uploadPartRequest.respond(200, {ETag: "etag2_a"}, null); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + // failing multipart complete request assert.equal(fileTestHelper.getRequests().length, 7); - uploader.retry(0); + multipartCompleteRequest = fileTestHelper.getRequests()[6]; + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + key0 + "?uploadId=123"); + assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); + multipartCompleteRequest.respond(200, null, "" + key0 + ""); + setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_FAILED); + assert.equal(fileTestHelper.getRequests().length, 7); + uploader.retry(0); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOADING); - // successful multipart complete request - assert.equal(fileTestHelper.getRequests().length, 8); - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + uploader.getKey(0) + "?uploadId=123"); - assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + uploader.getKey(0) + ""); + // successful multipart complete request + assert.equal(fileTestHelper.getRequests().length, 8); + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + key0 + "?uploadId=123"); + assert.equal(multipartCompleteRequest.requestBody, "1etag1_a2etag2_a"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + key0 + ""); - setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + }, 0); }, 0); }, 0); }, 0); @@ -1066,7 +1078,7 @@ if (qqtest.canDownloadFileAsBlob) { }, 0); }, 0); }, 0); - }, 0); + }); }); }); }); diff --git a/test/unit/s3/serverless-uploads.js b/test/unit/s3/serverless-uploads.js index d9fa5d608..1caea4e8b 100644 --- a/test/unit/s3/serverless-uploads.js +++ b/test/unit/s3/serverless-uploads.js @@ -47,17 +47,19 @@ describe("S3 serverless upload tests", function() { assert.equal(requestParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME], null); assert.equal(requestParams["x-amz-storage-class"], null); assert.equal(requestParams["x-amz-meta-qqfilename"], "test"); - assert.equal(requestParams.key, uploader.getKey(0)); - assert.equal(requestParams.acl, "private"); - assert.ok(requestParams.file); - - assert.equal(requestParams["x-amz-algorithm"], "AWS4-HMAC-SHA256"); - assert.ok(new RegExp(testAccessKey + "\\/\\d{8}\\/us-east-1\\/s3\\/aws4_request").test(requestParams["x-amz-credential"])); - assert.ok(requestParams["x-amz-date"]); - assert.ok(requestParams["x-amz-signature"]); - assert.ok(requestParams.policy); - - done(); + uploader.getKey(0).then(function(key0) { + assert.equal(requestParams.key, key0); + assert.equal(requestParams.acl, "private"); + assert.ok(requestParams.file); + + assert.equal(requestParams["x-amz-algorithm"], "AWS4-HMAC-SHA256"); + assert.ok(new RegExp(testAccessKey + "\\/\\d{8}\\/us-east-1\\/s3\\/aws4_request").test(requestParams["x-amz-credential"])); + assert.ok(requestParams["x-amz-date"]); + assert.ok(requestParams["x-amz-signature"]); + assert.ok(requestParams.policy); + + done(); + }); }, 0); }); }); @@ -95,15 +97,17 @@ describe("S3 serverless upload tests", function() { assert.equal(requestParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME], null); assert.equal(requestParams["x-amz-storage-class"], null); assert.equal(requestParams["x-amz-meta-qqfilename"], "test"); - assert.equal(requestParams.key, uploader.getKey(0)); - assert.equal(requestParams.AWSAccessKeyId, testAccessKey); - assert.equal(requestParams.acl, "private"); - assert.ok(requestParams.file); + uploader.getKey(0).then(function(key0) { + assert.equal(requestParams.key, key0); + assert.equal(requestParams.AWSAccessKeyId, testAccessKey); + assert.equal(requestParams.acl, "private"); + assert.ok(requestParams.file); - assert.ok(requestParams.signature); - assert.ok(requestParams.policy); + assert.ok(requestParams.signature); + assert.ok(requestParams.policy); - done(); + done(); + }); }, 0); }); }); @@ -171,14 +175,16 @@ describe("S3 serverless upload tests", function() { assert.equal(requestParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME], testSessionToken); assert.equal(requestParams["x-amz-storage-class"], null); assert.equal(requestParams["x-amz-meta-qqfilename"], "test"); - assert.equal(requestParams.key, uploader.getKey(0)); - assert.equal(requestParams.AWSAccessKeyId, testAccessKey); - assert.equal(requestParams.acl, "private"); - assert.ok(requestParams.file); + uploader.getKey(0).then(function (key0) { + assert.equal(requestParams.key, key0); + assert.equal(requestParams.AWSAccessKeyId, testAccessKey); + assert.equal(requestParams.acl, "private"); + assert.ok(requestParams.file); - assert.ok(requestParams.signature); - assert.ok(requestParams.policy); - done(); + assert.ok(requestParams.signature); + assert.ok(requestParams.policy); + done(); + }); }, 0); }); }); @@ -224,15 +230,17 @@ describe("S3 serverless upload tests", function() { assert.equal(requestParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME], testSessionTokenFromCallback); assert.equal(requestParams["x-amz-storage-class"], null); assert.equal(requestParams["x-amz-meta-qqfilename"], "test"); - assert.equal(requestParams.key, uploader.getKey(0)); - assert.equal(requestParams.AWSAccessKeyId, testAccessKeyFromCallback); - assert.equal(requestParams.acl, "private"); - assert.ok(requestParams.file); + uploader.getKey(0).then(function(key0) { + assert.equal(requestParams.key, key0); + assert.equal(requestParams.AWSAccessKeyId, testAccessKeyFromCallback); + assert.equal(requestParams.acl, "private"); + assert.ok(requestParams.file); - assert.ok(requestParams.signature); - assert.ok(requestParams.policy); + assert.ok(requestParams.signature); + assert.ok(requestParams.policy); - done(); + done(); + }); }, 10); }); } diff --git a/test/unit/s3/simple-file-uploads.js b/test/unit/s3/simple-file-uploads.js index d315afbca..d99aca34d 100644 --- a/test/unit/s3/simple-file-uploads.js +++ b/test/unit/s3/simple-file-uploads.js @@ -69,37 +69,39 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(conditions["Content-Type"], "image/jpeg"); assert.equal(conditions.success_action_status, 200); assert.equal(conditions["x-amz-algorithm"], "AWS4-HMAC-SHA256"); - assert.equal(conditions.key, uploader.getKey(0)); - assert.equal(conditions.key, uploader.getUuid(0) + ".jpg"); - assert.equal(conditions["x-amz-credential"], testAccessKey + "/" + now.getUTCFullYear() + ("0" + (now.getUTCMonth() + 1)).slice(-2) + ("0" + now.getUTCDate()).slice(-2) + "/us-east-1/s3/aws4_request"); - policyDate = conditions["x-amz-date"]; - assert.ok(policyDate); - assert.equal(conditions["x-amz-meta-qqfilename"], "test.jpg"); - - signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - - setTimeout(function () { - uploadRequestParams = uploadRequest.requestBody.fields; - - assert.equal(uploadRequest.url, testS3Endpoint); - assert.equal(uploadRequest.method, "POST"); - - assert.equal(uploadRequestParams.key, uploader.getUuid(0) + ".jpg"); - assert.equal(uploadRequestParams["Content-Type"], "image/jpeg"); - assert.equal(uploadRequestParams.success_action_status, 200); - assert.equal(uploadRequestParams.acl, "private"); - assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); - assert.equal(uploadRequestParams["x-amz-algorithm"], "AWS4-HMAC-SHA256"); - assert.equal(uploadRequestParams["x-amz-credential"], testAccessKey + "/" + now.getUTCFullYear() + ("0" + (now.getUTCMonth() + 1)).slice(-2) + ("0" + now.getUTCDate()).slice(-2) + "/us-east-1/s3/aws4_request"); - assert.equal(uploadRequestParams["x-amz-date"], policyDate); - - assert.ok(uploadRequestParams.file); - - assert.equal(uploadRequestParams["x-amz-signature"], "thesignature"); - assert.equal(uploadRequestParams.policy, "thepolicy"); - - done(); - }, 0); + uploader.getKey(0).then(function(key0) { + assert.equal(conditions.key, key0); + assert.equal(conditions.key, uploader.getUuid(0) + ".jpg"); + assert.equal(conditions["x-amz-credential"], testAccessKey + "/" + now.getUTCFullYear() + ("0" + (now.getUTCMonth() + 1)).slice(-2) + ("0" + now.getUTCDate()).slice(-2) + "/us-east-1/s3/aws4_request"); + policyDate = conditions["x-amz-date"]; + assert.ok(policyDate); + assert.equal(conditions["x-amz-meta-qqfilename"], "test.jpg"); + + signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); + + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; + + assert.equal(uploadRequest.url, testS3Endpoint); + assert.equal(uploadRequest.method, "POST"); + + assert.equal(uploadRequestParams.key, uploader.getUuid(0) + ".jpg"); + assert.equal(uploadRequestParams["Content-Type"], "image/jpeg"); + assert.equal(uploadRequestParams.success_action_status, 200); + assert.equal(uploadRequestParams.acl, "private"); + assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); + assert.equal(uploadRequestParams["x-amz-algorithm"], "AWS4-HMAC-SHA256"); + assert.equal(uploadRequestParams["x-amz-credential"], testAccessKey + "/" + now.getUTCFullYear() + ("0" + (now.getUTCMonth() + 1)).slice(-2) + ("0" + now.getUTCDate()).slice(-2) + "/us-east-1/s3/aws4_request"); + assert.equal(uploadRequestParams["x-amz-date"], policyDate); + + assert.ok(uploadRequestParams.file); + + assert.equal(uploadRequestParams["x-amz-signature"], "thesignature"); + assert.equal(uploadRequestParams.policy, "thepolicy"); + + done(); + }, 0); + }); }); }); @@ -205,32 +207,34 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(conditions.acl, "private"); assert.equal(conditions.bucket, testBucketName); assert.equal(conditions.success_action_status, 200); - assert.equal(conditions.key, uploader.getKey(0)); - assert.equal(conditions.key, uploader.getUuid(0) + ".jpg"); - assert.equal(conditions["x-amz-meta-qqfilename"], "test.jpg"); + uploader.getKey(0).then(function(key0) { + assert.equal(conditions.key, key0); + assert.equal(conditions.key, uploader.getUuid(0) + ".jpg"); + assert.equal(conditions["x-amz-meta-qqfilename"], "test.jpg"); - signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); + signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - setTimeout(function () { - uploadRequestParams = uploadRequest.requestBody.fields; + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequest.url, testS3Endpoint); - assert.equal(uploadRequest.method, "POST"); + assert.equal(uploadRequest.url, testS3Endpoint); + assert.equal(uploadRequest.method, "POST"); - assert.equal(uploadRequestParams["Content-Type"], "image/jpeg"); - assert.equal(uploadRequestParams.success_action_status, 200); - assert.equal(uploadRequestParams["x-amz-storage-class"], null); - assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); - assert.equal(uploadRequestParams.key, uploader.getUuid(0) + ".jpg"); - assert.equal(uploadRequestParams.AWSAccessKeyId, testAccessKey); - assert.equal(uploadRequestParams.acl, "private"); - assert.ok(uploadRequestParams.file); + assert.equal(uploadRequestParams["Content-Type"], "image/jpeg"); + assert.equal(uploadRequestParams.success_action_status, 200); + assert.equal(uploadRequestParams["x-amz-storage-class"], null); + assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); + assert.equal(uploadRequestParams.key, uploader.getUuid(0) + ".jpg"); + assert.equal(uploadRequestParams.AWSAccessKeyId, testAccessKey); + assert.equal(uploadRequestParams.acl, "private"); + assert.ok(uploadRequestParams.file); - assert.equal(uploadRequestParams.signature, "thesignature"); - assert.equal(uploadRequestParams.policy, "thepolicy"); + assert.equal(uploadRequestParams.signature, "thesignature"); + assert.equal(uploadRequestParams.policy, "thepolicy"); - done(); - }, 0); + done(); + }, 0); + }); }); }); @@ -368,18 +372,20 @@ if (qqtest.canDownloadFileAsBlob) { var uploadRequestParams; assert.equal(conditions.key, "test.jpg"); - assert.equal(uploader.getKey(0), "test.jpg"); - assert.equal(conditions["x-amz-meta-qqfilename"], "test.jpg"); + uploader.getKey(0).then(function(key0) { + assert.equal(key0, "test.jpg"); + assert.equal(conditions["x-amz-meta-qqfilename"], "test.jpg"); - signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); + signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - setTimeout(function () { - uploadRequestParams = uploadRequest.requestBody.fields; + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); + assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); - done(); - }, 0); + done(); + }, 0); + }); }); }); @@ -400,16 +406,18 @@ if (qqtest.canDownloadFileAsBlob) { var uploadRequestParams; assert.equal(conditions.key, customKeyPrefix + "test.jpg"); - assert.equal(uploader.getKey(0), customKeyPrefix + "test.jpg"); - assert.equal(conditions["x-amz-meta-qqfilename"], "test.jpg"); - signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); + uploader.getKey(0).then(function(key0) { + assert.equal(key0, customKeyPrefix + "test.jpg"); + assert.equal(conditions["x-amz-meta-qqfilename"], "test.jpg"); + signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - setTimeout(function () { - uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; + assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); - done(); - }, 0); + done(); + }, 0); + }); }); }); @@ -430,16 +438,18 @@ if (qqtest.canDownloadFileAsBlob) { var uploadRequestParams; assert.equal(conditions.key, customKeyPrefix + "test.jpg"); - assert.equal(uploader.getKey(0), customKeyPrefix + "test.jpg"); - assert.equal(conditions["x-amz-meta-qqfilename"], "test.jpg"); - signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); + uploader.getKey(0).then(function(key0) { + assert.equal(key0, customKeyPrefix + "test.jpg"); + assert.equal(conditions["x-amz-meta-qqfilename"], "test.jpg"); + signatureRequest.respond(200, null, JSON.stringify({policy: "thepolicy", signature: "thesignature"})); - setTimeout(function () { - uploadRequestParams = uploadRequest.requestBody.fields; - assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); + setTimeout(function () { + uploadRequestParams = uploadRequest.requestBody.fields; + assert.equal(uploadRequestParams["x-amz-meta-qqfilename"], "test.jpg"); - done(); - }, 0); + done(); + }, 0); + }); }); } @@ -693,16 +703,18 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(uploadSuccessRequest.requestHeaders["test-header-name"], uploadSuccessHeaders["test-header-name"]); assert.equal(uploadSuccessRequestParsedBody["test-param-name"], uploadSuccessParams["test-param-name"]); assert.equal(uploadSuccessRequestParsedBody.foo, "bar"); - assert.equal(uploadSuccessRequestParsedBody.key, uploader.getKey(0)); - assert.equal(uploadSuccessRequestParsedBody.uuid, uploader.getUuid(0)); - assert.equal(uploadSuccessRequestParsedBody.name, uploader.getName(0)); - assert.equal(uploadSuccessRequestParsedBody.bucket, testBucketName); - assert.equal(uploadSuccessRequestParsedBody.etag, "123"); + uploader.getKey(0).then(function(key0) { + assert.equal(uploadSuccessRequestParsedBody.key, key0); + assert.equal(uploadSuccessRequestParsedBody.uuid, uploader.getUuid(0)); + assert.equal(uploadSuccessRequestParsedBody.name, uploader.getName(0)); + assert.equal(uploadSuccessRequestParsedBody.bucket, testBucketName); + assert.equal(uploadSuccessRequestParsedBody.etag, "123"); - uploadSuccessRequest.respond(200, null, null); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + uploadSuccessRequest.respond(200, null, null); + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + done(); + }); }, 0); }, 0); }); From 3c3ee2f2d289d2dbd5a2b82c119bf40b2de2a559 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 12:25:11 +1100 Subject: [PATCH 45/73] refactor: upload() to return Promise --- client/js/uploader.basic.api.js | 2 +- test/unit/chunked-uploads.js | 20 ++- test/unit/delete-file.js | 8 +- test/unit/file-upload-params-and-headers.js | 44 +++-- test/unit/form-support.js | 20 ++- test/unit/on-all-complete.js | 18 +- test/unit/set-status.js | 52 +++--- test/unit/simple-file-uploads.js | 183 ++++++++++++-------- 8 files changed, 210 insertions(+), 137 deletions(-) diff --git a/client/js/uploader.basic.api.js b/client/js/uploader.basic.api.js index 52ad8bac8..3f2763116 100644 --- a/client/js/uploader.basic.api.js +++ b/client/js/uploader.basic.api.js @@ -807,7 +807,7 @@ return onUploadResult; } - return new qq.Promise().success(); + return Promise.resolve(); }, onUploadChunk: function(id, name, chunkData) { self._onUploadChunk(id, chunkData); diff --git a/test/unit/chunked-uploads.js b/test/unit/chunked-uploads.js index 528d55ed6..0226a1f6d 100644 --- a/test/unit/chunked-uploads.js +++ b/test/unit/chunked-uploads.js @@ -495,7 +495,9 @@ if (qqtest.canDownloadFileAsBlob) { qqtest.downloadFileAsBlob("up.jpg", "image/jpeg").then(function (blob) { fileTestHelper.mockXhr(); uploader.addFiles({name: "test", blob: blob}); - fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + setTimeout(function() { + fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + }, 0); }); } @@ -724,14 +726,16 @@ if (qqtest.canDownloadFileAsBlob) { fileTestHelper.mockXhr(); uploader.addFiles({name: "test", blob: blob}); - if (sinonResponse) { - var request = fileTestHelper.getRequests()[0]; + setTimeout(function() { + if (sinonResponse) { + var request = fileTestHelper.getRequests()[0]; - request.respond.apply(request, sinonResponse); - } - else { - fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); - } + request.respond.apply(request, sinonResponse); + } + else { + fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + } + }, 0); }); } diff --git a/test/unit/delete-file.js b/test/unit/delete-file.js index 381f157de..314b1031d 100644 --- a/test/unit/delete-file.js +++ b/test/unit/delete-file.js @@ -165,9 +165,11 @@ if (qqtest.canDownloadFileAsBlob) { uploader.addFiles({name: "test", blob: blob}); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - request = fileTestHelper.getRequests()[0]; - request.respond(200, null, JSON.stringify({success: true})); + setTimeout(function () { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + request = fileTestHelper.getRequests()[0]; + request.respond(200, null, JSON.stringify({success: true})); + }, 0); }); } diff --git a/test/unit/file-upload-params-and-headers.js b/test/unit/file-upload-params-and-headers.js index 7462e3d0e..4ca0e3669 100644 --- a/test/unit/file-upload-params-and-headers.js +++ b/test/unit/file-upload-params-and-headers.js @@ -57,18 +57,22 @@ if (qqtest.canDownloadFileAsBlob) { theparams = overrideParams || params; uploader.addFiles({name: "test", blob: blob}); - uploader.uploadStoredFiles(); - - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - request = fileTestHelper.getRequests()[0]; - requestParams = request.requestBody.fields; - purlUrl = purl(request.url); - - assert.equal(mpe ? requestParams.foo : purlUrl.param("foo"), theparams.foo, "'foo' param value incorrect"); - assert.equal(mpe ? requestParams.one : purlUrl.param("one"), theparams.one, "'one' param value incorrect"); - assert.equal(mpe ? requestParams.thefunc : purlUrl.param("thefunc"), theparams.thefunc(), "'thefunc' param value incorrect"); - - fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + setTimeout(function() { + uploader.uploadStoredFiles(); + + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + request = fileTestHelper.getRequests()[0]; + requestParams = request.requestBody.fields; + purlUrl = purl(request.url); + + assert.equal(mpe ? requestParams.foo : purlUrl.param("foo"), theparams.foo, "'foo' param value incorrect"); + assert.equal(mpe ? requestParams.one : purlUrl.param("one"), theparams.one, "'one' param value incorrect"); + assert.equal(mpe ? requestParams.thefunc : purlUrl.param("thefunc"), theparams.thefunc(), "'thefunc' param value incorrect"); + + fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + }, 0); + }, 0); }); } @@ -82,15 +86,19 @@ if (qqtest.canDownloadFileAsBlob) { var request; uploader.addFiles({name: "test", blob: blob}); - uploader.uploadStoredFiles(); + setTimeout(function() { + uploader.uploadStoredFiles(); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - request = fileTestHelper.getRequests()[0]; + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + request = fileTestHelper.getRequests()[0]; - assert.equal(request.requestHeaders.one, headers.one, "Wrong 'one' header"); - assert.equal(request.requestHeaders.two, headers.two, "Wrong 'two' header"); + assert.equal(request.requestHeaders.one, headers.one, "Wrong 'one' header"); + assert.equal(request.requestHeaders.two, headers.two, "Wrong 'two' header"); - fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + }, 0); + }, 0); }); } diff --git a/test/unit/form-support.js b/test/unit/form-support.js index 3023b15a5..f5b9f52b8 100644 --- a/test/unit/form-support.js +++ b/test/unit/form-support.js @@ -176,14 +176,18 @@ describe("test form support", function() { uploader.addFiles(blob); - assert.equal(fileTestHelper.getRequests().length, 0, "Wrong # of requests"); - uploader.uploadStoredFiles(); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - - request = fileTestHelper.getRequests()[0]; - assert.equal(request.url, endopint); - requestParams = request.requestBody.fields; - assert.equal(requestParams.text_test, "test"); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 0, "Wrong # of requests"); + uploader.uploadStoredFiles(); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + + request = fileTestHelper.getRequests()[0]; + assert.equal(request.url, endopint); + requestParams = request.requestBody.fields; + assert.equal(requestParams.text_test, "test"); + }, 0); + }, 0); }); }; diff --git a/test/unit/on-all-complete.js b/test/unit/on-all-complete.js index 11069eb86..0fe3e1341 100644 --- a/test/unit/on-all-complete.js +++ b/test/unit/on-all-complete.js @@ -40,14 +40,18 @@ if (qqtest.canDownloadFileAsBlob) { qqtest.downloadFileAsBlob("up.jpg", "image/jpeg").then(function (blob) { fileTestHelper.mockXhr(); uploader.addFiles(blob); - !autoUpload && uploader.uploadStoredFiles(); + setTimeout(function () { + !autoUpload && uploader.uploadStoredFiles(); - if (success) { - fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); - } - else { - fileTestHelper.getRequests()[0].respond(400, null, null); - } + setTimeout(function () { + if (success) { + fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + } + else { + fileTestHelper.getRequests()[0].respond(400, null, null); + } + }, 0); + }, 0); }); }, runMultipleUploadTest = function(success, done) { diff --git a/test/unit/set-status.js b/test/unit/set-status.js index 83cb78338..2f97ae424 100644 --- a/test/unit/set-status.js +++ b/test/unit/set-status.js @@ -62,21 +62,25 @@ describe("set-status.js", function() { fileTestHelper.mockXhr(); uploader.addFiles({name: "test", blob: blob}); - uploader.uploadStoredFiles(); - fileTestHelper.getRequests()[0].respond(201, null, JSON.stringify({success: true})); - setTimeout(function() { - var uploaderFiles = uploader.getUploads(); - var file = uploaderFiles[0]; + uploader.uploadStoredFiles(); + setTimeout(function() { + fileTestHelper.getRequests()[0].respond(201, null, JSON.stringify({success: true})); + + setTimeout(function() { + var uploaderFiles = uploader.getUploads(); + var file = uploaderFiles[0]; - uploader.setStatus(file.id, qq.status.DELETED); + uploader.setStatus(file.id, qq.status.DELETED); - uploaderFiles = uploader.getUploads(); - file = uploaderFiles[0]; + uploaderFiles = uploader.getUploads(); + file = uploaderFiles[0]; - assert.equal(0, uploader.getNetUploads()); - assert.equal(qq.status.DELETED, file.status); - done(); + assert.equal(0, uploader.getNetUploads()); + assert.equal(qq.status.DELETED, file.status); + done(); + }, 0); + }, 0); }, 0); }); @@ -94,21 +98,25 @@ describe("set-status.js", function() { fileTestHelper.mockXhr(); uploader.addFiles({name: "test", blob: blob}); - uploader.uploadStoredFiles(); - fileTestHelper.getRequests()[0].respond(201, null, JSON.stringify({success: true})); - setTimeout(function() { - var uploaderFiles = uploader.getUploads(); - var file = uploaderFiles[0]; + uploader.uploadStoredFiles(); + setTimeout(function() { + fileTestHelper.getRequests()[0].respond(201, null, JSON.stringify({success: true})); + + setTimeout(function() { + var uploaderFiles = uploader.getUploads(); + var file = uploaderFiles[0]; - uploader.setStatus(file.id, qq.status.DELETE_FAILED); + uploader.setStatus(file.id, qq.status.DELETE_FAILED); - uploaderFiles = uploader.getUploads(); - file = uploaderFiles[0]; + uploaderFiles = uploader.getUploads(); + file = uploaderFiles[0]; - assert.equal(1, uploader.getNetUploads()); - assert.equal(qq.status.DELETE_FAILED, file.status); - done(); + assert.equal(1, uploader.getNetUploads()); + assert.equal(qq.status.DELETE_FAILED, file.status); + done(); + }, 0); + }, 0); }, 0); }); diff --git a/test/unit/simple-file-uploads.js b/test/unit/simple-file-uploads.js index 2e731c067..f80773642 100644 --- a/test/unit/simple-file-uploads.js +++ b/test/unit/simple-file-uploads.js @@ -55,16 +55,20 @@ if (qqtest.canDownloadFileAsBlob) { requestParams; uploader.addFiles({name: "test", blob: blob}); - uploader.uploadStoredFiles(); + setTimeout(function() { + uploader.uploadStoredFiles(); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - request = fileTestHelper.getRequests()[0]; + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + request = fileTestHelper.getRequests()[0]; - assert.equal(request.method, "PUT", "Wrong request method"); + assert.equal(request.method, "PUT", "Wrong request method"); - fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); - done(); + done(); + }, 0); + }, 0); }); }); @@ -79,11 +83,15 @@ if (qqtest.canDownloadFileAsBlob) { var request; uploader.addFiles({name: "test", blob: blob}); - uploader.uploadStoredFiles(); + setTimeout(function() { + uploader.uploadStoredFiles(); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - fileTestHelper.getRequests()[0].respond(201, null, JSON.stringify({success: true})); + fileTestHelper.getRequests()[0].respond(201, null, JSON.stringify({success: true})); + }, 0); + }, 0); }); }); @@ -98,11 +106,15 @@ if (qqtest.canDownloadFileAsBlob) { var request; uploader.addFiles({name: "test", blob: blob}); - uploader.uploadStoredFiles(); + setTimeout(function() { + uploader.uploadStoredFiles(); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - fileTestHelper.getRequests()[0].respond(202, null, JSON.stringify({success: true})); + fileTestHelper.getRequests()[0].respond(202, null, JSON.stringify({success: true})); + }, 0); + }, 0); }); }); @@ -117,11 +129,15 @@ if (qqtest.canDownloadFileAsBlob) { var request; uploader.addFiles({name: "test", blob: blob}); - uploader.uploadStoredFiles(); + setTimeout(function() { + uploader.uploadStoredFiles(); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - fileTestHelper.getRequests()[0].respond(203, null, JSON.stringify({success: true})); + fileTestHelper.getRequests()[0].respond(203, null, JSON.stringify({success: true})); + }, 0); + }, 0); }); }); @@ -136,11 +152,15 @@ if (qqtest.canDownloadFileAsBlob) { var request; uploader.addFiles({name: "test", blob: blob}); - uploader.uploadStoredFiles(); + setTimeout(function() { + uploader.uploadStoredFiles(); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - fileTestHelper.getRequests()[0].respond(204, null, JSON.stringify({success: true})); + fileTestHelper.getRequests()[0].respond(204, null, JSON.stringify({success: true})); + }, 0); + }, 0); }); }); @@ -155,11 +175,15 @@ if (qqtest.canDownloadFileAsBlob) { var request; uploader.addFiles({name: "test", blob: blob}); - uploader.uploadStoredFiles(); + setTimeout(function() { + uploader.uploadStoredFiles(); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - fileTestHelper.getRequests()[0].respond(204, null, JSON.stringify({success: true})); + fileTestHelper.getRequests()[0].respond(204, null, JSON.stringify({success: true})); + }, 0); + }, 0); }); }); @@ -180,20 +204,24 @@ if (qqtest.canDownloadFileAsBlob) { }; uploader.addFiles(fakeFileInput); - uploader.uploadStoredFiles(); + setTimeout(function() { + uploader.uploadStoredFiles(); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - request = fileTestHelper.getRequests()[0]; - requestParams = request.requestBody.fields; - - assert.equal(requestParams.qquuid, uploader.getUuid(0), "Wrong UUID param sent with request"); - assert.equal(requestParams.qqfilename, uploader.getName(0), "Wrong filename param sent with request"); - assert.equal(requestParams.qqtotalfilesize, uploader.getSize(0), "Wrong file size param sent with request"); - assert.ok(qq.isBlob(requestParams.qqfile), "File is incorrect"); - assert.equal(request.method, "POST", "Wrong request method"); - assert.equal(request.url, testUploadEndpoint, "Wrong request url"); - - fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + request = fileTestHelper.getRequests()[0]; + requestParams = request.requestBody.fields; + + assert.equal(requestParams.qquuid, uploader.getUuid(0), "Wrong UUID param sent with request"); + assert.equal(requestParams.qqfilename, uploader.getName(0), "Wrong filename param sent with request"); + assert.equal(requestParams.qqtotalfilesize, uploader.getSize(0), "Wrong file size param sent with request"); + assert.ok(qq.isBlob(requestParams.qqfile), "File is incorrect"); + assert.equal(request.method, "POST", "Wrong request method"); + assert.equal(request.url, testUploadEndpoint, "Wrong request url"); + + fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + }, 0); + }, 0); }); }); @@ -209,20 +237,24 @@ if (qqtest.canDownloadFileAsBlob) { requestParams; uploader.addFiles({name: "test", blob: blob}); - uploader.uploadStoredFiles(); - - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - request = fileTestHelper.getRequests()[0]; - requestParams = request.requestBody.fields; - - assert.equal(requestParams.qquuid, uploader.getUuid(0), "Wrong UUID param sent with request"); - assert.equal(requestParams.qqfilename, uploader.getName(0), "Wrong filename param sent with request"); - assert.equal(requestParams.qqtotalfilesize, uploader.getSize(0), "Wrong file size param sent with request"); - assert.ok(qq.isBlob(requestParams.qqfile), "File is incorrect"); - assert.equal(request.method, "POST", "Wrong request method"); - assert.equal(request.url, testUploadEndpoint, "Wrong request url"); + setTimeout(function() { + uploader.uploadStoredFiles(); - fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + request = fileTestHelper.getRequests()[0]; + requestParams = request.requestBody.fields; + + assert.equal(requestParams.qquuid, uploader.getUuid(0), "Wrong UUID param sent with request"); + assert.equal(requestParams.qqfilename, uploader.getName(0), "Wrong filename param sent with request"); + assert.equal(requestParams.qqtotalfilesize, uploader.getSize(0), "Wrong file size param sent with request"); + assert.ok(qq.isBlob(requestParams.qqfile), "File is incorrect"); + assert.equal(request.method, "POST", "Wrong request method"); + assert.equal(request.url, testUploadEndpoint, "Wrong request url"); + + fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + }, 0); + }, 0); }); }); @@ -238,17 +270,19 @@ if (qqtest.canDownloadFileAsBlob) { uploader.addFiles({name: "test", blob: blob}); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - request = fileTestHelper.getRequests()[0]; - purlUrl = purl(request.url); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + request = fileTestHelper.getRequests()[0]; + purlUrl = purl(request.url); - assert.equal(request.requestHeaders["X-Mime-Type"], "image/jpeg", "Wrong X-Mime-Type"); - assert.equal(purlUrl.param("qquuid"), uploader.getUuid(0), "Wrong UUID param sent with request"); - assert.equal(purlUrl.param("qqfilename"), uploader.getName(0), "Wrong filename param sent with request"); - assert.equal(request.method, "POST", "Wrong request method"); - assert.equal(purlUrl.attr("path"), testUploadEndpoint, "Wrong request url"); + assert.equal(request.requestHeaders["X-Mime-Type"], "image/jpeg", "Wrong X-Mime-Type"); + assert.equal(purlUrl.param("qquuid"), uploader.getUuid(0), "Wrong UUID param sent with request"); + assert.equal(purlUrl.param("qqfilename"), uploader.getName(0), "Wrong filename param sent with request"); + assert.equal(request.method, "POST", "Wrong request method"); + assert.equal(purlUrl.attr("path"), testUploadEndpoint, "Wrong request url"); - fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + }, 0); }); }); @@ -275,15 +309,17 @@ if (qqtest.canDownloadFileAsBlob) { uploader.addFiles(blob); - assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); - request = fileTestHelper.getRequests()[0]; - requestParams = request.requestBody.fields; - - assert.equal(requestParams[uuidParamName], uploader.getUuid(0), "Wrong UUID param sent with request"); - assert.equal(requestParams[filenameParamName], uploader.getName(0), "Wrong filename param sent with request"); - assert.equal(requestParams[totalFileSizeParamName], uploader.getSize(0), "Wrong file size param sent with request"); - assert.ok(qq.isBlob(requestParams[inputParamName]), "File is incorrect"); - done(); + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 1, "Wrong # of requests"); + request = fileTestHelper.getRequests()[0]; + requestParams = request.requestBody.fields; + + assert.equal(requestParams[uuidParamName], uploader.getUuid(0), "Wrong UUID param sent with request"); + assert.equal(requestParams[filenameParamName], uploader.getName(0), "Wrong filename param sent with request"); + assert.equal(requestParams[totalFileSizeParamName], uploader.getSize(0), "Wrong file size param sent with request"); + assert.ok(qq.isBlob(requestParams[inputParamName]), "File is incorrect"); + done(); + }, 0); }); }); @@ -322,7 +358,9 @@ if (qqtest.canDownloadFileAsBlob) { uploader.addFiles(blob); - fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true, newUuid: newUuid})); + setTimeout(function() { + fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true, newUuid: newUuid})); + }, 0); }); }); @@ -414,7 +452,9 @@ if (qqtest.canDownloadFileAsBlob) { fileTestHelper.mockXhr(); uploader.addFiles(blob); - fileTestHelper.getRequests()[0].respond(500, null, JSON.stringify({success: true})); + setTimeout(function() { + fileTestHelper.getRequests()[0].respond(500, null, JSON.stringify({success: true})); + }, 0); }); }); @@ -498,9 +538,12 @@ if (qqtest.canDownloadFileAsBlob) { }); uploader.addFiles({name: "test", blob: blob}); - uploader.uploadStoredFiles(); - - fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + setTimeout(function() { + uploader.uploadStoredFiles(); + setTimeout(function() { + fileTestHelper.getRequests()[0].respond(200, null, JSON.stringify({success: true})); + }, 0); + }, 0); }); }); From 8e347bb4c45471d5a36cda4ad1a440e8471ed0bd Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 12:37:21 +1100 Subject: [PATCH 46/73] refactor: handleFileItems() to return Promise --- client/js/session.js | 69 ++++++++++++++++++------------ test/unit/delete-file.js | 92 ++++++++++++++++------------------------ 2 files changed, 79 insertions(+), 82 deletions(-) diff --git a/client/js/session.js b/client/js/session.js index 50f718563..35cc1cabf 100644 --- a/client/js/session.js +++ b/client/js/session.js @@ -26,38 +26,48 @@ qq.Session = function(spec) { options.log("Session response is not an array.", "error"); } - function handleFileItems(fileItems, success, xhrOrXdr, promise) { - var someItemsIgnored = false; + function handleFileItems(fileItems, success, xhrOrXdr) { + return new Promise(function(resolve, reject) { + var someItemsIgnored = false, + error; - success = success && isJsonResponseValid(fileItems); + success = success && isJsonResponseValid(fileItems); - if (success) { - qq.each(fileItems, function(idx, fileItem) { - /* jshint eqnull:true */ - if (fileItem.uuid == null) { - someItemsIgnored = true; - options.log(qq.format("Session response item {} did not include a valid UUID - ignoring.", idx), "error"); - } - else if (fileItem.name == null) { - someItemsIgnored = true; - options.log(qq.format("Session response item {} did not include a valid name - ignoring.", idx), "error"); - } - else { - try { - options.addFileRecord(fileItem); - return true; + if (success) { + qq.each(fileItems, function(idx, fileItem) { + /* jshint eqnull:true */ + if (fileItem.uuid == null) { + someItemsIgnored = true; + options.log(qq.format("Session response item {} did not include a valid UUID - ignoring.", idx), "error"); } - catch (err) { + else if (fileItem.name == null) { someItemsIgnored = true; - options.log(err.message, "error"); + options.log(qq.format("Session response item {} did not include a valid name - ignoring.", idx), "error"); + } + else { + try { + options.addFileRecord(fileItem); + return true; + } + catch (err) { + someItemsIgnored = true; + options.log(err.message, "error"); + } } - } - return false; - }); - } + return false; + }); + } - promise[success && !someItemsIgnored ? "success" : "failure"](fileItems, xhrOrXdr); + if (success && !someItemsIgnored) { + resolve({fileItems: fileItems, xhrOrXdr: xhrOrXdr}); + } else { + error = new Error("Unable to handle file items"); + error.fileItems = fileItems; + error.xhrOrXdr = xhrOrXdr; + reject(error); + } + }); } // Initiate a call to the server that will be used to populate the initial file list. @@ -66,7 +76,14 @@ qq.Session = function(spec) { /*jshint indent:false */ var refreshEffort = new qq.Promise(), refreshCompleteCallback = function(response, success, xhrOrXdr) { - handleFileItems(response, success, xhrOrXdr, refreshEffort); + handleFileItems(response, success, xhrOrXdr, refreshEffort).then( + function(info) { + refreshEffort.success(info.fileItems, info.xhrOrXdr); + }, + function (error) { + refreshEffort.failure(error.fileItems, error.xhrOrXdr); + } + ); }, requesterOptions = qq.extend({}, options), requester = new qq.SessionAjaxRequester( diff --git a/test/unit/delete-file.js b/test/unit/delete-file.js index 314b1031d..442a8133a 100644 --- a/test/unit/delete-file.js +++ b/test/unit/delete-file.js @@ -19,32 +19,9 @@ if (qqtest.canDownloadFileAsBlob) { }; function testDeleteFile(done, expectedMethod, deleteEnabled, successful, reject, expectedParams, setParamsViaOptions, expectedHeaders, setHeadersViaOptions) { - var expectedAssertions = 0; - expectedParams = expectedParams || {}; expectedHeaders = expectedHeaders || {}; - if (!deleteEnabled) { - expectedAssertions = 2; - } - else if (reject) { - expectedAssertions = 3; - } - else { - if (expectedMethod === "POST") { - expectedAssertions = 12 + Object.keys(expectedParams).length; - } - else { - expectedAssertions = 10 + Object.keys(expectedParams).length; - } - } - - if (Object.keys(expectedHeaders).length) { - expectedAssertions += 2; - } - - assert.expect(expectedAssertions, done); - var uploader = new qq.FineUploaderBasic({ request: { endpoint: testUploadEndpoint @@ -75,47 +52,50 @@ if (qqtest.canDownloadFileAsBlob) { uploader.deleteFile(id); - deleteRequest = fileTestHelper.getRequests()[1]; + setTimeout(function() { + deleteRequest = fileTestHelper.getRequests()[1]; - if (deleteEnabled && !reject) { - deleteRequestPurl = purl(deleteRequest.url); + if (deleteEnabled && !reject) { + deleteRequestPurl = purl(deleteRequest.url); - assert.equal(fileTestHelper.getRequests().length, 2, "Wrong # of requests"); - assert.equal(deleteRequest.method, expectedMethod, "Wrong method for delete request"); + assert.equal(fileTestHelper.getRequests().length, 2, "Wrong # of requests"); + assert.equal(deleteRequest.method, expectedMethod, "Wrong method for delete request"); - if (expectedMethod === "DELETE") { - assert.equal(deleteRequestPurl.attr("path"), testDeleteEndpoint + "/" + uuid, "Wrong endpoint for delete request"); + if (expectedMethod === "DELETE") { + assert.equal(deleteRequestPurl.attr("path"), testDeleteEndpoint + "/" + uuid, "Wrong endpoint for delete request"); - if (Object.keys(expectedParams).length) { - assert.equal(deleteRequestPurl.param("foo"), expectedParams.foo, "Wrong 'foo' parameter"); - assert.equal(deleteRequestPurl.param("one"), expectedParams.one, "Wrong 'one' parameter"); - assert.equal(deleteRequestPurl.param("thefunc"), expectedParams.thefunc(), "Wrong 'thefunc' parameter"); + if (Object.keys(expectedParams).length) { + assert.equal(deleteRequestPurl.param("foo"), expectedParams.foo, "Wrong 'foo' parameter"); + assert.equal(deleteRequestPurl.param("one"), expectedParams.one, "Wrong 'one' parameter"); + assert.equal(deleteRequestPurl.param("thefunc"), expectedParams.thefunc(), "Wrong 'thefunc' parameter"); + } } - } - else { - deleteRequestBodyPurl = purl("?" + deleteRequest.requestBody); - assert.equal(deleteRequestPurl.attr("path"), testDeleteEndpoint, "Wrong endpoint for delete request"); - assert.equal(deleteRequestBodyPurl.param("_method"), "DELETE", "Wrong _method param"); - assert.equal(deleteRequestBodyPurl.param("qquuid"), uuid, "Wrong qquuid param"); - - if (Object.keys(expectedParams).length) { - assert.equal(deleteRequestBodyPurl.param("foo"), expectedParams.foo, "Wrong 'foo' parameter"); - assert.equal(deleteRequestBodyPurl.param("one"), expectedParams.one, "Wrong 'one' parameter"); - assert.equal(deleteRequestBodyPurl.param("thefunc"), expectedParams.thefunc(), "Wrong 'thefunc' parameter"); + else { + deleteRequestBodyPurl = purl("?" + deleteRequest.requestBody); + assert.equal(deleteRequestPurl.attr("path"), testDeleteEndpoint, "Wrong endpoint for delete request"); + assert.equal(deleteRequestBodyPurl.param("_method"), "DELETE", "Wrong _method param"); + assert.equal(deleteRequestBodyPurl.param("qquuid"), uuid, "Wrong qquuid param"); + + if (Object.keys(expectedParams).length) { + assert.equal(deleteRequestBodyPurl.param("foo"), expectedParams.foo, "Wrong 'foo' parameter"); + assert.equal(deleteRequestBodyPurl.param("one"), expectedParams.one, "Wrong 'one' parameter"); + assert.equal(deleteRequestBodyPurl.param("thefunc"), expectedParams.thefunc(), "Wrong 'thefunc' parameter"); + } } - } - if (Object.keys(expectedHeaders).length) { - assert.equal(deleteRequest.requestHeaders.one, expectedHeaders.one, "Wrong 'one' header"); - assert.equal(deleteRequest.requestHeaders.two, expectedHeaders.two, "Wrong 'two' header"); - } + if (Object.keys(expectedHeaders).length) { + assert.equal(deleteRequest.requestHeaders.one, expectedHeaders.one, "Wrong 'one' header"); + assert.equal(deleteRequest.requestHeaders.two, expectedHeaders.two, "Wrong 'two' header"); + } - deleteRequest.respond(successful ? 200 : 500, null, null); - } - else { - /* jshint eqnull:true */ - assert.ok(deleteRequest == null, "delete request may have been sent"); - } + deleteRequest.respond(successful ? 200 : 500, null, null); + } + else { + /* jshint eqnull:true */ + assert.ok(deleteRequest == null, "delete request may have been sent"); + } + done(); + }, 0); }, onSubmitDelete: function(id) { assert.equal(id, 0, "Wrong ID passed to onSubmitDelete"); From fb613676b7a3b9323c86e3c2174942de04a26243 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 12:44:21 +1100 Subject: [PATCH 47/73] refactor: qq.Session.refresh to return Promise --- client/js/session.js | 28 ++++++++++------------------ client/js/uploader.basic.api.js | 10 ++++------ 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/client/js/session.js b/client/js/session.js index 35cc1cabf..04d9e3c72 100644 --- a/client/js/session.js +++ b/client/js/session.js @@ -71,27 +71,19 @@ qq.Session = function(spec) { } // Initiate a call to the server that will be used to populate the initial file list. - // Returns a `qq.Promise`. + // Returns a `Promise`. this.refresh = function() { /*jshint indent:false */ - var refreshEffort = new qq.Promise(), - refreshCompleteCallback = function(response, success, xhrOrXdr) { - handleFileItems(response, success, xhrOrXdr, refreshEffort).then( - function(info) { - refreshEffort.success(info.fileItems, info.xhrOrXdr); - }, - function (error) { - refreshEffort.failure(error.fileItems, error.xhrOrXdr); - } + return new Promise(function(resolve, reject) { + var refreshCompleteCallback = function(response, success, xhrOrXdr) { + handleFileItems(response, success, xhrOrXdr).then(resolve, reject); + }, + requesterOptions = qq.extend({}, options), + requester = new qq.SessionAjaxRequester( + qq.extend(requesterOptions, {onComplete: refreshCompleteCallback}) ); - }, - requesterOptions = qq.extend({}, options), - requester = new qq.SessionAjaxRequester( - qq.extend(requesterOptions, {onComplete: refreshCompleteCallback}) - ); - requester.queryServer(); - - return refreshEffort; + requester.queryServer(); + }); }; }; diff --git a/client/js/uploader.basic.api.js b/client/js/uploader.basic.api.js index 3f2763116..2c29f49e7 100644 --- a/client/js/uploader.basic.api.js +++ b/client/js/uploader.basic.api.js @@ -1762,13 +1762,11 @@ } setTimeout(function() { - self._session.refresh().then(function(response, xhrOrXdr) { + self._session.refresh().then(function(info) { self._sessionRequestComplete(); - self._options.callbacks.onSessionRequestComplete(response, true, xhrOrXdr); - - }, function(response, xhrOrXdr) { - - self._options.callbacks.onSessionRequestComplete(response, false, xhrOrXdr); + self._options.callbacks.onSessionRequestComplete(info.fileItems, true, info.xhrOrXdr); + }, function(error) { + self._options.callbacks.onSessionRequestComplete(error.fileItems, false, error.xhrOrXdr); }); }, 0); } From c6b7f96890a4a3594da763f77a43c5d31e830aff Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 12:57:22 +1100 Subject: [PATCH 48/73] refactor: qq.s3.*AjaxRequester.getHeaders to return Promise --- .../js/s3/multipart.abort.ajax.requester.js | 6 +- .../s3/multipart.complete.ajax.requester.js | 31 ++-- .../s3/multipart.initiate.ajax.requester.js | 31 ++-- test/unit/s3/cdn/generic-chunked.js | 68 ++++---- test/unit/s3/chunked-uploads.js | 154 +++++++++--------- 5 files changed, 151 insertions(+), 139 deletions(-) diff --git a/client/js/s3/multipart.abort.ajax.requester.js b/client/js/s3/multipart.abort.ajax.requester.js index e4ff97ea5..42b6d7628 100644 --- a/client/js/s3/multipart.abort.ajax.requester.js +++ b/client/js/s3/multipart.abort.ajax.requester.js @@ -125,11 +125,11 @@ qq.s3.AbortMultipartAjaxRequester = function(o) { * @param uploadId AWS uploadId for this file */ send: function(id, uploadId) { - getHeaders(id, uploadId).then(function(headers, endOfUrl) { + getHeaders(id, uploadId).then(function(info) { options.log("Submitting S3 Abort multipart upload request for " + id); requester.initTransport(id) - .withPath(endOfUrl) - .withHeaders(headers) + .withPath(info.endOfUrl) + .withHeaders(info.headers) .send(); }); } diff --git a/client/js/s3/multipart.complete.ajax.requester.js b/client/js/s3/multipart.complete.ajax.requester.js index e83548ca3..6027e33c5 100644 --- a/client/js/s3/multipart.complete.ajax.requester.js +++ b/client/js/s3/multipart.complete.ajax.requester.js @@ -35,16 +35,15 @@ qq.s3.CompleteMultipartAjaxRequester = function(o) { }); /** - * Attach all required headers (including Authorization) to the "Complete" request. This is a promissory function - * that will fulfill the associated promise once all headers have been attached or when an error has occurred that - * prevents headers from being attached. + * Attach all required headers (including Authorization) to the "Complete" + * request. This is a promissory function that will resolved once all + * headers have been attached or when an error has occurred that prevents + * headers from being attached. * - * @returns {qq.Promise} + * @returns {Promise} */ function getHeaders(id, uploadId, body) { - var promise = new qq.Promise(); - - options.getKey(id).then(function(key) { + return options.getKey(id).then(function(key) { var headers = {}, bucket = options.getBucket(id), host = options.getHost(id), @@ -55,10 +54,14 @@ qq.s3.CompleteMultipartAjaxRequester = function(o) { .withContentType("application/xml; charset=UTF-8"); // Ask the local server to sign the request. Use this signature to form the Authorization header. - getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure); + return new Promise(function(resolve, reject) { + getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(function(headers, endOfUrl) { + resolve({headers: headers, endOfUrl: endOfUrl}); + }, function(errorReason) { + reject(new Error(errorReason)); + }); + }); }); - - return promise; } /** @@ -171,15 +174,15 @@ qq.s3.CompleteMultipartAjaxRequester = function(o) { var promise = new qq.Promise(), body = getCompleteRequestBody(etagEntries); - getHeaders(id, uploadId, body).then(function(headers, endOfUrl) { + getHeaders(id, uploadId, body).then(function(info) { options.log("Submitting S3 complete multipart upload request for " + id); pendingCompleteRequests[id] = promise; - delete headers["Content-Type"]; + delete info.headers["Content-Type"]; requester.initTransport(id) - .withPath(endOfUrl) - .withHeaders(headers) + .withPath(info.endOfUrl) + .withHeaders(info.headers) .withPayload(body) .send(); }, promise.failure); diff --git a/client/js/s3/multipart.initiate.ajax.requester.js b/client/js/s3/multipart.initiate.ajax.requester.js index 31f3303f7..81fde5290 100644 --- a/client/js/s3/multipart.initiate.ajax.requester.js +++ b/client/js/s3/multipart.initiate.ajax.requester.js @@ -40,18 +40,17 @@ qq.s3.InitiateMultipartAjaxRequester = function(o) { }); /** - * Determine all headers for the "Initiate MPU" request, including the "Authorization" header, which must be determined - * by the local server. This is a promissory function. If the server responds with a signature, the headers - * (including the Authorization header) will be passed into the success method of the promise. Otherwise, the failure - * method on the promise will be called. + * Determine all headers for the "Initiate MPU" request, including the + * "Authorization" header, which must be determined by the local server. + * This is a promissory function. If the server responds with a signature, + * the promise will be resolved with the headers (including the + * Authorization header). Otherwise, it will be rejected. * * @param id Associated file ID - * @returns {qq.Promise} + * @returns {Promise} */ function getHeaders(id) { - var promise = new qq.Promise(); - - options.getKey(id).then(function(key) { + return options.getKey(id).then(function(key) { var bucket = options.getBucket(id), host = options.getHost(id), headers = {}, @@ -84,10 +83,14 @@ qq.s3.InitiateMultipartAjaxRequester = function(o) { .withHeaders(headers); // Ask the local server to sign the request. Use this signature to form the Authorization header. - getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(promise.success, promise.failure); + return new Promise(function(resolve, reject) { + getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(function (headers, endOfUrl) { + resolve({headers: headers, endOfUrl: endOfUrl}); + }, function(errorReason) { + reject(new Error(errorReason)); + }); + }); }); - - return promise; } /** @@ -168,13 +171,13 @@ qq.s3.InitiateMultipartAjaxRequester = function(o) { send: function(id) { var promise = new qq.Promise(); - getHeaders(id).then(function(headers, endOfUrl) { + getHeaders(id).then(function(info) { options.log("Submitting S3 initiate multipart upload request for " + id); pendingInitiateRequests[id] = promise; requester.initTransport(id) - .withPath(endOfUrl) - .withHeaders(headers) + .withPath(info.endOfUrl) + .withHeaders(info.headers) .send(); }, promise.failure); diff --git a/test/unit/s3/cdn/generic-chunked.js b/test/unit/s3/cdn/generic-chunked.js index 763c0eea6..e6893d2ff 100644 --- a/test/unit/s3/cdn/generic-chunked.js +++ b/test/unit/s3/cdn/generic-chunked.js @@ -44,49 +44,53 @@ if (qqtest.canDownloadFileAsBlob) { assert.ok(initiateToSign.headers.indexOf("/mybucket/" + key0 + "?uploads") > 0); initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - // initiate multipart upload request - initiateRequest = fileTestHelper.getRequests()[1]; - initiateRequest.respond(200, null, "123"); - setTimeout(function() { - // signature request for upload part 1 - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers.indexOf("/mybucket/" + key0 + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + // initiate multipart upload request + initiateRequest = fileTestHelper.getRequests()[1]; + initiateRequest.respond(200, null, "123"); setTimeout(function() { - // upload part 1 request - uploadPartRequest = fileTestHelper.getRequests()[2]; - uploadPartRequest.respond(200, {ETag: "etag1"}, null); + // signature request for upload part 1 + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers.indexOf("/mybucket/" + key0 + "?partNumber=1&uploadId=123") > 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - // signature request for upload part 2 - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers.indexOf("/mybucket/" + key0 + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + // upload part 1 request + uploadPartRequest = fileTestHelper.getRequests()[2]; + uploadPartRequest.respond(200, {ETag: "etag1"}, null); setTimeout(function() { - // upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[4]; - uploadPartRequest.respond(200, {ETag: "etag2"}, null); + // signature request for upload part 2 + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers.indexOf("/mybucket/" + key0 + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - // signature request for multipart complete - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers.indexOf("/mybucket/" + key0 + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - - // multipart complete request - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - multipartCompleteRequest.respond(200, null, "mybucket" + key0 + ""); + // upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[4]; + uploadPartRequest.respond(200, {ETag: "etag2"}, null); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - - done(); + // signature request for multipart complete + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers.indexOf("/mybucket/" + key0 + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + + setTimeout(function() { + // multipart complete request + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + multipartCompleteRequest.respond(200, null, "mybucket" + key0 + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + + done(); + }, 0); + }, 0); }, 0); }, 0); }, 0); diff --git a/test/unit/s3/chunked-uploads.js b/test/unit/s3/chunked-uploads.js index 0c2ce8dcd..cad17508f 100644 --- a/test/unit/s3/chunked-uploads.js +++ b/test/unit/s3/chunked-uploads.js @@ -334,97 +334,99 @@ if (qqtest.canDownloadFileAsBlob) { assert.ok(initiateToSign.headers.indexOf("/" + testBucketName + "/" + key0 + "?uploads") > 0); initiateSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); - // initiate multipart upload request - assert.equal(fileTestHelper.getRequests().length, 2); - initiateRequest = fileTestHelper.getRequests()[1]; - assert.equal(initiateRequest.method, "POST"); - assert.equal(initiateRequest.url, testS3Endpoint + "/" + key0 + "?uploads"); - assert.equal(initiateRequest.requestHeaders["x-amz-meta-qqfilename"], uploader.getName(0)); - assert.equal(initiateRequest.requestHeaders["x-amz-acl"], "private"); - assert.ok(initiateRequest.requestHeaders["x-amz-date"]); - assert.equal(initiateRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); - initiateRequest.respond(200, null, "123"); - setTimeout(function() { - // signature request for upload part 1 - assert.equal(fileTestHelper.getRequests().length, 4); - uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; - assert.equal(uploadPartSignatureRequest1.method, "POST"); - assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); - assert.equal(uploadPartSignatureRequest1.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); - assert.ok(uploadPartToSign1.headers); - assert.equal(uploadPartToSign1.headers.indexOf("PUT"), 0); - assert.ok(uploadPartToSign1.headers.indexOf("x-amz-date:") > 0); - assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + key0 + "?partNumber=1&uploadId=123") > 0); - uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); + // initiate multipart upload request + assert.equal(fileTestHelper.getRequests().length, 2); + initiateRequest = fileTestHelper.getRequests()[1]; + assert.equal(initiateRequest.method, "POST"); + assert.equal(initiateRequest.url, testS3Endpoint + "/" + key0 + "?uploads"); + assert.equal(initiateRequest.requestHeaders["x-amz-meta-qqfilename"], uploader.getName(0)); + assert.equal(initiateRequest.requestHeaders["x-amz-acl"], "private"); + assert.ok(initiateRequest.requestHeaders["x-amz-date"]); + assert.equal(initiateRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); + initiateRequest.respond(200, null, "123"); setTimeout(function() { - // upload part 1 request - uploadPartRequest = fileTestHelper.getRequests()[2]; - assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=1&uploadId=123"); - assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); + // signature request for upload part 1 + assert.equal(fileTestHelper.getRequests().length, 4); + uploadPartSignatureRequest1 = fileTestHelper.getRequests()[3]; + assert.equal(uploadPartSignatureRequest1.method, "POST"); + assert.equal(uploadPartSignatureRequest1.url, testSignatureEndoint); + assert.equal(uploadPartSignatureRequest1.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadPartToSign1 = JSON.parse(uploadPartSignatureRequest1.requestBody); + assert.ok(uploadPartToSign1.headers); + assert.equal(uploadPartToSign1.headers.indexOf("PUT"), 0); + assert.ok(uploadPartToSign1.headers.indexOf("x-amz-date:") > 0); + assert.ok(uploadPartToSign1.headers.indexOf("/" + testBucketName + "/" + key0 + "?partNumber=1&uploadId=123") > 0); + uploadPartSignatureRequest1.respond(200, null, JSON.stringify({signature: "thesignature"})); - assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); + setTimeout(function() { + // upload part 1 request + uploadPartRequest = fileTestHelper.getRequests()[2]; + assert.equal(uploadPartRequest.method, "PUT"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=1&uploadId=123"); + assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); - assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); - uploadPartRequest.respond(200, {ETag: "etag1"}, null); + assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); - setTimeout(function() { - // signature request for upload part 2 - assert.equal(fileTestHelper.getRequests().length, 6); - uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; - assert.equal(uploadPartSignatureRequest2.method, "POST"); - assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); - assert.equal(uploadPartSignatureRequest2.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); - assert.ok(uploadPartToSign2.headers); - assert.equal(uploadPartToSign2.headers.indexOf("PUT"), 0); - assert.ok(uploadPartToSign2.headers.indexOf("x-amz-date:") > 0); - assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + key0 + "?partNumber=2&uploadId=123") > 0); - uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); + assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); + uploadPartRequest.respond(200, {ETag: "etag1"}, null); setTimeout(function() { - // upload part 2 request - uploadPartRequest = fileTestHelper.getRequests()[4]; - assert.equal(uploadPartRequest.method, "PUT"); - assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=2&uploadId=123"); - assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); + // signature request for upload part 2 + assert.equal(fileTestHelper.getRequests().length, 6); + uploadPartSignatureRequest2 = fileTestHelper.getRequests()[5]; + assert.equal(uploadPartSignatureRequest2.method, "POST"); + assert.equal(uploadPartSignatureRequest2.url, testSignatureEndoint); + assert.equal(uploadPartSignatureRequest2.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadPartToSign2 = JSON.parse(uploadPartSignatureRequest2.requestBody); + assert.ok(uploadPartToSign2.headers); + assert.equal(uploadPartToSign2.headers.indexOf("PUT"), 0); + assert.ok(uploadPartToSign2.headers.indexOf("x-amz-date:") > 0); + assert.ok(uploadPartToSign2.headers.indexOf("/" + testBucketName + "/" + key0 + "?partNumber=2&uploadId=123") > 0); + uploadPartSignatureRequest2.respond(200, null, JSON.stringify({signature: "thesignature"})); - assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); + setTimeout(function() { + // upload part 2 request + uploadPartRequest = fileTestHelper.getRequests()[4]; + assert.equal(uploadPartRequest.method, "PUT"); + assert.equal(uploadPartRequest.url, testS3Endpoint + "/" + key0 + "?partNumber=2&uploadId=123"); + assert.ok(uploadPartRequest.requestHeaders["x-amz-date"]); - assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); - uploadPartRequest.respond(200, {ETag: "etag2"}, null); + assert.equal(uploadPartRequest.requestHeaders["Content-Type"], ""); - setTimeout(function() { - // signature request for multipart complete - assert.equal(fileTestHelper.getRequests().length, 7); - uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; - assert.equal(uploadCompleteSignatureRequest.method, "POST"); - assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); - assert.equal(uploadCompleteSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); - uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); - assert.ok(uploadCompleteToSign.headers); - assert.equal(uploadCompleteToSign.headers.indexOf("POST"), 0); - assert.ok(uploadCompleteToSign.headers.indexOf("x-amz-date:") > 0); - assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + key0 + "?uploadId=123") > 0); - uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); + assert.equal(uploadPartRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); + uploadPartRequest.respond(200, {ETag: "etag2"}, null); setTimeout(function() { - // multipart complete request - assert.equal(fileTestHelper.getRequests().length, 8); - multipartCompleteRequest = fileTestHelper.getRequests()[7]; - assert.equal(multipartCompleteRequest.method, "POST"); - assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + key0 + "?uploadId=123"); - assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); - assert.equal(multipartCompleteRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); - assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); - multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + key0 + ""); + // signature request for multipart complete + assert.equal(fileTestHelper.getRequests().length, 7); + uploadCompleteSignatureRequest = fileTestHelper.getRequests()[6]; + assert.equal(uploadCompleteSignatureRequest.method, "POST"); + assert.equal(uploadCompleteSignatureRequest.url, testSignatureEndoint); + assert.equal(uploadCompleteSignatureRequest.requestHeaders["Content-Type"].indexOf("application/json;"), 0); + uploadCompleteToSign = JSON.parse(uploadCompleteSignatureRequest.requestBody); + assert.ok(uploadCompleteToSign.headers); + assert.equal(uploadCompleteToSign.headers.indexOf("POST"), 0); + assert.ok(uploadCompleteToSign.headers.indexOf("x-amz-date:") > 0); + assert.ok(uploadCompleteToSign.headers.indexOf("/" + testBucketName + "/" + key0 + "?uploadId=123") > 0); + uploadCompleteSignatureRequest.respond(200, null, JSON.stringify({signature: "thesignature"})); setTimeout(function() { - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + // multipart complete request + assert.equal(fileTestHelper.getRequests().length, 8); + multipartCompleteRequest = fileTestHelper.getRequests()[7]; + assert.equal(multipartCompleteRequest.method, "POST"); + assert.equal(multipartCompleteRequest.url, testS3Endpoint + "/" + key0 + "?uploadId=123"); + assert.ok(multipartCompleteRequest.requestHeaders["x-amz-date"]); + assert.equal(multipartCompleteRequest.requestHeaders.Authorization, "AWS " + testAccessKey + ":thesignature"); + assert.equal(multipartCompleteRequest.requestBody, "1etag12etag2"); + multipartCompleteRequest.respond(200, null, "" + testBucketName + "" + key0 + ""); + + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + done(); + }, 0); }, 0); }, 0); }, 0); From 7676f2621cb85920c680a6122cd6290f0d01807d Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 13:10:42 +1100 Subject: [PATCH 49/73] refactor: qq.s3.InitiateMultipartAjaxRequester.send to return Promise --- .../s3/multipart.initiate.ajax.requester.js | 37 ++++++++++--------- client/js/s3/s3.xhr.upload.handler.js | 16 ++++---- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/client/js/s3/multipart.initiate.ajax.requester.js b/client/js/s3/multipart.initiate.ajax.requester.js index 81fde5290..d0390376c 100644 --- a/client/js/s3/multipart.initiate.ajax.requester.js +++ b/client/js/s3/multipart.initiate.ajax.requester.js @@ -105,7 +105,7 @@ qq.s3.InitiateMultipartAjaxRequester = function(o) { var promise = pendingInitiateRequests[id], domParser = new DOMParser(), responseDoc = domParser.parseFromString(xhr.responseText, "application/xml"), - uploadIdElements, messageElements, uploadId, errorMessage, status; + uploadIdElements, messageElements, uploadId, errorMessage, status, error; delete pendingInitiateRequests[id]; @@ -138,11 +138,13 @@ qq.s3.InitiateMultipartAjaxRequester = function(o) { options.log(qq.format("Unexplained error with initiate multipart upload request for {}. Status code {}.", id, status), "error"); } - promise.failure("Problem initiating upload request.", xhr); + error = new Error("Problem initiating upload request."); + error.xhr = xhr; + promise.reject(error); } else { options.log(qq.format("Initiate multipart upload request successful for {}. Upload ID is {}", id, uploadId)); - promise.success(uploadId, xhr); + promise.resolve({uploadId: uploadId, xhr: xhr}); } } @@ -161,27 +163,28 @@ qq.s3.InitiateMultipartAjaxRequester = function(o) { qq.extend(this, { /** - * Sends the "Initiate MPU" request to AWS via the REST API. First, though, we must get a signature from the - * local server for the request. If all is successful, the uploadId from AWS will be passed into the promise's - * success handler. Otherwise, an error message will ultimately be passed into the failure method. + * Sends the "Initiate MPU" request to AWS via the REST API. First, + * though, we must get a signature from the local server for the + * request. If all is successful, the promise will be resolved with + * `{uploadId: string, xhr: XMLHttpRequest}` from AWS. Otherwise, it + * will be rejected with an error with an `xhr` property. * * @param id The ID associated with the file - * @returns {qq.Promise} + * @returns {Promise} */ send: function(id) { - var promise = new qq.Promise(); - - getHeaders(id).then(function(info) { + return getHeaders(id).then(function(info) { options.log("Submitting S3 initiate multipart upload request for " + id); - pendingInitiateRequests[id] = promise; - requester.initTransport(id) - .withPath(info.endOfUrl) - .withHeaders(info.headers) - .send(); - }, promise.failure); + return new Promise(function(resolve, reject) { + pendingInitiateRequests[id] = {resolve: resolve, reject: reject}; - return promise; + requester.initTransport(id) + .withPath(info.endOfUrl) + .withHeaders(info.headers) + .send(); + }); + }); } }); }; diff --git a/client/js/s3/s3.xhr.upload.handler.js b/client/js/s3/s3.xhr.upload.handler.js index 5010e509d..c07d14f2a 100755 --- a/client/js/s3/s3.xhr.upload.handler.js +++ b/client/js/s3/s3.xhr.upload.handler.js @@ -177,14 +177,12 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { if (!uploadId) { handler._getPersistableData(id).uploadId = new Promise(function(resolve, reject) { requesters.initiateMultipart.send(id).then( - function(uploadId) { - handler._getPersistableData(id).uploadId = uploadId; - resolve(uploadId); - setupResolve(uploadId); + function(info) { + handler._getPersistableData(id).uploadId = info.uploadId; + resolve(info.uploadId); + setupResolve(info.uploadId); }, - function(errorMsg, xhr) { - var error = new Error(errorMsg); - error.xhr = xhr; + function(error) { handler._getPersistableData(id).uploadId = null; setupReject(error); reject(error); @@ -193,8 +191,8 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { }); } else if (uploadId instanceof Promise) { - uploadId.then(function(uploadId) { - setupResolve(uploadId); + uploadId.then(function(info) { + setupResolve(info.uploadId); }); } else { From 9d3cb9de7803fb39e86b2e699e2e37f6da8fa7ea Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 13:14:37 +1100 Subject: [PATCH 50/73] refactor: qq.s3.CompleteMultipartAjaxRequester.send to return Promise --- .../s3/multipart.complete.ajax.requester.js | 38 ++++++++++--------- client/js/s3/s3.xhr.upload.handler.js | 12 +++--- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/client/js/s3/multipart.complete.ajax.requester.js b/client/js/s3/multipart.complete.ajax.requester.js index 6027e33c5..d101e946f 100644 --- a/client/js/s3/multipart.complete.ajax.requester.js +++ b/client/js/s3/multipart.complete.ajax.requester.js @@ -80,7 +80,8 @@ qq.s3.CompleteMultipartAjaxRequester = function(o) { bucket = options.getBucket(id), responseDoc = domParser.parseFromString(xhr.responseText, "application/xml"), bucketEls = responseDoc.getElementsByTagName("Bucket"), - keyEls = responseDoc.getElementsByTagName("Key"); + keyEls = responseDoc.getElementsByTagName("Key"), + error; delete pendingCompleteRequests[id]; @@ -107,10 +108,12 @@ qq.s3.CompleteMultipartAjaxRequester = function(o) { } if (isError) { - promise.failure("Problem combining the file parts!", xhr); + error = new Error("Problem combining the file parts!"); + error.xhr = xhr; + promise.reject(error); } else { - promise.success({}, xhr); + promise.resolve({response: {}, xhr: xhr}); } }); } @@ -163,31 +166,30 @@ qq.s3.CompleteMultipartAjaxRequester = function(o) { qq.extend(this, { /** - * Sends the "Complete" request and fulfills the returned promise when the success of this request is known. + * Sends the "Complete" request and resolved the returned promise when the success of this request is known. * * @param id ID associated with the file. * @param uploadId AWS uploadId for this file * @param etagEntries Array of objects containing `etag` values and their associated `part` numbers. - * @returns {qq.Promise} + * @returns {Promise} */ send: function(id, uploadId, etagEntries) { - var promise = new qq.Promise(), - body = getCompleteRequestBody(etagEntries); + var body = getCompleteRequestBody(etagEntries); - getHeaders(id, uploadId, body).then(function(info) { + return getHeaders(id, uploadId, body).then(function(info) { options.log("Submitting S3 complete multipart upload request for " + id); - pendingCompleteRequests[id] = promise; - delete info.headers["Content-Type"]; + return new Promise(function(resolve, reject) { + pendingCompleteRequests[id] = {resolve: resolve, reject: reject}; + delete info.headers["Content-Type"]; - requester.initTransport(id) - .withPath(info.endOfUrl) - .withHeaders(info.headers) - .withPayload(body) - .send(); - }, promise.failure); - - return promise; + requester.initTransport(id) + .withPath(info.endOfUrl) + .withHeaders(info.headers) + .withPayload(body) + .send(); + }); + }); } }); }; diff --git a/client/js/s3/s3.xhr.upload.handler.js b/client/js/s3/s3.xhr.upload.handler.js index c07d14f2a..6cbbcbd5f 100755 --- a/client/js/s3/s3.xhr.upload.handler.js +++ b/client/js/s3/s3.xhr.upload.handler.js @@ -39,14 +39,12 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { return new Promise(function(resolve, reject) { requesters.completeMultipart.send(id, uploadId, etagMap).then( - function(response, xhr) { - resolve({response: response, xhr: xhr}); - }, + resolve, - function failure(reason, xhr) { - var error = new Error(reason); - error.xhr = xhr; - error.response = upload.done(id, xhr).response; + function failure(err) { + var error = new Error(err.message); + error.xhr = err.xhr; + error.response = upload.done(id, err.xhr).response; reject(error); } ); From 5b9546cb4f7c68ae9949fe8c0a4c0676419a8042 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 13:16:25 +1100 Subject: [PATCH 51/73] refactor: onExpired to return Promise --- client/js/s3/request-signer.js | 2 +- client/js/s3/uploader.basic.js | 47 +++++++++++++++++----------------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/client/js/s3/request-signer.js b/client/js/s3/request-signer.js index 2e12551db..14a4251aa 100644 --- a/client/js/s3/request-signer.js +++ b/client/js/s3/request-signer.js @@ -503,7 +503,7 @@ qq.s3.RequestSigner = function(o) { signatureEffort, credentialsProvider.get().accessKey, credentialsProvider.get().sessionToken); - }, function(errorMsg) { + }, function() { options.log("Attempt to update expired credentials apparently failed! Unable to sign request. ", "error"); signatureEffort.failure("Unable to sign request - expired credentials."); }); diff --git a/client/js/s3/uploader.basic.js b/client/js/s3/uploader.basic.js index a8999c948..367a6d08a 100644 --- a/client/js/s3/uploader.basic.js +++ b/client/js/s3/uploader.basic.js @@ -255,30 +255,29 @@ }, onExpired: function() { - var updateCredentials = new qq.Promise(), - callbackRetVal = self._options.callbacks.onCredentialsExpired(); - - if (qq.isGenericPromise(callbackRetVal)) { - callbackRetVal.then(function(credentials) { - try { - self.setCredentials(credentials); - updateCredentials.success(); - } - catch (error) { - self.log("Invalid credentials returned from onCredentialsExpired callback! (" + error.message + ")", "error"); - updateCredentials.failure("onCredentialsExpired did not return valid credentials."); - } - }, function(errorMsg) { - self.log("onCredentialsExpired callback indicated failure! (" + errorMsg + ")", "error"); - updateCredentials.failure("onCredentialsExpired callback failed."); - }); - } - else { - self.log("onCredentialsExpired callback did not return a promise!", "error"); - updateCredentials.failure("Unexpected return value for onCredentialsExpired."); - } - - return updateCredentials; + var callbackRetVal = self._options.callbacks.onCredentialsExpired(); + + return new Promise(function(resolve, reject) { + if (qq.isGenericPromise(callbackRetVal)) { + callbackRetVal.then(function(credentials) { + try { + self.setCredentials(credentials); + resolve(); + } + catch (error) { + self.log("Invalid credentials returned from onCredentialsExpired callback! (" + error.message + ")", "error"); + reject(new Error("onCredentialsExpired did not return valid credentials.")); + } + }, function(errorMsg) { + self.log("onCredentialsExpired callback indicated failure! (" + errorMsg + ")", "error"); + reject(new Error("onCredentialsExpired callback failed.")); + }); + } + else { + self.log("onCredentialsExpired callback did not return a promise!", "error"); + reject(new Error("Unexpected return value for onCredentialsExpired.")); + } + }); } }; From 58b19d73ae4aa875d7390de250d606c276018ede Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 13:19:19 +1100 Subject: [PATCH 52/73] refactor: _determineObjectPropertyValue to return Promise --- client/js/s3/uploader.basic.js | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/client/js/s3/uploader.basic.js b/client/js/s3/uploader.basic.js index 367a6d08a..f19ede7ee 100644 --- a/client/js/s3/uploader.basic.js +++ b/client/js/s3/uploader.basic.js @@ -286,29 +286,31 @@ _determineObjectPropertyValue: function(id, property) { var maybe = this._options.objectProperties[property], - promise = new qq.Promise(), + promise, self = this; - if (qq.isFunction(maybe)) { - maybe = maybe(id); - if (qq.isGenericPromise(maybe)) { - promise = maybe; + promise = new Promise(function(resolve, reject) { + if (qq.isFunction(maybe)) { + maybe = maybe(id); + if (qq.isGenericPromise(maybe)) { + maybe.then(resolve, reject); + } + else { + resolve(maybe); + } } - else { - promise.success(maybe); + else if (qq.isString(maybe)) { + resolve(maybe); } - } - else if (qq.isString(maybe)) { - promise.success(maybe); - } + }); promise.then( function success(value) { self["_" + property + "s"][id] = value; }, - function failure(errorMsg) { - qq.log("Problem determining " + property + " for ID " + id + " (" + errorMsg + ")", "error"); + function failure(error) { + qq.log("Problem determining " + property + " for ID " + id + " (" + error.message + ")", "error"); } ); From 9bae71c4729139e641bec65a98f2dfeebcd9461b Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 13:26:13 +1100 Subject: [PATCH 53/73] refactor: qq.s3.FineUploaderBasic._determineKeyName to return Promise --- client/js/s3/s3.form.upload.handler.js | 4 +- client/js/s3/s3.xhr.upload.handler.js | 10 ++-- client/js/s3/uploader.basic.js | 67 ++++++++++++++------------ 3 files changed, 41 insertions(+), 40 deletions(-) diff --git a/client/js/s3/s3.form.upload.handler.js b/client/js/s3/s3.form.upload.handler.js index 61812d7a0..2a17b163e 100644 --- a/client/js/s3/s3.form.upload.handler.js +++ b/client/js/s3/s3.form.upload.handler.js @@ -228,9 +228,9 @@ qq.s3.FormUploadHandler = function(options, proxy) { error.error = errorReason; reject(error); }); - }, function(errorReason) { + }, function(err) { var error = new Error("Failed to get key name"); - error.error = errorReason; + error.error = err.message; reject(error); }); } diff --git a/client/js/s3/s3.xhr.upload.handler.js b/client/js/s3/s3.xhr.upload.handler.js index 6cbbcbd5f..b79bf8844 100755 --- a/client/js/s3/s3.xhr.upload.handler.js +++ b/client/js/s3/s3.xhr.upload.handler.js @@ -447,13 +447,11 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { if (key == null) { key = new Promise(function(resolve, reject) { onGetKeyName(id, getName(id)).then( - function(keyName) { - resolve(keyName); - }, - function(errorReason) { + resolve, + function(err) { handler._setThirdPartyFileId(id, null); - var error = new Error(errorReason); - error.error = errorReason; + var error = new Error(err.message); + error.error = err.message; reject(error); } ); diff --git a/client/js/s3/uploader.basic.js b/client/js/s3/uploader.basic.js index f19ede7ee..33338a674 100644 --- a/client/js/s3/uploader.basic.js +++ b/client/js/s3/uploader.basic.js @@ -332,43 +332,46 @@ * * @param id ID of the file * @param filename Name of the file - * @returns {qq.Promise} A promise that will be fulfilled when the key name has been determined (and will be passed to the caller via the success callback). + * @returns {Promise} A promise that will be resolved with the key name when it has been determined. * @private */ _determineKeyName: function(id, filename) { - /*jshint -W015*/ - var promise = new qq.Promise(), - keynameLogic = this._options.objectProperties.key, - extension = qq.getExtension(filename), - onGetKeynameFailure = promise.failure, - onGetKeynameSuccess = function(keyname, extension) { - var keynameToUse = keyname; - - if (extension !== undefined) { - keynameToUse += "." + extension; - } - - promise.success(keynameToUse); - }; + var self = this; - switch (keynameLogic) { - case "uuid": - onGetKeynameSuccess(this.getUuid(id), extension); - break; - case "filename": - onGetKeynameSuccess(filename); - break; - default: - if (qq.isFunction(keynameLogic)) { - this._handleKeynameFunction(keynameLogic, id, onGetKeynameSuccess, onGetKeynameFailure); - } - else { - this.log(keynameLogic + " is not a valid value for the s3.keyname option!", "error"); - onGetKeynameFailure(); - } - } + return new Promise(function(resolve, reject) { + /*jshint -W015*/ + var keynameLogic = self._options.objectProperties.key, + extension = qq.getExtension(filename), + onGetKeynameFailure = function(reason) { + reject(new Error(reason)); + }, + onGetKeynameSuccess = function(keyname, extension) { + var keynameToUse = keyname; + + if (extension !== undefined) { + keynameToUse += "." + extension; + } - return promise; + resolve(keynameToUse); + }; + + switch (keynameLogic) { + case "uuid": + onGetKeynameSuccess(self.getUuid(id), extension); + break; + case "filename": + onGetKeynameSuccess(filename); + break; + default: + if (qq.isFunction(keynameLogic)) { + self._handleKeynameFunction(keynameLogic, id, onGetKeynameSuccess, onGetKeynameFailure); + } + else { + self.log(keynameLogic + " is not a valid value for the s3.keyname option!", "error"); + onGetKeynameFailure(); + } + } + }); }, /** From a6a432baac15e3d3f4f9a96569444b58cf37eebf Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 13:28:09 +1100 Subject: [PATCH 54/73] refactor: qq.azure.PutBlock.upload to return Promise --- client/js/azure/rest/put-block.js | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/client/js/azure/rest/put-block.js b/client/js/azure/rest/put-block.js index b5d0b09d5..a2cc94292 100644 --- a/client/js/azure/rest/put-block.js +++ b/client/js/azure/rest/put-block.js @@ -45,10 +45,10 @@ qq.azure.PutBlock = function(o) { delete blockIdEntries[id]; if (isError) { - promise.failure(); + promise.reject(); } else { - promise.success(blockIdEntry); + promise.resolve(blockIdEntry); } } })); @@ -64,21 +64,20 @@ qq.azure.PutBlock = function(o) { qq.extend(this, { method: method, upload: function(id, xhr, sasUri, partNum, blob) { - var promise = new qq.Promise(), - blockId = createBlockId(partNum); + return new Promise(function(resolve, reject) { + var blockId = createBlockId(partNum); - promises[id] = promise; + promises[id] = {resolve: resolve, reject: reject}; - options.log(qq.format("Submitting Put Block request for {} = part {}", id, partNum)); + options.log(qq.format("Submitting Put Block request for {} = part {}", id, partNum)); - endpoints[id] = qq.format("{}&comp=block&blockid={}", sasUri, encodeURIComponent(blockId)); - blockIdEntries[id] = {part: partNum, id: blockId}; + endpoints[id] = qq.format("{}&comp=block&blockid={}", sasUri, encodeURIComponent(blockId)); + blockIdEntries[id] = {part: partNum, id: blockId}; - requester.initTransport(id) - .withPayload(blob) - .send(xhr); - - return promise; + requester.initTransport(id) + .withPayload(blob) + .send(xhr); + }); } }); }; From e317ed0dba8534252d3196213dcfb6d14f67d4c3 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 13:30:17 +1100 Subject: [PATCH 55/73] refactor: qq.azure.PutBlob.upload to return Promise --- client/js/azure/rest/put-blob.js | 24 +++++++++++------------- test/unit/azure/delete-files.js | 12 +++++++----- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/client/js/azure/rest/put-blob.js b/client/js/azure/rest/put-blob.js index 2570dd9df..693732612 100644 --- a/client/js/azure/rest/put-blob.js +++ b/client/js/azure/rest/put-blob.js @@ -51,10 +51,10 @@ qq.azure.PutBlob = function(o) { delete promises[id]; if (isError) { - promise.failure(); + promise.reject(); } else { - promise.success(); + promise.resolve(); } } })); @@ -62,19 +62,17 @@ qq.azure.PutBlob = function(o) { qq.extend(this, { method: method, upload: function(id, xhr, url, file) { - var promise = new qq.Promise(); + return new Promise(function(resolve, reject) { + options.log("Submitting Put Blob request for " + id); - options.log("Submitting Put Blob request for " + id); + promises[id] = {resolve: resolve, reject: reject}; + endpoints[id] = url; - promises[id] = promise; - endpoints[id] = url; - - requester.initTransport(id) - .withPayload(file) - .withHeaders({"Content-Type": file.type}) - .send(xhr); - - return promise; + requester.initTransport(id) + .withPayload(file) + .withHeaders({"Content-Type": file.type}) + .send(xhr); + }); } }); }; diff --git a/test/unit/azure/delete-files.js b/test/unit/azure/delete-files.js index 167550701..c3a166d05 100644 --- a/test/unit/azure/delete-files.js +++ b/test/unit/azure/delete-files.js @@ -127,12 +127,14 @@ if (qqtest.canDownloadFileAsBlob) { var deleteFileSignatureRequest; uploader.deleteFile(0); - deleteFileSignatureRequest = fileTestHelper.getRequests()[2]; - deleteFileSignatureRequest.respond(500, null, null); - setTimeout(function() { - assert.equal(fileTestHelper.getRequests().length, 3); - assert.equal(uploader.getUploads()[0].status, qq.status.DELETE_FAILED); + deleteFileSignatureRequest = fileTestHelper.getRequests()[2]; + deleteFileSignatureRequest.respond(500, null, null); + + setTimeout(function() { + assert.equal(fileTestHelper.getRequests().length, 3); + assert.equal(uploader.getUploads()[0].status, qq.status.DELETE_FAILED); + }, 0); }, 0); }); }); From 51a4b57af42a4989f2c9603f8ceb0254461fffca Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 13:37:34 +1100 Subject: [PATCH 56/73] refactor: qq.azure.PutBlockList.send to return Promise --- client/js/azure/rest/put-block-list.js | 34 ++++++++++++++------------ 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/client/js/azure/rest/put-block-list.js b/client/js/azure/rest/put-block-list.js index ea161a788..017862cf1 100644 --- a/client/js/azure/rest/put-block-list.js +++ b/client/js/azure/rest/put-block-list.js @@ -43,16 +43,19 @@ qq.azure.PutBlockList = function(o) { log: options.log, onSend: function() {}, onComplete: function(id, xhr, isError) { - var promise = promises[id]; + var promise = promises[id], + error; delete endpoints[id]; delete promises[id]; if (isError) { - promise.failure(xhr); + error = new Error("Failed to put block list"); + error.xhr = xhr; + promise.reject(error); } else { - promise.success(xhr); + promise.resolve(xhr); } } @@ -82,23 +85,22 @@ qq.azure.PutBlockList = function(o) { qq.extend(this, { method: method, send: function(id, sasUri, blockIdEntries, fileMimeType, registerXhrCallback) { - var promise = new qq.Promise(), - blockIdsXml = createRequestBody(blockIdEntries), - xhr; + return new Promise(function(resolve, reject) { + var blockIdsXml = createRequestBody(blockIdEntries), + xhr; - promises[id] = promise; + promises[id] = {resolve: resolve, reject: reject}; - options.log(qq.format("Submitting Put Block List request for {}", id)); + options.log(qq.format("Submitting Put Block List request for {}", id)); - endpoints[id] = qq.format("{}&comp=blocklist", sasUri); + endpoints[id] = qq.format("{}&comp=blocklist", sasUri); - xhr = requester.initTransport(id) - .withPayload(blockIdsXml) - .withHeaders({"x-ms-blob-content-type": fileMimeType}) - .send(); - registerXhrCallback(xhr); - - return promise; + xhr = requester.initTransport(id) + .withPayload(blockIdsXml) + .withHeaders({"x-ms-blob-content-type": fileMimeType}) + .send(); + registerXhrCallback(xhr); + }); } }); }; From 16392654b3581412e095a2cb8c89846606c2c43d Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 13:52:01 +1100 Subject: [PATCH 57/73] refactor: qq.traditional.AllChunksDoneAjaxRequester.complete to return Promise --- .../all-chunks-done.ajax.requester.js | 27 ++++++++++--------- .../traditional.xhr.upload.handler.js | 6 ++--- test/unit/submit-validate-cancel.js | 1 + 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/client/js/traditional/all-chunks-done.ajax.requester.js b/client/js/traditional/all-chunks-done.ajax.requester.js index c60b79f3d..7dfe36ff6 100644 --- a/client/js/traditional/all-chunks-done.ajax.requester.js +++ b/client/js/traditional/all-chunks-done.ajax.requester.js @@ -43,33 +43,34 @@ qq.traditional.AllChunksDoneAjaxRequester = function(o) { cors: options.cors, log: options.log, onComplete: function(id, xhr, isError) { - var promise = promises[id]; + var promise = promises[id], + error; delete promises[id]; if (isError) { - promise.failure(xhr); + error = new Error("Failed to request all chunks done."); + error.xhr = xhr; + promise.reject(error); } else { - promise.success(xhr); + promise.resolve(xhr); } } })); qq.extend(this, { complete: function(id, xhr, params, headers) { - var promise = new qq.Promise(); + return new Promise(function(resolve, reject) { + options.log("Submitting All Chunks Done request for " + id); - options.log("Submitting All Chunks Done request for " + id); + promises[id] = {resolve: resolve, reject: reject}; - promises[id] = promise; - - requester.initTransport(id) - .withParams(options.params(id) || params) - .withHeaders(options.headers(id) || headers) - .send(xhr); - - return promise; + requester.initTransport(id) + .withParams(options.params(id) || params) + .withHeaders(options.headers(id) || headers) + .send(xhr); + }); } }); }; diff --git a/client/js/traditional/traditional.xhr.upload.handler.js b/client/js/traditional/traditional.xhr.upload.handler.js index f02450aae..6252c3d35 100644 --- a/client/js/traditional/traditional.xhr.upload.handler.js +++ b/client/js/traditional/traditional.xhr.upload.handler.js @@ -127,10 +127,10 @@ qq.traditional.XhrUploadHandler = function(spec, proxy) { ) .then(function(xhr) { resolve({response: parseResponse(false, xhr), xhr: xhr}); - }, function(xhr) { + }, function(err) { var error = new Error("All chunks done requester failed"); - error.response = parseResponse(false, xhr); - error.xhr = xhr; + error.response = parseResponse(false, err.xhr); + error.xhr = err.xhr; reject(error); }); }); diff --git a/test/unit/submit-validate-cancel.js b/test/unit/submit-validate-cancel.js index f32eb5cf6..7408575df 100644 --- a/test/unit/submit-validate-cancel.js +++ b/test/unit/submit-validate-cancel.js @@ -10,6 +10,7 @@ if (qqtest.canDownloadFileAsBlob) { before(function() { oldWrapCallbacks = qq.FineUploaderBasic.prototype._wrapCallbacks; + window.localStorage.clear(); // "Turn off" wrapping of callbacks that squelches errors. We need AssertionErrors in callbacks to bubble. qq.FineUploaderBasic.prototype._wrapCallbacks = function() {}; From 53f90d0f37675b8aa5be5ba7567b697aed6b4d35 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 13:55:10 +1100 Subject: [PATCH 58/73] refactor: qq.traditional.FormUploadHandler.uploadFile to return Promise --- .../traditional.form.upload.handler.js | 43 ++++++++++--------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/client/js/traditional/traditional.form.upload.handler.js b/client/js/traditional/traditional.form.upload.handler.js index 1b95dda06..e9c18e0f0 100644 --- a/client/js/traditional/traditional.form.upload.handler.js +++ b/client/js/traditional/traditional.form.upload.handler.js @@ -71,37 +71,40 @@ qq.traditional.FormUploadHandler = function(options, proxy) { this.uploadFile = function(id) { var input = handler.getInput(id), iframe = handler._createIframe(id), - promise = new qq.Promise(), form; form = createForm(id, iframe); form.appendChild(input); - handler._attachLoadEvent(iframe, function(responseFromMessage) { - log("iframe loaded"); + return new Promise(function(resolve, reject) { + handler._attachLoadEvent(iframe, function(responseFromMessage) { + var error; - var response = responseFromMessage ? responseFromMessage : getIframeContentJson(id, iframe); + log("iframe loaded"); - handler._detachLoadEvent(id); + var response = responseFromMessage ? responseFromMessage : getIframeContentJson(id, iframe); - //we can't remove an iframe if the iframe doesn't belong to the same domain - if (!options.cors.expected) { - qq(iframe).remove(); - } + handler._detachLoadEvent(id); - if (response.success) { - promise.success(response); - } - else { - promise.failure(response); - } - }); + //we can't remove an iframe if the iframe doesn't belong to the same domain + if (!options.cors.expected) { + qq(iframe).remove(); + } - log("Sending upload request for " + id); - form.submit(); - qq(form).remove(); + if (response.success) { + resolve(response); + } + else { + error = new Error("Failed to upload file"); + error.response = response; + reject(error); + } + }); - return promise; + log("Sending upload request for " + id); + form.submit(); + qq(form).remove(); + }); }; qq.extend(this, new qq.FormUploadHandler({ From 3e653bccc1d8fde0a83f39e17309b349bc7db06e Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 14:00:04 +1100 Subject: [PATCH 59/73] refactor: qq.Templating.showDialog to return Promise --- client/js/templating.js | 63 ++++++++++++++--------------- test/unit/submit-validate-cancel.js | 31 ++++++++------ 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/client/js/templating.js b/client/js/templating.js index d2a493aac..dc8c09cd2 100644 --- a/client/js/templating.js +++ b/client/js/templating.js @@ -1004,44 +1004,43 @@ qq.Templating = function(spec) { }, showDialog: function(type, message, defaultValue) { - var dialog = getDialog(type), - messageEl = getTemplateEl(dialog, selectorClasses.dialogMessage), - inputEl = dialog.getElementsByTagName("INPUT")[0], - cancelBtn = getTemplateEl(dialog, selectorClasses.dialogCancelButton), - okBtn = getTemplateEl(dialog, selectorClasses.dialogOkButton), - promise = new qq.Promise(), - - closeHandler = function() { - cancelBtn.removeEventListener("click", cancelClickHandler); - okBtn && okBtn.removeEventListener("click", okClickHandler); - promise.failure(); - }, - - cancelClickHandler = function() { - cancelBtn.removeEventListener("click", cancelClickHandler); - dialog.close(); - }, + return new Promise(function(resolve, reject) { + var dialog = getDialog(type), + messageEl = getTemplateEl(dialog, selectorClasses.dialogMessage), + inputEl = dialog.getElementsByTagName("INPUT")[0], + cancelBtn = getTemplateEl(dialog, selectorClasses.dialogCancelButton), + okBtn = getTemplateEl(dialog, selectorClasses.dialogOkButton), + + closeHandler = function() { + cancelBtn.removeEventListener("click", cancelClickHandler); + okBtn && okBtn.removeEventListener("click", okClickHandler); + reject(); + }, - okClickHandler = function() { - dialog.removeEventListener("close", closeHandler); - okBtn.removeEventListener("click", okClickHandler); - dialog.close(); + cancelClickHandler = function() { + cancelBtn.removeEventListener("click", cancelClickHandler); + dialog.close(); + }, - promise.success(inputEl && inputEl.value); - }; + okClickHandler = function() { + dialog.removeEventListener("close", closeHandler); + okBtn.removeEventListener("click", okClickHandler); + dialog.close(); - dialog.addEventListener("close", closeHandler); - cancelBtn.addEventListener("click", cancelClickHandler); - okBtn && okBtn.addEventListener("click", okClickHandler); + resolve(inputEl && inputEl.value); + }; - if (inputEl) { - inputEl.value = defaultValue; - } - messageEl.textContent = message; + dialog.addEventListener("close", closeHandler); + cancelBtn.addEventListener("click", cancelClickHandler); + okBtn && okBtn.addEventListener("click", okClickHandler); - dialog.showModal(); + if (inputEl) { + inputEl.value = defaultValue; + } + messageEl.textContent = message; - return promise; + dialog.showModal(); + }); } }); }; diff --git a/test/unit/submit-validate-cancel.js b/test/unit/submit-validate-cancel.js index 7408575df..e4577b75e 100644 --- a/test/unit/submit-validate-cancel.js +++ b/test/unit/submit-validate-cancel.js @@ -61,18 +61,20 @@ if (qqtest.canDownloadFileAsBlob) { qqtest.downloadFileAsBlob(testImgKey, testImgType).then(function(blob) { uploader.addFiles({blob: blob, name: expectedName}); - assert.deepEqual(callbackOrder, expectedCallbackOrder); - assert.deepEqual(statusChangeOrder, expectedStatusChangeOrder); - assert.equal(uploader.getName(0), expectedName); - assert.equal(uploader.getNetUploads(), 0); - assert.equal(uploader.getSize(0), expectedFileSize); - assert.equal(uploader.getUploads().length, 1); - assert.equal(uploader.getUploads({id: 0}).name, expectedName); - assert.equal(uploader.getUploads({id: 0}).originalName, expectedName); - assert.equal(uploader.getUploads({id: 0}).size, expectedFileSize); - assert.equal(uploader.getUploads({id: 0}).status, qq.status.SUBMITTED); - - done(); + setTimeout(function() { + assert.deepEqual(callbackOrder, expectedCallbackOrder); + assert.deepEqual(statusChangeOrder, expectedStatusChangeOrder); + assert.equal(uploader.getName(0), expectedName); + assert.equal(uploader.getNetUploads(), 0); + assert.equal(uploader.getSize(0), expectedFileSize); + assert.equal(uploader.getUploads().length, 1); + assert.equal(uploader.getUploads({id: 0}).name, expectedName); + assert.equal(uploader.getUploads({id: 0}).originalName, expectedName); + assert.equal(uploader.getUploads({id: 0}).size, expectedFileSize); + assert.equal(uploader.getUploads({id: 0}).status, qq.status.SUBMITTED); + + done(); + }, 0); }); }); @@ -94,7 +96,10 @@ if (qqtest.canDownloadFileAsBlob) { {blob: blob, name: "name1"}, {blob: blob, name: "name2"} ]); - done(); + + setTimeout(function() { + done(); + }, 0); }); }); From cab1b63e8caa954d646ab2ffb9fdfb187e37e10a Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 14:05:14 +1100 Subject: [PATCH 60/73] refactor: drawThumbnail to return Promise --- client/js/uploader.basic.api.js | 74 ++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 33 deletions(-) diff --git a/client/js/uploader.basic.api.js b/client/js/uploader.basic.api.js index 2c29f49e7..1a8a59dc6 100644 --- a/client/js/uploader.basic.api.js +++ b/client/js/uploader.basic.api.js @@ -167,48 +167,56 @@ }, // Generate a variable size thumbnail on an img or canvas, - // returning a promise that is fulfilled when the attempt completes. + // returning a promise that is resolved when the attempt completes. // Thumbnail can either be based off of a URL for an image returned // by the server in the upload response, or the associated `Blob`. drawThumbnail: function(fileId, imgOrCanvas, maxSize, fromServer, customResizeFunction) { - var promiseToReturn = new qq.Promise(), - fileOrUrl, options; + var self = this; - if (this._imageGenerator) { - fileOrUrl = this._thumbnailUrls[fileId]; - options = { - customResizeFunction: customResizeFunction, - maxSize: maxSize > 0 ? maxSize : null, - scale: maxSize > 0 - }; + return new Promise(function(resolve, reject) { + var fileOrUrl, options, error; - // If client-side preview generation is possible - // and we are not specifically looking for the image URl returned by the server... - if (!fromServer && qq.supportedFeatures.imagePreviews) { - fileOrUrl = this.getFile(fileId); - } + if (self._imageGenerator) { + fileOrUrl = self._thumbnailUrls[fileId]; + options = { + customResizeFunction: customResizeFunction, + maxSize: maxSize > 0 ? maxSize : null, + scale: maxSize > 0 + }; - /* jshint eqeqeq:false,eqnull:true */ - if (fileOrUrl == null) { - promiseToReturn.failure({container: imgOrCanvas, error: "File or URL not found."}); + // If client-side preview generation is possible + // and we are not specifically looking for the image URl returned by the server... + if (!fromServer && qq.supportedFeatures.imagePreviews) { + fileOrUrl = self.getFile(fileId); + } + + /* jshint eqeqeq:false,eqnull:true */ + if (fileOrUrl == null) { + error = new Error("File or URL not found."); + error.error = error.message; + error.container = imgOrCanvas; + reject(error); + } + else { + self._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then( + resolve, + + function failure(error) { + error = new Error(error.message || "Problem generating thumbnail"); + error.error = error.message; + error.container = error.container; + reject(error); + } + ); + } } else { - this._imageGenerator.generate(fileOrUrl, imgOrCanvas, options).then( - function success(modifiedContainer) { - promiseToReturn.success(modifiedContainer); - }, - - function failure(error) { - promiseToReturn.failure({container: error.container, error: error.message || "Problem generating thumbnail"}); - } - ); + error = new Error("Missing image generator module"); + error.error = error.message; + error.container = imgOrCanvas; + reject(error); } - } - else { - promiseToReturn.failure({container: imgOrCanvas, error: "Missing image generator module"}); - } - - return promiseToReturn; + }); }, getButton: function(fileId) { From c1fa3f3c271825a8e507e36160ecc940c45fd6e2 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 14:07:14 +1100 Subject: [PATCH 61/73] refactor: onComplete to use instanceof Promise --- client/js/uploader.basic.api.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/client/js/uploader.basic.api.js b/client/js/uploader.basic.api.js index 1a8a59dc6..a32ff3303 100644 --- a/client/js/uploader.basic.api.js +++ b/client/js/uploader.basic.api.js @@ -777,8 +777,10 @@ // If the internal `_onComplete` handler returns a promise, don't invoke the `onComplete` callback // until the promise has been fulfilled. - if (retVal instanceof qq.Promise) { - retVal.done(function() { + if (retVal instanceof Promise) { + retVal.then(function() { + self._options.callbacks.onComplete(id, name, result, xhr); + }, function() { self._options.callbacks.onComplete(id, name, result, xhr); }); } From fd6cb3305b979408a03fdbd8958f7029efbc049b Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 14:08:58 +1100 Subject: [PATCH 62/73] refactor: onCancel to return Promise --- client/js/uploader.basic.api.js | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/client/js/uploader.basic.api.js b/client/js/uploader.basic.api.js index a32ff3303..1cf677e12 100644 --- a/client/js/uploader.basic.api.js +++ b/client/js/uploader.basic.api.js @@ -789,23 +789,21 @@ } }, onCancel: function(id, name, cancelFinalizationEffort) { - var promise = new qq.Promise(); - - self._handleCheckedCallback({ - name: "onCancel", - callback: qq.bind(self._options.callbacks.onCancel, self, id, name), - onFailure: promise.failure, - onSuccess: function() { - cancelFinalizationEffort.then(function() { - self._onCancel(id, name); - }); - - promise.success(); - }, - identifier: id + return new Promise(function(resolve, reject) { + self._handleCheckedCallback({ + name: "onCancel", + callback: qq.bind(self._options.callbacks.onCancel, self, id, name), + onFailure: reject, + onSuccess: function() { + cancelFinalizationEffort.then(function() { + self._onCancel(id, name); + }); + + resolve(); + }, + identifier: id + }); }); - - return promise; }, onUploadPrep: qq.bind(this._onUploadPrep, this), onUpload: function(id, name) { From 4c8d4b3e2d604248aa34c1dacd54be5794de3a77 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 14:09:58 +1100 Subject: [PATCH 63/73] refactor: onUploadChunk to return Promise --- client/js/uploader.basic.api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/js/uploader.basic.api.js b/client/js/uploader.basic.api.js index 1cf677e12..e92a6157f 100644 --- a/client/js/uploader.basic.api.js +++ b/client/js/uploader.basic.api.js @@ -826,7 +826,7 @@ return onUploadChunkResult; } - return new qq.Promise().success(); + return Promise.resolve(); }, onUploadChunkSuccess: function(id, chunkData, result, xhr) { self._onUploadChunkSuccess(id, chunkData); From bad4382e04a47f62762065ac7274104700844f5b Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 15:31:32 +1100 Subject: [PATCH 64/73] refactor: generateHeaders to return Promise --- .../js/s3/multipart.abort.ajax.requester.js | 33 +--- .../s3/multipart.complete.ajax.requester.js | 8 +- .../s3/multipart.initiate.ajax.requester.js | 8 +- client/js/s3/request-signer.js | 167 +++++++++--------- client/js/s3/s3.xhr.upload.handler.js | 31 ++-- client/js/s3/util.js | 24 +-- .../upload.handler.controller.js | 2 +- test/unit/azure/simple-file-uploads.js | 15 ++ test/unit/s3/serverless-uploads.js | 15 ++ test/unit/s3/simple-file-uploads.js | 26 ++- test/unit/uploader.basic.api.js | 32 +++- 11 files changed, 206 insertions(+), 155 deletions(-) diff --git a/client/js/s3/multipart.abort.ajax.requester.js b/client/js/s3/multipart.abort.ajax.requester.js index 42b6d7628..19130a44e 100644 --- a/client/js/s3/multipart.abort.ajax.requester.js +++ b/client/js/s3/multipart.abort.ajax.requester.js @@ -42,31 +42,16 @@ qq.s3.AbortMultipartAjaxRequester = function(o) { * @returns {Promise} */ function getHeaders(id, uploadId) { - return new Promise(function(resolve, reject) { - options.getKey(id).then(function(key) { - var headers = {}, - bucket = options.getBucket(id), - host = options.getHost(id), - signatureConstructor = getSignatureAjaxRequester.constructStringToSign - (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_ABORT, bucket, host, key) - .withUploadId(uploadId); + return options.getKey(id).then(function(key) { + var headers = {}, + bucket = options.getBucket(id), + host = options.getHost(id), + signatureConstructor = getSignatureAjaxRequester.constructStringToSign + (getSignatureAjaxRequester.REQUEST_TYPE.MULTIPART_ABORT, bucket, host, key) + .withUploadId(uploadId); - // Ask the local server to sign the request. Use this signature to form the Authorization header. - getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then( - function (signedPolicy, updatedAccessKey, updatedSessionToken) { - resolve({ - signedPolicy: signedPolicy, - updatedAccessKey: updatedAccessKey, - updatedSessionToken: updatedSessionToken - }); - }, - function (reason) { - var error = new Error("Faild to get signature"); - error.error = reason; - reject(error); - } - ); - }); + // Ask the local server to sign the request. Use this signature to form the Authorization header. + return getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}); }); } diff --git a/client/js/s3/multipart.complete.ajax.requester.js b/client/js/s3/multipart.complete.ajax.requester.js index d101e946f..9d6b37824 100644 --- a/client/js/s3/multipart.complete.ajax.requester.js +++ b/client/js/s3/multipart.complete.ajax.requester.js @@ -54,13 +54,7 @@ qq.s3.CompleteMultipartAjaxRequester = function(o) { .withContentType("application/xml; charset=UTF-8"); // Ask the local server to sign the request. Use this signature to form the Authorization header. - return new Promise(function(resolve, reject) { - getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(function(headers, endOfUrl) { - resolve({headers: headers, endOfUrl: endOfUrl}); - }, function(errorReason) { - reject(new Error(errorReason)); - }); - }); + return getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}); }); } diff --git a/client/js/s3/multipart.initiate.ajax.requester.js b/client/js/s3/multipart.initiate.ajax.requester.js index d0390376c..08d11b289 100644 --- a/client/js/s3/multipart.initiate.ajax.requester.js +++ b/client/js/s3/multipart.initiate.ajax.requester.js @@ -83,13 +83,7 @@ qq.s3.InitiateMultipartAjaxRequester = function(o) { .withHeaders(headers); // Ask the local server to sign the request. Use this signature to form the Authorization header. - return new Promise(function(resolve, reject) { - getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}).then(function (headers, endOfUrl) { - resolve({headers: headers, endOfUrl: endOfUrl}); - }, function(errorReason) { - reject(new Error(errorReason)); - }); - }); + return getSignatureAjaxRequester.getSignature(id, {signatureConstructor: signatureConstructor}); }); } diff --git a/client/js/s3/request-signer.js b/client/js/s3/request-signer.js index 14a4251aa..b54b38f00 100644 --- a/client/js/s3/request-signer.js +++ b/client/js/s3/request-signer.js @@ -46,7 +46,7 @@ qq.s3.RequestSigner = function(o) { }, credentialsProvider, - generateHeaders = function(signatureConstructor, signature, promise) { + generateHeaders = function(signatureConstructor, signature) { var headers = signatureConstructor.getHeaders(); if (options.signatureSpec.version === 4) { @@ -62,7 +62,7 @@ qq.s3.RequestSigner = function(o) { headers.Authorization = "AWS " + options.signatureSpec.credentialsProvider.get().accessKey + ":" + signature; } - promise.success(headers, signatureConstructor.getEndOfUrl()); + return Promise.resolve({headers: headers, endOfUrl: signatureConstructor.getEndOfUrl()}); }, v2 = { @@ -76,25 +76,29 @@ qq.s3.RequestSigner = function(o) { signatureSpec.endOfUrl); }, - signApiRequest: function(signatureConstructor, headersStr, signatureEffort) { + signApiRequest: function(signatureConstructor, headersStr) { var headersWordArray = qq.CryptoJS.enc.Utf8.parse(headersStr), headersHmacSha1 = qq.CryptoJS.HmacSHA1(headersWordArray, credentialsProvider.get().secretKey), headersHmacSha1Base64 = qq.CryptoJS.enc.Base64.stringify(headersHmacSha1); - generateHeaders(signatureConstructor, headersHmacSha1Base64, signatureEffort); + return generateHeaders(signatureConstructor, headersHmacSha1Base64); }, - signPolicy: function(policy, signatureEffort, updatedAccessKey, updatedSessionToken) { + signPolicy: function(policy, updatedAccessKey, updatedSessionToken) { var policyStr = JSON.stringify(policy), policyWordArray = qq.CryptoJS.enc.Utf8.parse(policyStr), base64Policy = qq.CryptoJS.enc.Base64.stringify(policyWordArray), policyHmacSha1 = qq.CryptoJS.HmacSHA1(base64Policy, credentialsProvider.get().secretKey), policyHmacSha1Base64 = qq.CryptoJS.enc.Base64.stringify(policyHmacSha1); - signatureEffort.success({ - policy: base64Policy, - signature: policyHmacSha1Base64 - }, updatedAccessKey, updatedSessionToken); + return Promise.resolve({ + policyAndSignature: { + policy: base64Policy, + signature: policyHmacSha1Base64 + }, + updatedAccessKey: updatedAccessKey, + updatedSessionToken: updatedSessionToken + }); } }, @@ -210,7 +214,7 @@ qq.s3.RequestSigner = function(o) { return signedHeaders; }, - signApiRequest: function(signatureConstructor, headersStr, signatureEffort) { + signApiRequest: function(signatureConstructor, headersStr) { var secretKey = credentialsProvider.get().secretKey, headersPattern = /.+\n.+\n(\d+)\/(.+)\/s3\/.+\n(.+)/, matches = headersPattern.exec(headersStr), @@ -221,10 +225,10 @@ qq.s3.RequestSigner = function(o) { dateRegionServiceKey = qq.CryptoJS.HmacSHA256("s3", dateRegionKey); signingKey = qq.CryptoJS.HmacSHA256("aws4_request", dateRegionServiceKey); - generateHeaders(signatureConstructor, qq.CryptoJS.HmacSHA256(headersStr, signingKey), signatureEffort); + return generateHeaders(signatureConstructor, qq.CryptoJS.HmacSHA256(headersStr, signingKey)); }, - signPolicy: function(policy, signatureEffort, updatedAccessKey, updatedSessionToken) { + signPolicy: function(policy, updatedAccessKey, updatedSessionToken) { var policyStr = JSON.stringify(policy), policyWordArray = qq.CryptoJS.enc.Utf8.parse(policyStr), base64Policy = qq.CryptoJS.enc.Base64.stringify(policyWordArray), @@ -249,10 +253,14 @@ qq.s3.RequestSigner = function(o) { dateRegionServiceKey = qq.CryptoJS.HmacSHA256("s3", dateRegionKey); signingKey = qq.CryptoJS.HmacSHA256("aws4_request", dateRegionServiceKey); - signatureEffort.success({ - policy: base64Policy, - signature: qq.CryptoJS.HmacSHA256(base64Policy, signingKey).toString() - }, updatedAccessKey, updatedSessionToken); + return Promise.resolve({ + policyAndSignature: { + policy: base64Policy, + signature: qq.CryptoJS.HmacSHA256(base64Policy, signingKey).toString() + }, + updatedAccessKey: updatedAccessKey, + updatedSessionToken: updatedSessionToken + }); } }; @@ -311,13 +319,13 @@ qq.s3.RequestSigner = function(o) { options.log(errorMessage, "error"); } - promise.failure(errorMessage); + promise.reject(new Error(errorMessage)); } else if (signatureConstructor) { - generateHeaders(signatureConstructor, response.signature, promise); + generateHeaders(signatureConstructor, response.signature).then(promise.resolve, promise.reject); } else { - promise.success(response); + promise.resolve({policyAndSignature: response}); } } @@ -414,7 +422,7 @@ qq.s3.RequestSigner = function(o) { }); } - function determineSignatureClientSide(id, toBeSigned, signatureEffort, updatedAccessKey, updatedSessionToken) { + function determineSignatureClientSide(id, toBeSigned, updatedAccessKey, updatedSessionToken) { var updatedHeaders; // REST API request @@ -425,34 +433,32 @@ qq.s3.RequestSigner = function(o) { toBeSigned.signatureConstructor.withHeaders(updatedHeaders); } - toBeSigned.signatureConstructor.getToSign(id).then(function(signatureArtifacts) { - signApiRequest(toBeSigned.signatureConstructor, signatureArtifacts.stringToSign, signatureEffort); - }, function (err) { - signatureEffort.failure(err); + return toBeSigned.signatureConstructor.getToSign(id).then(function(signatureArtifacts) { + return signApiRequest(toBeSigned.signatureConstructor, signatureArtifacts.stringToSign); }); } // Form upload (w/ policy document) else { updatedSessionToken && qq.s3.util.refreshPolicyCredentials(toBeSigned, updatedSessionToken); - signPolicy(toBeSigned, signatureEffort, updatedAccessKey, updatedSessionToken); + return signPolicy(toBeSigned, updatedAccessKey, updatedSessionToken); } } - function signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken) { + function signPolicy(policy, updatedAccessKey, updatedSessionToken) { if (options.signatureSpec.version === 4) { - v4.signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken); + return v4.signPolicy(policy, updatedAccessKey, updatedSessionToken); } else { - v2.signPolicy(policy, signatureEffort, updatedAccessKey, updatedSessionToken); + return v2.signPolicy(policy, updatedAccessKey, updatedSessionToken); } } - function signApiRequest(signatureConstructor, headersStr, signatureEffort) { + function signApiRequest(signatureConstructor, headersStr) { if (options.signatureSpec.version === 4) { - v4.signApiRequest(signatureConstructor, headersStr, signatureEffort); + return v4.signApiRequest(signatureConstructor, headersStr); } else { - v2.signApiRequest(signatureConstructor, headersStr, signatureEffort); + return v2.signApiRequest(signatureConstructor, headersStr); } } @@ -475,69 +481,70 @@ qq.s3.RequestSigner = function(o) { qq.extend(this, { /** - * On success, an object containing the parsed JSON response will be passed into the success handler if the - * request succeeds. Otherwise an error message will be passed into the failure method. + * On success, an object containing the parsed JSON response will be + * used to resolve the promise. Otherwise it will be rejected with an + * error message. * * @param id File ID. * @param toBeSigned an Object that holds the item(s) to be signed - * @returns {qq.Promise} A promise that is fulfilled when the response has been received. + * @returns {Promise} A promise that is resolved when the response has + * been received. */ getSignature: function(id, toBeSigned) { - var params = toBeSigned, - signatureConstructor = toBeSigned.signatureConstructor, - signatureEffort = new qq.Promise(), - queryParams; + return new Promise(function(resolve, reject) { + var params = toBeSigned, + signatureConstructor = toBeSigned.signatureConstructor, + queryParams; - if (options.signatureSpec.version === 4) { - queryParams = {v4: true}; - } + if (options.signatureSpec.version === 4) { + queryParams = {v4: true}; + } - if (credentialsProvider.get().secretKey && qq.CryptoJS) { - if (credentialsProvider.get().expiration.getTime() > Date.now()) { - determineSignatureClientSide(id, toBeSigned, signatureEffort); + if (credentialsProvider.get().secretKey && qq.CryptoJS) { + if (credentialsProvider.get().expiration.getTime() > Date.now()) { + determineSignatureClientSide(id, toBeSigned).then(resolve, reject); + } + // If credentials are expired, ask for new ones before attempting to sign request + else { + credentialsProvider.onExpired().then(function() { + determineSignatureClientSide(id, toBeSigned, + credentialsProvider.get().accessKey, + credentialsProvider.get().sessionToken).then(resolve, reject); + }, function() { + options.log("Attempt to update expired credentials apparently failed! Unable to sign request. ", "error"); + reject(new Error("Unable to sign request - expired credentials.")); + }); + } } - // If credentials are expired, ask for new ones before attempting to sign request else { - credentialsProvider.onExpired().then(function() { - determineSignatureClientSide(id, toBeSigned, - signatureEffort, - credentialsProvider.get().accessKey, - credentialsProvider.get().sessionToken); - }, function() { - options.log("Attempt to update expired credentials apparently failed! Unable to sign request. ", "error"); - signatureEffort.failure("Unable to sign request - expired credentials."); - }); - } - } - else { - options.log("Submitting S3 signature request for " + id); - - if (signatureConstructor) { - signatureConstructor.getToSign(id).then(function(signatureArtifacts) { - params = {headers: signatureArtifacts.stringToSignRaw}; + options.log("Submitting S3 signature request for " + id); + + if (signatureConstructor) { + signatureConstructor.getToSign(id).then(function(signatureArtifacts) { + params = {headers: signatureArtifacts.stringToSignRaw}; + requester.initTransport(id) + .withParams(params) + .withQueryParams(queryParams) + .send(); + }, function (err) { + var error = new Error("Failed to construct signature."); + options.log(error.message, "error"); + reject(error); + }); + } + else { requester.initTransport(id) .withParams(params) .withQueryParams(queryParams) .send(); - }, function (err) { - options.log("Failed to construct signature. ", "error"); - signatureEffort.failure("Failed to construct signature."); - }); - } - else { - requester.initTransport(id) - .withParams(params) - .withQueryParams(queryParams) - .send(); - } - - pendingSignatures[id] = { - promise: signatureEffort, - signatureConstructor: signatureConstructor - }; - } + } - return signatureEffort; + pendingSignatures[id] = { + promise: {resolve: resolve, reject: reject}, + signatureConstructor: signatureConstructor + }; + } + }); }, constructStringToSign: function(type, bucket, host, key) { diff --git a/client/js/s3/s3.xhr.upload.handler.js b/client/js/s3/s3.xhr.upload.handler.js index b79bf8844..a59dc6811 100755 --- a/client/js/s3/s3.xhr.upload.handler.js +++ b/client/js/s3/s3.xhr.upload.handler.js @@ -80,25 +80,18 @@ qq.s3.XhrUploadHandler = function(spec, proxy) { * @returns {Promise} */ initHeaders: function(id, chunkIdx, blob) { - return new Promise(function(resolve, reject) { - upload.key.urlSafe(id).then(function(key) { - var headers = {}, - bucket = upload.bucket.getName(id), - host = upload.host.getName(id), - signatureConstructor = requesters.restSignature.constructStringToSign - (requesters.restSignature.REQUEST_TYPE.MULTIPART_UPLOAD, bucket, host, key) - .withPartNum(chunkIdx + 1) - .withContent(blob) - .withUploadId(handler._getPersistableData(id).uploadId); - - // Ask the local server to sign the request. Use this signature to form the Authorization header. - requesters.restSignature.getSignature(id + "." + chunkIdx, {signatureConstructor: signatureConstructor}).then( - function (headers, endOfUrl) { - resolve({headers: headers, endOfUrl: endOfUrl}); - }, function() { - reject(); - }); - }); + return upload.key.urlSafe(id).then(function(key) { + var headers = {}, + bucket = upload.bucket.getName(id), + host = upload.host.getName(id), + signatureConstructor = requesters.restSignature.constructStringToSign + (requesters.restSignature.REQUEST_TYPE.MULTIPART_UPLOAD, bucket, host, key) + .withPartNum(chunkIdx + 1) + .withContent(blob) + .withUploadId(handler._getPersistableData(id).uploadId); + + // Ask the local server to sign the request. Use this signature to form the Authorization header. + return requesters.restSignature.getSignature(id + "." + chunkIdx, {signatureConstructor: signatureConstructor}); }); }, diff --git a/client/js/s3/util.js b/client/js/s3/util.js index a360d5167..19aa4eb31 100644 --- a/client/js/s3/util.js +++ b/client/js/s3/util.js @@ -317,30 +317,30 @@ qq.s3.util = qq.s3.util || (function() { // Invoke a promissory callback that should provide us with a base64-encoded policy doc and an // HMAC signature for the policy doc. signPolicyCallback(policyJson).then( - function(policyAndSignature, updatedAccessKey, updatedSessionToken) { - awsParams.policy = policyAndSignature.policy; + function(info) { + awsParams.policy = info.policyAndSignature.policy; if (spec.signatureVersion === 2) { - awsParams.signature = policyAndSignature.signature; + awsParams.signature = info.policyAndSignature.signature; - if (updatedAccessKey) { - awsParams.AWSAccessKeyId = updatedAccessKey; + if (info.updatedAccessKey) { + awsParams.AWSAccessKeyId = info.updatedAccessKey; } } else if (spec.signatureVersion === 4) { - awsParams[qq.s3.util.V4_SIGNATURE_PARAM_NAME] = policyAndSignature.signature; + awsParams[qq.s3.util.V4_SIGNATURE_PARAM_NAME] = info.policyAndSignature.signature; } - if (updatedSessionToken) { - awsParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = updatedSessionToken; + if (info.updatedSessionToken) { + awsParams[qq.s3.util.SESSION_TOKEN_PARAM_NAME] = info.updatedSessionToken; } resolve(awsParams); }, - function(errorMessage) { - var error = new Error(errorMessage || "Can't continue further with request to S3 as we did not receive " + - "a valid signature and policy from the server."); - error.error = errorMessage; + function(err) { + var error = new Error(err.message || "Can't continue further with request to S3 as we did not receive " + + "a valid signature and policy from the server."); + error.error = err.error; log("Policy signing failed. " + error.message, "error"); reject(error); } diff --git a/client/js/upload-handler/upload.handler.controller.js b/client/js/upload-handler/upload.handler.controller.js index 6434163c6..24f611a01 100644 --- a/client/js/upload-handler/upload.handler.controller.js +++ b/client/js/upload-handler/upload.handler.controller.js @@ -418,7 +418,7 @@ qq.UploadHandlerController = function(o, namespace) { var optXhr = error.xhr; log("Simple upload request failed for " + id); - var responseToReport = upload.normalizeResponse({error: error.error, azureError: error.azureError}, false); + var responseToReport = upload.normalizeResponse({error: error.error || error.message, azureError: error.azureError}, false); if (!options.onAutoRetry(id, name, responseToReport, optXhr)) { upload.cleanup(id, responseToReport, optXhr); diff --git a/test/unit/azure/simple-file-uploads.js b/test/unit/azure/simple-file-uploads.js index 1d4a7a9b4..aa72522cd 100644 --- a/test/unit/azure/simple-file-uploads.js +++ b/test/unit/azure/simple-file-uploads.js @@ -135,6 +135,21 @@ if (qqtest.canDownloadFileAsBlob) { }); } + it("Promise", function(done) { + var uploader = new qq.azure.FineUploaderBasic({ + request: {endpoint: testEndpoint}, + signature: {endpoint: testSignatureEndoint}, + blobProperties: { + name: function(id) { + return Promise.resolve(id + "_blobname"); + } + } + } + ); + + runTest(uploader, done); + }); + it("qq.Promise", function(done) { var uploader = new qq.azure.FineUploaderBasic({ request: {endpoint: testEndpoint}, diff --git a/test/unit/s3/serverless-uploads.js b/test/unit/s3/serverless-uploads.js index 1caea4e8b..45854b0f6 100644 --- a/test/unit/s3/serverless-uploads.js +++ b/test/unit/s3/serverless-uploads.js @@ -245,6 +245,21 @@ describe("S3 serverless upload tests", function() { }); } + it("Promise", function(done) { + var callback = function() { + assert.ok(true); + + return Promise.resolve({ + accessKey: testAccessKeyFromCallback, + secretKey: testSecretKey, + expiration: new Date(Date.now() + 10000), + sessionToken: testSessionTokenFromCallback + }); + }; + + runTest(callback, done); + }); + it("qq.Promise", function(done) { var callback = function() { assert.ok(true); diff --git a/test/unit/s3/simple-file-uploads.js b/test/unit/s3/simple-file-uploads.js index d99aca34d..a477d21d7 100644 --- a/test/unit/s3/simple-file-uploads.js +++ b/test/unit/s3/simple-file-uploads.js @@ -453,6 +453,14 @@ if (qqtest.canDownloadFileAsBlob) { }); } + it("Promise", function(done) { + var keyFunc = function(id) { + return Promise.resolve(customKeyPrefix + this.getName(id)); + }; + + runTest(keyFunc, done); + }); + it("qq.Promise", function(done) { var keyFunc = function(id) { return new qq.Promise().success(customKeyPrefix + this.getName(id)); @@ -491,6 +499,14 @@ if (qqtest.canDownloadFileAsBlob) { }); } + it("Promise", function(done) { + var keyFunc = function() { + return Promise.reject(); + }; + + runTest(keyFunc, done); + }); + it("qq.Promise", function(done) { var keyFunc = function() { return new qq.Promise().failure(); @@ -533,6 +549,14 @@ if (qqtest.canDownloadFileAsBlob) { }); } + it("Promise", function(done) { + var keyFunc = function() { + return Promise.reject("oops"); + }; + + runTest(keyFunc, done); + }); + it("qq.Promise", function(done) { var keyFunc = function() { return new qq.Promise().failure("oops"); @@ -541,7 +565,7 @@ if (qqtest.canDownloadFileAsBlob) { runTest(keyFunc, done); }); - it("qq.Promise", function(done) { + it("Q.js", function(done) { var keyFunc = function() { return Q.reject("oops"); }; diff --git a/test/unit/uploader.basic.api.js b/test/unit/uploader.basic.api.js index 056eb691b..5ce9e7683 100644 --- a/test/unit/uploader.basic.api.js +++ b/test/unit/uploader.basic.api.js @@ -242,7 +242,19 @@ describe("uploader.basic.api.js", function () { fineuploader._handleCheckedCallback(spec); } - it ("qq.Promise", function(done) { + it("Promise", function(done) { + var callback = function() { + return new Promise(function(resolve) { + setTimeout(function() { + resolve("foobar"); + }, 100); + }); + }; + + runTest(callback, done); + }); + + it("qq.Promise", function(done) { var callback = function() { var promise = new qq.Promise(); @@ -256,7 +268,7 @@ describe("uploader.basic.api.js", function () { runTest(callback, done); }); - it ("Q.js", function(done) { + it("Q.js", function(done) { var callback = function() { return Q.Promise(function(resolve) { setTimeout(function() { @@ -285,7 +297,19 @@ describe("uploader.basic.api.js", function () { fineuploader._handleCheckedCallback(spec); } - it ("qq.Promise", function(done) { + it("Promise", function(done) { + var callback = function() { + return new Promise(function(resolve, reject) { + setTimeout(function() { + reject(); + }, 100); + }); + }; + + runTest(callback, done); + }); + + it("qq.Promise", function(done) { var callback = function() { var promise = new qq.Promise(); @@ -299,7 +323,7 @@ describe("uploader.basic.api.js", function () { runTest(callback, done); }); - it ("Q.js", function(done) { + it("Q.js", function(done) { var callback = function() { return Q.Promise(function (resolve, reject) { setTimeout(function () { From 3c7b3ed832627c6561489f8a70b1e1bd39850fd6 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 15:45:11 +1100 Subject: [PATCH 65/73] refactor: qq.Templating to use Promise --- client/js/templating.js | 170 +++++++++++++++++++++------------------- 1 file changed, 89 insertions(+), 81 deletions(-) diff --git a/client/js/templating.js b/client/js/templating.js index dc8c09cd2..a77ff8a1e 100644 --- a/client/js/templating.js +++ b/client/js/templating.js @@ -85,8 +85,8 @@ qq.Templating = function(spec) { thumbnail: "qq-thumbnail-selector" }, previewGeneration = {}, - cachedThumbnailNotAvailableImg = new qq.Promise(), - cachedWaitingForThumbnailImg = new qq.Promise(), + cachedThumbnailNotAvailableImg, + cachedWaitingForThumbnailImg, log, isEditElementsExist, isRetryElementExist, @@ -108,66 +108,68 @@ qq.Templating = function(spec) { }; if (showThumbnails) { - if (notAvailableUrl) { - options.imageGenerator.generate(notAvailableUrl, new Image(), spec).then( - function(updatedImg) { - cachedThumbnailNotAvailableImg.success(updatedImg); - }, - function() { - cachedThumbnailNotAvailableImg.failure(); - log("Problem loading 'not available' placeholder image at " + notAvailableUrl, "error"); - } - ); - } - else { - cachedThumbnailNotAvailableImg.failure(); - } + cachedThumbnailNotAvailableImg = new Promise(function(resolve, reject) { + if (notAvailableUrl) { + options.imageGenerator.generate(notAvailableUrl, new Image(), spec).then( + function(updatedImg) { + resolve(updatedImg); + }, + function() { + reject(); + log("Problem loading 'not available' placeholder image at " + notAvailableUrl, "error"); + } + ); + } + else { + reject(); + } + }); - if (waitingUrl) { - options.imageGenerator.generate(waitingUrl, new Image(), spec).then( - function(updatedImg) { - cachedWaitingForThumbnailImg.success(updatedImg); - }, - function() { - cachedWaitingForThumbnailImg.failure(); - log("Problem loading 'waiting for thumbnail' placeholder image at " + waitingUrl, "error"); - } - ); - } - else { - cachedWaitingForThumbnailImg.failure(); - } + cachedWaitingForThumbnailImg = new Promise(function(resolve, reject) { + if (waitingUrl) { + options.imageGenerator.generate(waitingUrl, new Image(), spec).then( + function(updatedImg) { + resolve(updatedImg); + }, + function() { + reject(); + log("Problem loading 'waiting for thumbnail' placeholder image at " + waitingUrl, "error"); + } + ); + } + else { + reject(); + } + }); } }, // Displays a "waiting for thumbnail" type placeholder image // iff we were able to load it during initialization of the templating module. displayWaitingImg = function(thumbnail) { - var waitingImgPlacement = new qq.Promise(); - - cachedWaitingForThumbnailImg.then(function(img) { - maybeScalePlaceholderViaCss(img, thumbnail); - /* jshint eqnull:true */ - if (!thumbnail.src) { - thumbnail.src = img.src; - thumbnail.onload = function() { - thumbnail.onload = null; - show(thumbnail); - waitingImgPlacement.success(); - }; - } - else { - waitingImgPlacement.success(); - } - }, function() { - // In some browsers (such as IE9 and older) an img w/out a src attribute - // are displayed as "broken" images, so we should just hide the img tag - // if we aren't going to display the "waiting" placeholder. - hide(thumbnail); - waitingImgPlacement.success(); + return new Promise(function(resolve) { + cachedWaitingForThumbnailImg.then(function(img) { + maybeScalePlaceholderViaCss(img, thumbnail); + /* jshint eqnull:true */ + if (!thumbnail.src) { + thumbnail.src = img.src; + thumbnail.onload = function() { + thumbnail.onload = null; + show(thumbnail); + resolve(); + }; + } + else { + resolve(); + } + }, function() { + // In some browsers (such as IE9 and older) an img w/out a src attribute + // are displayed as "broken" images, so we should just hide the img tag + // if we aren't going to display the "waiting" placeholder. + hide(thumbnail); + resolve(); + }); }); - - return waitingImgPlacement; }, generateNewPreview = function(id, blob, spec) { @@ -180,10 +182,10 @@ qq.Templating = function(spec) { function() { generatedThumbnails++; show(thumbnail); - previewGeneration[id].success(); + previewGeneration[id].resolve(); }, function() { - previewGeneration[id].failure(); + previewGeneration[id].reject(); // Display the "not available" placeholder img only if we are // not expecting a thumbnail at a later point, such as in a server response. @@ -303,29 +305,28 @@ qq.Templating = function(spec) { // iff we were able to load this placeholder during initialization // of the templating module or after preview generation has failed. maybeSetDisplayNotAvailableImg = function(id, thumbnail) { - var previewing = previewGeneration[id] || new qq.Promise().failure(), - notAvailableImgPlacement = new qq.Promise(); + var previewing = previewGeneration[id] || Promise.reject(); - cachedThumbnailNotAvailableImg.then(function(img) { - previewing.then( - function() { - notAvailableImgPlacement.success(); - }, - function() { - maybeScalePlaceholderViaCss(img, thumbnail); + return new Promise(function(resolve) { + cachedThumbnailNotAvailableImg.then(function(img) { + previewing.then( + function() { + resolve(); + }, + function() { + maybeScalePlaceholderViaCss(img, thumbnail); - thumbnail.onload = function() { - thumbnail.onload = null; - notAvailableImgPlacement.success(); - }; + thumbnail.onload = function() { + thumbnail.onload = null; + resolve(); + }; - thumbnail.src = img.src; - show(thumbnail); - } - ); + thumbnail.src = img.src; + show(thumbnail); + } + ); + }); }); - - return notAvailableImgPlacement; }, /** @@ -499,12 +500,19 @@ qq.Templating = function(spec) { generateNextQueuedPreview(); } else { - displayWaitingImg(thumbnail).done(function() { - previewGeneration[id] = new qq.Promise(); + displayWaitingImg(thumbnail).then(function() { + var promise = new Promise(function(resolve, reject) { + promise.resolve = resolve; + promise.reject = reject; + }); - previewGeneration[id].done(function() { + previewGeneration[id] = promise; + + function onFinally() { setTimeout(generateNextQueuedPreview, options.limits.timeBetweenThumbs); - }); + } + + previewGeneration[id].then(onFinally, onFinally); /* jshint eqnull: true */ // If we've already generated an for this file, use the one that exists, @@ -600,13 +608,13 @@ qq.Templating = function(spec) { // Generation of the related thumbnail may still be in progress, so, wait until it is done. previewGeneration[cachedThumbnailId].then(function() { generatedThumbnails++; - previewGeneration[targetThumbnailId].success(); + previewGeneration[targetThumbnailId].resolve(); log(qq.format("Now using previously generated thumbnail created for ID {} on ID {}.", cachedThumbnailId, targetThumbnailId)); targetThumbnail.src = cachedThumbnail.src; show(targetThumbnail); }, function() { - previewGeneration[targetThumbnailId].failure(); + previewGeneration[targetThumbnailId].reject(); if (!options.placeholders.waitUntilUpdate) { maybeSetDisplayNotAvailableImg(targetThumbnailId, targetThumbnail); } From 5d6bf6d3e20b8cd67033e6b4beeb47be0a875dce Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 15:51:57 +1100 Subject: [PATCH 66/73] refactor: qq.UploadSuccessAjaxRequester.sendSuccessRequest to use Promise --- .../uploader.basic.api.js | 5 +- client/js/uploadsuccess.ajax.requester.js | 48 +++++++++++-------- test/unit/s3/simple-file-uploads.js | 12 +++-- 3 files changed, 38 insertions(+), 27 deletions(-) diff --git a/client/js/non-traditional-common/uploader.basic.api.js b/client/js/non-traditional-common/uploader.basic.api.js index 1fec08307..c135f36da 100644 --- a/client/js/non-traditional-common/uploader.basic.api.js +++ b/client/js/non-traditional-common/uploader.basic.api.js @@ -74,8 +74,9 @@ }, // If the upload success request fails, attempt to re-send the success request (via the core retry code). // The entire upload may be restarted if the server returns a "reset" property with a value of true as well. - function(successRequestResult) { - var callback = submitSuccessRequest, + function(err) { + var successRequestResult = err.response, + callback = submitSuccessRequest, error; qq.extend(result, successRequestResult); diff --git a/client/js/uploadsuccess.ajax.requester.js b/client/js/uploadsuccess.ajax.requester.js index 398839244..b83f55d0e 100644 --- a/client/js/uploadsuccess.ajax.requester.js +++ b/client/js/uploadsuccess.ajax.requester.js @@ -32,7 +32,8 @@ qq.UploadSuccessAjaxRequester = function(o) { responseJson = xhrOrXdr.responseText, successIndicator = {success: true}, failureIndicator = {success: false}, - parsedResponse; + parsedResponse, + error; delete pendingRequests[id]; @@ -46,23 +47,27 @@ qq.UploadSuccessAjaxRequester = function(o) { // since XDomainRequest (used in IE9 and IE8) doesn't give you access to the // response body for an "error" response. if (isError || (parsedResponse && (parsedResponse.error || parsedResponse.success === false))) { - options.log("Upload success request was rejected by the server.", "error"); - promise.failure(qq.extend(parsedResponse, failureIndicator)); + error = new Error("Upload success request was rejected by the server."); + error.response = qq.extend(parsedResponse, failureIndicator); + options.log(error.message, "error"); + promise.reject(error); } else { options.log("Upload success was acknowledged by the server."); - promise.success(qq.extend(parsedResponse, successIndicator)); + promise.resolve(qq.extend(parsedResponse, successIndicator)); } } - catch (error) { + catch (e) { // This will be executed if a JSON response is not present. This is not mandatory, so account for this properly. if (isError) { - options.log(qq.format("Your server indicated failure in its upload success request response for id {}!", id), "error"); - promise.failure(failureIndicator); + error = new Error(qq.format("Your server indicated failure in its upload success request response for id {}!", id)); + error.response = failureIndicator; + options.log(error.message, "error"); + promise.reject(error); } else { options.log("Upload success was acknowledged by the server."); - promise.success(successIndicator); + promise.resolve(successIndicator); } } } @@ -85,26 +90,27 @@ qq.UploadSuccessAjaxRequester = function(o) { qq.extend(this, { /** - * Sends a request to the server, notifying it that a recently submitted file was successfully sent. + * Sends a request to the server, notifying it that a recently submitted + * file was successfully sent. * * @param id ID of the associated file - * @param spec `Object` with the properties that correspond to important values that we want to - * send to the server with this request. - * @returns {qq.Promise} A promise to be fulfilled when the response has been received and parsed. The parsed - * payload of the response will be passed into the `failure` or `success` promise method. + * @param spec `Object` with the properties that correspond to important + * values that we want to send to the server with this request. + * @returns {Promise} A promise to be resolved when the response has + * been received and parsed. The promise will be resolved with the + * parsed payload of the response on success, or will be rejected with + * an Error with a `response` property. */ sendSuccessRequest: function(id, spec) { - var promise = new qq.Promise(); - options.log("Submitting upload success request/notification for " + id); - requester.initTransport(id) - .withParams(spec) - .send(); - - pendingRequests[id] = promise; + return new Promise(function(resolve, reject) { + pendingRequests[id] = {resolve: resolve, reject: reject}; - return promise; + requester.initTransport(id) + .withParams(spec) + .send(); + }); } }); }; diff --git a/test/unit/s3/simple-file-uploads.js b/test/unit/s3/simple-file-uploads.js index a477d21d7..ed376c0c6 100644 --- a/test/unit/s3/simple-file-uploads.js +++ b/test/unit/s3/simple-file-uploads.js @@ -735,9 +735,11 @@ if (qqtest.canDownloadFileAsBlob) { assert.equal(uploadSuccessRequestParsedBody.etag, "123"); uploadSuccessRequest.respond(200, null, null); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + setTimeout(function () { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + done(); + }, 0); }); }, 0); }, 0); @@ -796,9 +798,11 @@ if (qqtest.canDownloadFileAsBlob) { uploadSuccessRequest = fileTestHelper.getRequests()[2]; assert.equal(uploadSuccessRequest.method, "PUT"); uploadSuccessRequest.respond(200, null, null); - assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); + setTimeout(function() { + assert.equal(uploader.getUploads()[0].status, qq.status.UPLOAD_SUCCESSFUL); - done(); + done(); + }, 0); }, 0); }); }); From d74ba0b90f4f521c8d44e770b6f683eeedc50d05 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 15:58:18 +1100 Subject: [PATCH 67/73] refactor: _validateFileOrBlobData to use Promise --- client/js/uploader.basic.api.js | 74 +++++++++++++---------------- test/unit/on-all-complete.js | 4 +- test/unit/submit-validate-cancel.js | 8 ++-- 3 files changed, 41 insertions(+), 45 deletions(-) diff --git a/client/js/uploader.basic.api.js b/client/js/uploader.basic.api.js index e92a6157f..423a5215f 100644 --- a/client/js/uploader.basic.api.js +++ b/client/js/uploader.basic.api.js @@ -1895,7 +1895,7 @@ * * @param fileWrapper Wrapper containing a `file` along with an `id` * @param validationDescriptor Normalized information about the item (`size`, `name`). - * @returns qq.Promise with appropriate callbacks invoked depending on the validity of the file + * @returns {Promise} with appropriate callbacks invoked depending on the validity of the file * @private */ _validateFileOrBlobData: function(fileWrapper, validationDescriptor) { @@ -1910,47 +1910,39 @@ size = validationDescriptor.size, buttonId = this._getButtonId(fileWrapper.file), validationBase = this._getValidationBase(buttonId), - validityChecker = new qq.Promise(); - - validityChecker.then( - function() {}, - function() { - self._fileOrBlobRejected(fileWrapper.id, name); - }); - - if (qq.isFileOrInput(file) && !this._isAllowedExtension(validationBase.allowedExtensions, name)) { - this._itemError("typeError", name, file); - return validityChecker.failure(); - } - - if (!this._options.validation.allowEmpty && size === 0) { - this._itemError("emptyError", name, file); - return validityChecker.failure(); - } - - if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) { - this._itemError("sizeError", name, file); - return validityChecker.failure(); - } - - if (size > 0 && size < validationBase.minSizeLimit) { - this._itemError("minSizeError", name, file); - return validityChecker.failure(); - } + validityChecker; + + validityChecker = new Promise(function(resolve, reject) { + if (qq.isFileOrInput(file) && !self._isAllowedExtension(validationBase.allowedExtensions, name)) { + self._itemError("typeError", name, file); + reject(); + } else if (!self._options.validation.allowEmpty && size === 0) { + self._itemError("emptyError", name, file); + reject(); + } else if (size > 0 && validationBase.sizeLimit && size > validationBase.sizeLimit) { + self._itemError("sizeError", name, file); + reject(); + } else if (size > 0 && size < validationBase.minSizeLimit) { + self._itemError("minSizeError", name, file); + reject(); + } else if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) { + new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then( + resolve, + function(error) { + var errorCode = error.failingLimit; + self._itemError(errorCode + "ImageError", name, file); + reject(); + } + ); + } + else { + resolve(); + } + }); - if (qq.ImageValidation && qq.supportedFeatures.imagePreviews && qq.isFile(file)) { - new qq.ImageValidation(file, qq.bind(self.log, self)).validate(validationBase.image).then( - validityChecker.success, - function(error) { - var errorCode = error.failingLimit; - self._itemError(errorCode + "ImageError", name, file); - validityChecker.failure(); - } - ); - } - else { - validityChecker.success(); - } + validityChecker.catch(function() { + self._fileOrBlobRejected(fileWrapper.id, name); + }); return validityChecker; }, diff --git a/test/unit/on-all-complete.js b/test/unit/on-all-complete.js index 0fe3e1341..08139899e 100644 --- a/test/unit/on-all-complete.js +++ b/test/unit/on-all-complete.js @@ -267,7 +267,9 @@ if (qqtest.canDownloadFileAsBlob) { uploader.addFiles([blob, blob]); setTimeout(function() { - assert.deepEqual(callbackOrder, ["submit", "submit"]); + setTimeout(function() { + assert.deepEqual(callbackOrder, ["submit", "submit"]); + }, 0); }, 0); }); }); diff --git a/test/unit/submit-validate-cancel.js b/test/unit/submit-validate-cancel.js index e4577b75e..5d77e77b5 100644 --- a/test/unit/submit-validate-cancel.js +++ b/test/unit/submit-validate-cancel.js @@ -189,10 +189,12 @@ if (qqtest.canDownloadFileAsBlob) { qqtest.downloadFileAsBlob(testImgKey, testImgType).then(function(blob) { var uploader = setupUploader("submit", blob); - assert.equal(uploader.getUploads().length, 1, "Wrong number of uploads"); - assert.equal(uploader.getUploads({id: 0}).status, qq.status.REJECTED, "Wrong status"); + setTimeout(function() { + assert.equal(uploader.getUploads().length, 1, "Wrong number of uploads"); + assert.equal(uploader.getUploads({id: 0}).status, qq.status.REJECTED, "Wrong status"); - done(); + done(); + }, 0); }); }); From 23f5ed49055a357b08f105354b06e5fdf7bc3c57 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 16:03:08 +1100 Subject: [PATCH 68/73] refactor: qq.UploadHandler.cancel to use Promise --- client/js/upload-handler/upload.handler.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/client/js/upload-handler/upload.handler.js b/client/js/upload-handler/upload.handler.js index 7eab0b514..a6fd9b2a7 100644 --- a/client/js/upload-handler/upload.handler.js +++ b/client/js/upload-handler/upload.handler.js @@ -20,7 +20,10 @@ qq.UploadHandler = function(spec) { cancel: function(id) { var self = this, - cancelFinalizationEffort = new qq.Promise(), + resolveCancelFinalizationEffort, + cancelFinalizationEffort = new Promise(function(resolve) { + resolveCancelFinalizationEffort = resolve; + }), onCancelRetVal = onCancel(id, getName(id), cancelFinalizationEffort); onCancelRetVal.then(function() { @@ -28,7 +31,7 @@ qq.UploadHandler = function(spec) { fileState[id].canceled = true; self.expunge(id); } - cancelFinalizationEffort.success(); + resolveCancelFinalizationEffort(); }); }, From 5d63d392a84e352d80129d67ab62dcc851bfac8b Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 16:09:28 +1100 Subject: [PATCH 69/73] refactor: docs to use Promise --- client/typescript/fine-uploader.d.ts | 4 +- docs/api/options-azure.jmd | 2 +- docs/features/async-tasks-and-promises.jmd | 80 +--------------------- docs/features/paste-to-upload.jmd | 2 +- 4 files changed, 7 insertions(+), 81 deletions(-) diff --git a/client/typescript/fine-uploader.d.ts b/client/typescript/fine-uploader.d.ts index c687309ca..0c0ab7182 100644 --- a/client/typescript/fine-uploader.d.ts +++ b/client/typescript/fine-uploader.d.ts @@ -2875,7 +2875,7 @@ declare module "fine-uploader/lib/azure" { * * `function` * * If the value is a function, Fine Uploader Azure will pass the associated file ID as a parameter when invoking your function. - * If the value is a function it may return one of a `qq.Promise` or a `String` + * If the value is a function it may return one of a `Promise` or a `String` * * @default `'uuid'` */ @@ -3636,4 +3636,4 @@ declare module "fine-uploader/lib/s3" { } } -} \ No newline at end of file +} diff --git a/docs/api/options-azure.jmd b/docs/api/options-azure.jmd index f731f1e08..079fed766 100644 --- a/docs/api/options-azure.jmd +++ b/docs/api/options-azure.jmd @@ -53,7 +53,7 @@ alert("The [`chunking.paramNames` option](options.html#chunking) does **not** ap {{ api_parent_option("blobProperties", "blobProperties", "", ( - ("blobProperties.name", "name", "Describes the blob name used to identify the file in your Azure Blob Storage container. Possible values are 'uuid', 'filename' or a function. If the value is a function, Fine Uploader Azure will pass the associated file ID as a parameter when invoking your function. If the value is a function it may return one of a [`qq.Promise`](../features/async-tasks-and-promises.html) or a `String`.", "String or Function", "uuid",), + ("blobProperties.name", "name", "Describes the blob name used to identify the file in your Azure Blob Storage container. Possible values are 'uuid', 'filename' or a function. If the value is a function, Fine Uploader Azure will pass the associated file ID as a parameter when invoking your function. If the value is a function it may return one of a `Promise` or a `String`.", "String or Function", "uuid",), ) )}} diff --git a/docs/features/async-tasks-and-promises.jmd b/docs/features/async-tasks-and-promises.jmd index ec6ec45a0..002f76d5d 100644 --- a/docs/features/async-tasks-and-promises.jmd +++ b/docs/features/async-tasks-and-promises.jmd @@ -15,10 +15,7 @@ In some cases, Fine Uploader uses "promises", both internally and via the API. Promises are a design pattern taken from the functional programming style and are extremely helpful when dealing with asynchronous operations. -Fine Uploader's support for promises is encapsulated in the `qq.Promise` module. Starting with version 5.0, you -can use any A+ certified promise implementation to communicate with Fine Uploader as well. That is, you are -no longer bound to `qq.Promise`. Instead, you can use [Q][q], or [RSVP][rsvp], for example, to return promises from any -promissory callback handlers. +Starting with version 6.0, Fine Uploader supports native promises. For more information on promises in JavaScript, have a look at [Promises -- an alternative way to approach asynchronous JavaScript](http://12devs.co.uk/articles/promises-an-alternative-way-to-approach-asynchronous-javascript/). @@ -27,8 +24,8 @@ For more information on promises in JavaScript, have a look at Promises are acceptable return values in the following [event handlers](../api/events.html). Many of these callbacks can also prevent an associated action from being executed -with a false return value (non-promise) or a call to `failure()` on a returned -promise instance (see individual event docs for more details): +with a false return value (non-promise) or by returning a rejected promise (see +individual event docs for more details): * `onCancel` * `onCredentialsExpired` @@ -47,77 +44,6 @@ any of the above callbacks if you need to execute some non-blocking task, such as an AJAX request, or asking the user for input via a modal window that does not block the UI thread (such as a Bootstrap modal, or a Bootbox.js dialog box). -## qq.Promise API - -{{ alert( -"""Fine Uploader's internal `qq.Promise` object is _not_ compliant with the A+ specification. If this is a problem for you, -feel free to use any compliant promise library of your choice instead.""", "info", "Note:") }} - -{% endmarkdown %} -{{ api_method("then", "then (successCallback, failureCallback)", "Register callbacks from success *and* failure. The promise instance that `then` is called on will pass any values into the provided callbacks. If success or failure have already occurred before these callbacks have been registered, then they will be called immediately after this call has been executed. Each subsequent call to `then` registers an additional set of callbacks.", -[ - { - "name": "successCallback", - "type": "Function", - "description": "The function to call when the promise is successfully fulfilled." - }, - { - "name": "failureCallback", - "type": "Function", - "description": "The function to call when the promise is unsuccessfully fulfilled." - } -], -[ - { - "type": "qq.Promise", - "description": "An instance of a promise." - } -]) }} - -{{ api_method("done", "done (callback)", "Register callbacks for success *or* failure. Invoked when the promise is fulfilled regardless of the result. The promise instance that `done` is called on will pass any values into the provided callback. Each call to `done` registers an additional set of callbacks", -[ - { - "name": "callback", - "type": "Function", - "description": "The function to call when the promise is fulfilled, successful or not." - }, -], -[ - { - "type": "qq.Promise", - "description": "An instance of a promise." - } -]) }} -{{ api_method("success", "success (param)", "Call this on a promise to indicate success. The parameter value will depend on the situation.", -[ - { - "name": "param", - "type": "Object", - "description": "The value to pass to the promise's success handler." - }, -], -[ - { - "type": "qq.Promise", - "description": "An instance of a promise." - } -]) }} -{{ api_method("failure", "failure (param)", "Call this on a promise to indicate failure. The parameter value will depend on the situation.", -[ - { - "name": "param", - "type": "Object", - "description": "The value to pass to the promise's failure handler." - }, -], -[ - { - "type": "qq.Promise", - "description": "An instance of a promise." - } -]) }} -{% markdown %} - ## Promissory Options The [`showConfirm`][showconfirm], [`showMessage`][showmessage], and [`showPrompt`][showprompt] UI options in Fine Uploader accept promissory return values. diff --git a/docs/features/paste-to-upload.jmd b/docs/features/paste-to-upload.jmd index d8f61e662..54e457414 100644 --- a/docs/features/paste-to-upload.jmd +++ b/docs/features/paste-to-upload.jmd @@ -25,7 +25,7 @@ receive pasted images. This target element must have focus before the paste even accomplished by clicking on the element before pasting the image from the clipboard, or by programmatically giving it focus. Once the image has been pasted, the `onPasteReceived` callback will be invoked with the associated `Blob` as a parameter. -This is a promissory callback, and a `qq.Promise` MUST be returned if you provide your own implementation of this callback. +This is a promissory callback, and a `Promise` MUST be returned if you provide your own implementation of this callback. Via the promise object, you can return a string that determines the name of the associated image. This will be passed along with the upload request. Fine Uploader will also append an extension to the name, based on the image type. This callback can be used if you need to make an ajax call to determine the name of the pasted image, or if you need to display a From fd2ad47bf0a2617f9376aa65275050a84df166a0 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 16:17:17 +1100 Subject: [PATCH 70/73] refactor: tests to use native Promise, remove Q.js and qq.Promise --- client/js/promise.js | 80 ---------------------- docs/features/async-tasks-and-promises.jmd | 22 +++--- test/dev/devenv.js | 26 +++---- test/static/local/blob-maker.js | 61 ++++++++--------- test/unit/azure/simple-file-uploads.js | 31 --------- test/unit/promise.js | 63 ----------------- test/unit/s3/cdn/generic-chunked.js | 4 +- test/unit/s3/cdn/generic-non-chunked.js | 4 +- test/unit/s3/serverless-uploads.js | 33 --------- test/unit/s3/simple-file-uploads.js | 49 ------------- test/unit/scaling.js | 10 ++- test/unit/submit-validate-cancel.js | 31 ++------- test/unit/uploader.basic.api.js | 52 -------------- 13 files changed, 62 insertions(+), 404 deletions(-) delete mode 100644 test/unit/promise.js diff --git a/client/js/promise.js b/client/js/promise.js index 7407e8ce9..40f1adf5a 100644 --- a/client/js/promise.js +++ b/client/js/promise.js @@ -9,83 +9,3 @@ qq.isGenericPromise = function(maybePromise) { "use strict"; return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then)); }; - -qq.Promise = function() { - "use strict"; - - var successArgs, failureArgs, - successCallbacks = [], - failureCallbacks = [], - doneCallbacks = [], - state = 0; - - qq.extend(this, { - then: function(onSuccess, onFailure) { - if (state === 0) { - if (onSuccess) { - successCallbacks.push(onSuccess); - } - if (onFailure) { - failureCallbacks.push(onFailure); - } - } - else if (state === -1) { - onFailure && onFailure.apply(null, failureArgs); - } - else if (onSuccess) { - onSuccess.apply(null, successArgs); - } - - return this; - }, - - done: function(callback) { - if (state === 0) { - doneCallbacks.push(callback); - } - else { - callback.apply(null, failureArgs === undefined ? successArgs : failureArgs); - } - - return this; - }, - - success: function() { - state = 1; - successArgs = arguments; - - if (successCallbacks.length) { - qq.each(successCallbacks, function(idx, callback) { - callback.apply(null, successArgs); - }); - } - - if (doneCallbacks.length) { - qq.each(doneCallbacks, function(idx, callback) { - callback.apply(null, successArgs); - }); - } - - return this; - }, - - failure: function() { - state = -1; - failureArgs = arguments; - - if (failureCallbacks.length) { - qq.each(failureCallbacks, function(idx, callback) { - callback.apply(null, failureArgs); - }); - } - - if (doneCallbacks.length) { - qq.each(doneCallbacks, function(idx, callback) { - callback.apply(null, failureArgs); - }); - } - - return this; - } - }); -}; diff --git a/docs/features/async-tasks-and-promises.jmd b/docs/features/async-tasks-and-promises.jmd index 002f76d5d..1f42abe40 100644 --- a/docs/features/async-tasks-and-promises.jmd +++ b/docs/features/async-tasks-and-promises.jmd @@ -61,18 +61,16 @@ for your prompt dialog, might look something like this: ```javascript showPrompt: function(message, defaultValue) { - var promise = new qq.Promise(); - - bootbox.prompt("Enter a value", "Cancel", "Confirm", function(result) { - if (result === null || qq.trimStr(result).length === 0) { - promise.failure("User canceled prompt dialog or entered an empty string."); - } - else { - promise.success(result); - } - }, defaultValue); - - return promise; + return new Promise(function(resolve, reject) { + bootbox.prompt("Enter a value", "Cancel", "Confirm", function(result) { + if (result === null || qq.trimStr(result).length === 0) { + reject(new Error("User canceled prompt dialog or entered an empty string.")); + } + else { + resolve(result); + } + }, defaultValue); + }); } ``` diff --git a/test/dev/devenv.js b/test/dev/devenv.js index b68ff952c..27313ea3b 100644 --- a/test/dev/devenv.js +++ b/test/dev/devenv.js @@ -42,13 +42,11 @@ qq(window).attach("load", function() { }, thumbnails: { customResizer: !qq.ios() && function(resizeInfo) { - var promise = new qq.Promise(); - - pica.resizeCanvas(resizeInfo.sourceCanvas, resizeInfo.targetCanvas, {}, function() { - promise.success(); - }) - - return promise; + return new Promise(function(resolve) { + pica.resizeCanvas(resizeInfo.sourceCanvas, resizeInfo.targetCanvas, {}, function() { + resolve(); + }); + }); }, placeholders: { waitingPath: "/client/placeholders/waiting-generic.png", @@ -57,13 +55,11 @@ qq(window).attach("load", function() { }, scaling: { customResizer: !qq.ios() && function(resizeInfo) { - var promise = new qq.Promise(); - - pica.resizeCanvas(resizeInfo.sourceCanvas, resizeInfo.targetCanvas, {}, function() { - promise.success(); - }) - - return promise; + return new Promise(function(resolve) { + pica.resizeCanvas(resizeInfo.sourceCanvas, resizeInfo.targetCanvas, {}, function() { + resolve(); + }); + }); }, sizes: [{name: "small", maxSize: 800}] }, @@ -273,4 +269,4 @@ qq(window).attach("load", function() { onError: errorHandler } }); -}); \ No newline at end of file +}); diff --git a/test/static/local/blob-maker.js b/test/static/local/blob-maker.js index 8a0fd344c..1e12aa21b 100644 --- a/test/static/local/blob-maker.js +++ b/test/static/local/blob-maker.js @@ -11,43 +11,42 @@ $.extend(qqtest, { var BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder, xhr = new XMLHttpRequest(), - downloadAsync = new qq.Promise(), blobBuilder = BlobBuilder && new BlobBuilder(), self = this; - if (self._downloadedFiles[key]) { - downloadAsync.success(self._downloadedFiles[key]); - } - else { - xhr.open("GET", "http://" + window.location.hostname + ":4000/" + key, true); - xhr.responseType = "arraybuffer"; - - xhr.onerror = function() { - assert.fail(null, null, "Failed to download test file!"); - downloadAsync.failure(); - }; - - xhr.onload = function() { - if (this.status === 200) { - if (blobBuilder) { - blobBuilder.append(this.response); - self._downloadedFiles[key] = blobBuilder.getBlob(type); + return new Promise(function(resolve, reject) { + if (self._downloadedFiles[key]) { + resolve(self._downloadedFiles[key]); + } + else { + xhr.open("GET", "http://" + window.location.hostname + ":4000/" + key, true); + xhr.responseType = "arraybuffer"; + + xhr.onerror = function() { + assert.fail(null, null, "Failed to download test file!"); + reject(); + }; + + xhr.onload = function() { + if (this.status === 200) { + if (blobBuilder) { + blobBuilder.append(this.response); + self._downloadedFiles[key] = blobBuilder.getBlob(type); + } + else { + self._downloadedFiles[key] = new Blob([this.response], {type: type}); + } + + resolve(self._downloadedFiles[key]); } else { - self._downloadedFiles[key] = new Blob([this.response], {type: type}); + assert.fail(null, null, "Failed to download test file! Status: " + this.status); + reject(); } + }; - downloadAsync.success(self._downloadedFiles[key]); - } - else { - assert.fail(null, null, "Failed to download test file! Status: " + this.status); - downloadAsync.failure(); - } - }; - - xhr.send(); - } - - return downloadAsync; + xhr.send(); + } + }); } }, true); diff --git a/test/unit/azure/simple-file-uploads.js b/test/unit/azure/simple-file-uploads.js index aa72522cd..d1fb5a800 100644 --- a/test/unit/azure/simple-file-uploads.js +++ b/test/unit/azure/simple-file-uploads.js @@ -149,37 +149,6 @@ if (qqtest.canDownloadFileAsBlob) { runTest(uploader, done); }); - - it("qq.Promise", function(done) { - var uploader = new qq.azure.FineUploaderBasic({ - request: {endpoint: testEndpoint}, - signature: {endpoint: testSignatureEndoint}, - blobProperties: { - name: function(id) { - return new qq.Promise().success(id + "_blobname"); - } - } - } - ); - - runTest(uploader, done); - }); - - it("Q.js", function(done) { - var uploader = new qq.azure.FineUploaderBasic({ - request: {endpoint: testEndpoint}, - signature: {endpoint: testSignatureEndoint}, - blobProperties: { - name: function(id) { - /* jshint newcap:false */ - return Q(id + "_blobname"); - } - } - } - ); - - runTest(uploader, done); - }); }); it("test basic upload w/ params", function(done) { diff --git a/test/unit/promise.js b/test/unit/promise.js deleted file mode 100644 index 3beb8b2dd..000000000 --- a/test/unit/promise.js +++ /dev/null @@ -1,63 +0,0 @@ -/* globals describe, beforeEach, $fixture, qq, assert, it, qqtest, helpme, purl */ -describe("promise.js", function () { - "use strict"; - - describe("isPromise", function () { - it("returns true for a new'd promise", function () { - var promise = new qq.Promise(); - assert.ok(promise instanceof qq.Promise, - "a `new qq.Promise()` should be a promise"); - }); - }); - - describe("Promise API", function () { - - it("expects `success` callback", function(finish){ - var promise = new qq.Promise(); - promise.then(function(value){ - assert.ok(value); - finish(); - }); - - promise.success(true); - }); - - it("expects `failure` callback", function(finish){ - var promise = new qq.Promise(); - promise.then(null, function(value){ - assert.ok(value); - finish(); - }); - - promise.failure(true); - }); - - it("success: expects `done` to be callback", function (finish) { - var promise = new qq.Promise(); - promise.done(function (value) { - assert.ok(value); - finish(); - }); - - promise.success(true); - }); - - it("failure: expects `done` to be callback", function (finish) { - var promise = new qq.Promise(); - promise.done(function (value) { - assert.ok(value); - finish(); - }); - - promise.failure(true); - }); - - it("ensures success callback is not called if promise fails before then is invoked", function() { - var promise = new qq.Promise().failure(); - - promise.then(function() { - assert.ok(false, "Success callback was unexpectedly invoked"); - }); - }); - }); -}); diff --git a/test/unit/s3/cdn/generic-chunked.js b/test/unit/s3/cdn/generic-chunked.js index e6893d2ff..986f337fd 100644 --- a/test/unit/s3/cdn/generic-chunked.js +++ b/test/unit/s3/cdn/generic-chunked.js @@ -147,9 +147,7 @@ if (qqtest.canDownloadFileAsBlob) { chunking: typicalChunkingOption, objectProperties: { bucket: function() { - var promise = new qq.Promise(); - promise.success("mybucket"); - return promise; + return Promise.resolve("mybucket"); } } } diff --git a/test/unit/s3/cdn/generic-non-chunked.js b/test/unit/s3/cdn/generic-non-chunked.js index 33a881b64..8b1f7174e 100644 --- a/test/unit/s3/cdn/generic-non-chunked.js +++ b/test/unit/s3/cdn/generic-non-chunked.js @@ -97,9 +97,7 @@ if (qqtest.canDownloadFileAsBlob) { objectProperties: { bucket: function(id) { assert.equal(id, 0, "unexpected ID passed to bucket function"); - var promise = new qq.Promise(); - promise.success("mybucket"); - return promise; + return Promise.resolve("mybucket"); } }, uploadSuccess: { diff --git a/test/unit/s3/serverless-uploads.js b/test/unit/s3/serverless-uploads.js index 45854b0f6..be816bd37 100644 --- a/test/unit/s3/serverless-uploads.js +++ b/test/unit/s3/serverless-uploads.js @@ -259,39 +259,6 @@ describe("S3 serverless upload tests", function() { runTest(callback, done); }); - - it("qq.Promise", function(done) { - var callback = function() { - assert.ok(true); - - var promise = new qq.Promise(); - promise.success({ - accessKey: testAccessKeyFromCallback, - secretKey: testSecretKey, - expiration: new Date(Date.now() + 10000), - sessionToken: testSessionTokenFromCallback - }); - return promise; - }; - - runTest(callback, done); - }); - - it("Q.js", function(done) { - var callback = function() { - assert.ok(true); - - /* jshint newcap:false */ - return Q({ - accessKey: testAccessKeyFromCallback, - secretKey: testSecretKey, - expiration: new Date(Date.now() + 10000), - sessionToken: testSessionTokenFromCallback - }); - }; - - runTest(callback, done); - }); }); }); } diff --git a/test/unit/s3/simple-file-uploads.js b/test/unit/s3/simple-file-uploads.js index ed376c0c6..18d21cf21 100644 --- a/test/unit/s3/simple-file-uploads.js +++ b/test/unit/s3/simple-file-uploads.js @@ -460,23 +460,6 @@ if (qqtest.canDownloadFileAsBlob) { runTest(keyFunc, done); }); - - it("qq.Promise", function(done) { - var keyFunc = function(id) { - return new qq.Promise().success(customKeyPrefix + this.getName(id)); - }; - - runTest(keyFunc, done); - }); - - it("Q.js", function(done) { - var keyFunc = function(id) { - /* jshint newcap:false */ - return Q(customKeyPrefix + this.getName(id)); - }; - - runTest(keyFunc, done); - }); }); describe("respects the objectProperties.key option w/ a custom key generation function that returns a failed promise (no reason)", function() { @@ -506,22 +489,6 @@ if (qqtest.canDownloadFileAsBlob) { runTest(keyFunc, done); }); - - it("qq.Promise", function(done) { - var keyFunc = function() { - return new qq.Promise().failure(); - }; - - runTest(keyFunc, done); - }); - - it("Q.js", function(done) { - var keyFunc = function() { - return Q.reject(); - }; - - runTest(keyFunc, done); - }); }); describe("respects the objectProperties.key option w/ a custom key generation function that returns a failed promise (w/ reason)", function() { @@ -556,22 +523,6 @@ if (qqtest.canDownloadFileAsBlob) { runTest(keyFunc, done); }); - - it("qq.Promise", function(done) { - var keyFunc = function() { - return new qq.Promise().failure("oops"); - }; - - runTest(keyFunc, done); - }); - - it("Q.js", function(done) { - var keyFunc = function() { - return Q.reject("oops"); - }; - - runTest(keyFunc, done); - }); }); it("respects the objectProperties.acl option w/ a custom value set via option", function(done) { diff --git a/test/unit/scaling.js b/test/unit/scaling.js index d022c4d3b..c008e221e 100644 --- a/test/unit/scaling.js +++ b/test/unit/scaling.js @@ -15,13 +15,11 @@ if (qq.supportedFeatures.scaling) { }, 10); }, typicalCustomResizer = function(resizeInfo) { - var promise = new qq.Promise(); - - pica.resizeCanvas(resizeInfo.sourceCanvas, resizeInfo.targetCanvas, {}, function() { - promise.success(); + return new Promise(function(resolve) { + pica.resizeCanvas(resizeInfo.sourceCanvas, resizeInfo.targetCanvas, {}, function() { + resolve(); + }); }); - - return promise; }; it("is disabled if no sizes are specified", function() { diff --git a/test/unit/submit-validate-cancel.js b/test/unit/submit-validate-cancel.js index 5d77e77b5..a87071b1f 100644 --- a/test/unit/submit-validate-cancel.js +++ b/test/unit/submit-validate-cancel.js @@ -136,7 +136,7 @@ if (qqtest.canDownloadFileAsBlob) { }); describe("file rejection via callback", function() { - function setupUploader(callback, blob, done, useQ) { + function setupUploader(callback, blob, done) { var uploader = new qq.FineUploaderBasic({ autoUpload: false, callbacks: (function() { @@ -145,20 +145,11 @@ if (qqtest.canDownloadFileAsBlob) { if (done) { callbacks[callbackName] = function() { - if (useQ) { - return Q.Promise(function(resolve, reject) { - setTimeout(function() { - reject(); - },100); - }); - } - else { - var promise = new qq.Promise(); + return new Promise(function(resolve, reject) { setTimeout(function() { - promise.failure(); - },100); - return promise; - } + reject(); + }, 100); + }); }; callbacks.onStatusChange = function(id, oldStatus, newStatus) { @@ -221,12 +212,6 @@ if (qqtest.canDownloadFileAsBlob) { }); }); - it("Q.js: Ignores a submitted file that is rejected by returning a promise and failing it in a validate callback", function(done) { - qqtest.downloadFileAsBlob(testImgKey, testImgType).then(function(blob) { - setupUploader("validate", blob, done, true); - }); - }); - it("Ignores a submitted file that is rejected by returning false in a validateBatch callback", function(done) { qqtest.downloadFileAsBlob(testImgKey, testImgType).then(function(blob) { var uploader = setupUploader("validateBatch", blob); @@ -243,12 +228,6 @@ if (qqtest.canDownloadFileAsBlob) { setupUploader("validateBatch", blob, done); }); }); - - it("Q.js: Ignores a submitted file that is rejected by returning a promise and failing it in a validateBatch callback", function(done) { - qqtest.downloadFileAsBlob(testImgKey, testImgType).then(function(blob) { - setupUploader("validateBatch", blob, done, true); - }); - }); }); describe("file rejection via internal validation", function() { diff --git a/test/unit/uploader.basic.api.js b/test/unit/uploader.basic.api.js index 5ce9e7683..88048d5a5 100644 --- a/test/unit/uploader.basic.api.js +++ b/test/unit/uploader.basic.api.js @@ -253,32 +253,6 @@ describe("uploader.basic.api.js", function () { runTest(callback, done); }); - - it("qq.Promise", function(done) { - var callback = function() { - var promise = new qq.Promise(); - - setTimeout(function() { - promise.success("foobar"); - }, 100); - - return promise; - }; - - runTest(callback, done); - }); - - it("Q.js", function(done) { - var callback = function() { - return Q.Promise(function(resolve) { - setTimeout(function() { - resolve("foobar"); - }, 100); - }); - }; - - runTest(callback, done); - }); }); describe("handles failed promissory callbacks", function() { @@ -308,32 +282,6 @@ describe("uploader.basic.api.js", function () { runTest(callback, done); }); - - it("qq.Promise", function(done) { - var callback = function() { - var promise = new qq.Promise(); - - setTimeout(function() { - promise.failure(); - }, 100); - - return promise; - }; - - runTest(callback, done); - }); - - it("Q.js", function(done) { - var callback = function() { - return Q.Promise(function (resolve, reject) { - setTimeout(function () { - reject(); - }, 100); - }); - }; - - runTest(callback, done); - }); }); it("does auto retry if upload is not paused", function() { From 437ec5b0a2163cc8a408a021728499a3fd4d858f Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 16:19:17 +1100 Subject: [PATCH 71/73] refactor: remove isGenericPromise, use instanceof Promise BREAKING CHANGE: Drop support for non-native Promise implementations --- client/js/promise.js | 8 -------- client/js/s3/uploader.basic.js | 6 +++--- client/js/upload-handler/upload.handler.controller.js | 2 +- client/js/uploader.api.js | 2 +- client/js/uploader.basic.api.js | 6 +++--- 5 files changed, 8 insertions(+), 16 deletions(-) diff --git a/client/js/promise.js b/client/js/promise.js index 40f1adf5a..a4f7af382 100644 --- a/client/js/promise.js +++ b/client/js/promise.js @@ -1,11 +1,3 @@ -/*globals qq*/ - if (typeof Promise === "undefined") { throw new Error("FileUploader requires a native promise implementation."); } - -// Is the passed object a promise instance? -qq.isGenericPromise = function(maybePromise) { - "use strict"; - return !!(maybePromise && maybePromise.then && qq.isFunction(maybePromise.then)); -}; diff --git a/client/js/s3/uploader.basic.js b/client/js/s3/uploader.basic.js index 33338a674..206fba7dd 100644 --- a/client/js/s3/uploader.basic.js +++ b/client/js/s3/uploader.basic.js @@ -258,7 +258,7 @@ var callbackRetVal = self._options.callbacks.onCredentialsExpired(); return new Promise(function(resolve, reject) { - if (qq.isGenericPromise(callbackRetVal)) { + if (callbackRetVal instanceof Promise) { callbackRetVal.then(function(credentials) { try { self.setCredentials(credentials); @@ -292,7 +292,7 @@ promise = new Promise(function(resolve, reject) { if (qq.isFunction(maybe)) { maybe = maybe(id); - if (qq.isGenericPromise(maybe)) { + if (maybe instanceof Promise) { maybe.then(resolve, reject); } else { @@ -396,7 +396,7 @@ }, keyname = keynameFunc.call(this, id); - if (qq.isGenericPromise(keyname)) { + if (keyname instanceof Promise) { keyname.then(onSuccess, onFailure); } /*jshint -W116*/ diff --git a/client/js/upload-handler/upload.handler.controller.js b/client/js/upload-handler/upload.handler.controller.js index 24f611a01..509183f79 100644 --- a/client/js/upload-handler/upload.handler.controller.js +++ b/client/js/upload-handler/upload.handler.controller.js @@ -687,7 +687,7 @@ qq.UploadHandlerController = function(o, namespace) { cancel: function(id) { var cancelRetVal = handler.cancel(id); - if (qq.isGenericPromise(cancelRetVal)) { + if (cancelRetVal instanceof Promise) { cancelRetVal.then(function() { upload.cancel(id); }); diff --git a/client/js/uploader.api.js b/client/js/uploader.api.js index 97c05816b..d7c3d3c04 100644 --- a/client/js/uploader.api.js +++ b/client/js/uploader.api.js @@ -526,7 +526,7 @@ retVal = this._options.showConfirm(confirmMessage); - if (qq.isGenericPromise(retVal)) { + if (retVal instanceof Promise) { retVal.then(function() { self._sendDeleteRequest.apply(self, deleteRequestArgs); }); diff --git a/client/js/uploader.basic.api.js b/client/js/uploader.basic.api.js index 423a5215f..a90497cc9 100644 --- a/client/js/uploader.basic.api.js +++ b/client/js/uploader.basic.api.js @@ -810,7 +810,7 @@ self._onUpload(id, name); var onUploadResult = self._options.callbacks.onUpload(id, name); - if (qq.isGenericPromise(onUploadResult)) { + if (onUploadResult instanceof Promise) { self.log(qq.format("onUpload for {} returned a Promise - waiting for resolution.", id)); return onUploadResult; } @@ -821,7 +821,7 @@ self._onUploadChunk(id, chunkData); var onUploadChunkResult = self._options.callbacks.onUploadChunk(id, name, chunkData); - if (qq.isGenericPromise(onUploadChunkResult)) { + if (onUploadChunkResult instanceof Promise) { self.log(qq.format("onUploadChunk for {}.{} returned a Promise - waiting for resolution.", id, chunkData.partIndex)); return onUploadChunkResult; } @@ -1072,7 +1072,7 @@ var self = this, callbackRetVal = details.callback(); - if (qq.isGenericPromise(callbackRetVal)) { + if (callbackRetVal instanceof Promise) { this.log(details.name + " - waiting for " + details.name + " promise to be fulfilled for " + details.identifier); return callbackRetVal.then( function(successParam) { From 7e4473a87131b2c6b74ace9db041b984e75d2aa6 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Tue, 27 Mar 2018 16:20:15 +1100 Subject: [PATCH 72/73] refactor: remove CSS references to qq.Promise --- docs/_static/css/main.css | 3 --- docs/_templates/macros/code.html | 3 --- 2 files changed, 6 deletions(-) diff --git a/docs/_static/css/main.css b/docs/_static/css/main.css index 8823edf71..8a2d31ac6 100755 --- a/docs/_static/css/main.css +++ b/docs/_static/css/main.css @@ -207,9 +207,6 @@ h4 a, a:hover, a:focus, :visited { .label-htmlelement { background-color: #f87436; } -.label-qq.promise { - background-color: #C700AC; -} .label-xmlhttprequest { background-color: #66ccdd; } diff --git a/docs/_templates/macros/code.html b/docs/_templates/macros/code.html index 56d5e6270..20fcadbd2 100644 --- a/docs/_templates/macros/code.html +++ b/docs/_templates/macros/code.html @@ -67,9 +67,6 @@

{{ title }}

"htmlelement": { "link": "" }, - "qq.promise": { - "link": "" - }, "xmlhttprequest": { "link": "" }, From 2f9f381f0180e54bb9b9299b2cc2bada0058c6a8 Mon Sep 17 00:00:00 2001 From: Bradley Ayers Date: Sun, 1 Apr 2018 18:12:37 +1000 Subject: [PATCH 73/73] fix: Remove PromiseOptions from TypeScript definitions --- client/typescript/fine-uploader.d.ts | 118 +++++++----------------- client/typescript/fine-uploader.test.ts | 15 --- 2 files changed, 35 insertions(+), 98 deletions(-) diff --git a/client/typescript/fine-uploader.d.ts b/client/typescript/fine-uploader.d.ts index 0c0ab7182..2435838c1 100644 --- a/client/typescript/fine-uploader.d.ts +++ b/client/typescript/fine-uploader.d.ts @@ -81,12 +81,12 @@ declare module "fine-uploader/lib/core" { * @param boolean fromServer : true if the image data will come as a response from the server rather than be generated client-side * @param CustomResizerCallBack customResizer : Ignored if the current browser does not support image previews. * If you want to use an alternate library to resize the image, you must contribute a function for this option that returns a `Promise`. - * Once the resize is complete, your promise must be fulfilled. + * Once the resize is complete, resolve the promise. * You may, of course, reject your returned `Promise` is the resize fails in some way. - * @returns Promise: Fulfilled by passing the container back into the success callback after the thumbnail has been rendered. - * If the thumbnail cannot be rendered, failure callbacks will be invoked instead, passing an object with `container` and `error` properties. + * @returns {Promise} : Resolved with the container after the thumbnail has been rendered. + * If the thumbnail cannot be rendered, failure callbacks will be invoked instead, passing an object with `container` and `error` properties. */ - drawThumbnail(id: number, targetContainer: HTMLElement, maxSize?: number, fromServer?: boolean, customResizer?: CustomResizerCallBack): PromiseOptions; + drawThumbnail(id: number, targetContainer: HTMLElement, maxSize?: number, fromServer?: boolean, customResizer?: CustomResizerCallBack): Promise; /** * Returns the button container element associated with a file @@ -231,10 +231,10 @@ declare module "fine-uploader/lib/core" { * * @param number id : The id of the image file * @param ScaleImageOptions option : Information about the scaled image to generate - * @returns PromiseOptions : Fulfilled by passing the scaled image as a `Blob` back into the success callback after the original image has been scaled. - * If the scaled image cannot be generated, the failure callback will be invoked instead + * @returns {Promise} : Resolved with the scaled image as a `Blob` after the original image has been scaled. + * If the scaled image cannot be generated, the promise is rejected. */ - scaleImage(id: number, options: ScaleImageOptions): PromiseOptions; + scaleImage(id: number, options: ScaleImageOptions): Promise; /** * Set custom headers for an upload request. Pass in a file id to make the headers specific to that file @@ -591,9 +591,9 @@ declare module "fine-uploader/lib/core" { * Contribute this function to manually resize images using alternate 3rd party libraries * * @param ResizeInfo resizeInfo : the ResizeInfo object containing all the resize values/options - * @returns Promise : Once the resize is complete, the function must return a promise + * @returns {Promise} : Once the resize is complete, the function must return a promise */ - (resizeInfo: ResizeInfo): PromiseOptions; + (resizeInfo: ResizeInfo): Promise; } /** @@ -694,57 +694,12 @@ declare module "fine-uploader/lib/core" { * * If you want to use an alternate library to resize the image, you must contribute a function for this option that returns a `Promise`. * - * Once the resize is complete, your promise must be fulfilled. + * Once the resize is complete, your promise must be resolved. * You may, of course, reject your returned `Promise` is the resize fails in some way. */ customResizer?: CustomResizerCallBack; } - export interface PromiseOptions { - /** - * Register callbacks from success and failure. - * - * The promise instance that then is called on will pass any values into the provided callbacks. - * If success or failure have already occurred before these callbacks have been registered, then they will be called immediately after this call has been executed. - * Each subsequent call to then registers an additional set of callbacks. - * - * @param Function successCallback : The function to call when the promise is successfully fulfilled - * @param Function failureCallback : The function to call when the promise is unsuccessfully fulfilled - * @return PromiseOptions : An instance of a promise - */ - then(successCallback: Function, failureCallback: Function): PromiseOptions; - - /** - * Register callbacks for success or failure. - * - * Invoked when the promise is fulfilled regardless of the result. - * The promise instance that done is called on will pass any values into the provided callback. - * Each call to done registers an additional set of callbacks - * - * @param Function callback : The function to call when the promise is fulfilled, successful or not. - * @return PromiseOptions : An instance of a promise - */ - done(callback: Function): PromiseOptions; - - /** - * Call this on a promise to indicate success. - * The parameter values will depend on the situation. - * - * @param Object param : The value to pass to the promise's success handler. - * @return PromiseOptions : An instance of a promise - */ - success(param: any): PromiseOptions; - - /** - * Call this on a promise to indicate failure. - * The parameter values will depend on the situation. - * - * @param Object param : The value to pass to the promise's failure handler. - * @return PromiseOptions : An instance of a promise - */ - failure(param: any): PromiseOptions; - } - /** * A BlobWrapper object type */ @@ -1518,7 +1473,7 @@ declare module "fine-uploader/lib/core" { * Ignored if the current browser does not support image previews. * * If you want to use an alternate scaling library, you must contribute a function for this option that returns a Promise. - * Once the resize is complete, your promise must be fulfilled. You may, of course, reject your returned Promise is the resize fails in some way + * Once the resize is complete, your promise must be resolved. You may, of course, reject your returned Promise is the resize fails in some way * * @default `undefined` */ @@ -1803,9 +1758,9 @@ declare module "fine-uploader/lib/core" { * * The pasted image is represented as a `Blob`. Also can return a `Promise` if non-blocking work is required here. * - * If using a `Promise` the value of the success parameter must be the name to associate with the pasted image. + * If using a resolved `Promise`, the value must be the name to associate with the pasted image. * - * If the associated attempt is marked a failure then you should include a string explaining the reason in your failure callback for the `Promise` + * If the associated attempt is rejected, provide an error describing the reason. * * ###NOTE: * The `promptForName` option, if `true`, will effectively wipe away any custom implementation of this callback. @@ -1929,7 +1884,7 @@ declare module "fine-uploader/lib/core" { * * This event will not be called if you return `false` in your `validateBatch` event handler, or if the `stopOnFirstInvalidFile` validation option is `true` and the `validate` event handler has returned `false` for an item. * - * A promise can be used if non-blocking work is required. Processing of this item is deferred until the promise is fullfilled. If a promise is returned, a call to `failure` is the same as returning `false`. + * A promise can be used if non-blocking work is required. Processing of this item is deferred until the promise is fullfilled. Returning a rejected promise is the treated the same as returning `false`. * * A buttonContainer element will be passed as the last argument, provided the file was submitted using a Fine Uploader tracked button. * @@ -1958,7 +1913,7 @@ declare module "fine-uploader/lib/core" { * @param number id : The current file's id * @param string name : The current file's name */ - (id: number, name: string): boolean | PromiseOptions | void; + (id: number, name: string): boolean | Promise<{}> | void; } /** @@ -2038,7 +1993,7 @@ declare module "fine-uploader/lib/core" { /** * @param Blob blob : An object encapsulating the image pasted from the clipboard */ - (blob: Blob): PromiseOptions | void; + (blob: Blob): Promise | void; } /** @@ -2064,7 +2019,7 @@ declare module "fine-uploader/lib/core" { * @param Object chunkData : The chunk that will be sent next when file upload resumes * @param Object customResumeData : Any custom resume data provided for this resumable file */ - (id: number, name: string, chunkData: any, customResumeData: any): void | Promise; + (id: number, name: string, chunkData: any, customResumeData: any): void | Promise; } /** @@ -2096,7 +2051,7 @@ declare module "fine-uploader/lib/core" { * @param number id : The current file's id * @param string name : The current file's name */ - (id: number, name: string): boolean | PromiseOptions | void; + (id: number, name: string): boolean | Promise | void; } /** @@ -2106,7 +2061,7 @@ declare module "fine-uploader/lib/core" { /** * @param number id : The current file's id */ - (id: number): PromiseOptions | void; + (id: number): Promise | void; } /** @@ -2174,7 +2129,7 @@ declare module "fine-uploader/lib/core" { * @param string name : The current file's name * @param ChunkData chunkData : An object encapsulating the current chunk of data about to be uploaded */ - (id: number, name: string, chunkData: ChunkData): void | Promise; + (id: number, name: string, chunkData: ChunkData): void | Promise; } /** @@ -2212,7 +2167,7 @@ declare module "fine-uploader/lib/core" { * @param BlobDataObject data : An object with a name and size property * @param HTMLElement buttonContainer : The button corresponding to the respective file if the file was submitted to Fine Uploader using a tracked button */ - (data: BlobDataObject, buttonContainer?: HTMLElement): PromiseOptions | void; + (data: BlobDataObject, buttonContainer?: HTMLElement): Promise | void; } /** @@ -2223,7 +2178,7 @@ declare module "fine-uploader/lib/core" { * @param BlobDataObject[] fileOrBlobDataArray : An array of Objects with name and size properties * @param HTMLElement buttonContainer : The button corresponding to the respective file if the file was submitted to Fine Uploader using a tracked button */ - (fileOrBlobDataArray: BlobDataObject[], buttonContainer: HTMLElement): PromiseOptions | void; + (fileOrBlobDataArray: BlobDataObject[], buttonContainer: HTMLElement): Promise | void; } } @@ -2243,7 +2198,6 @@ declare module "fine-uploader" { PasteOptions, ScalingOptions, TextOptions, - PromiseOptions, CustomResizerCallBack } from 'fine-uploader/lib/core'; @@ -2401,21 +2355,21 @@ declare module "fine-uploader" { * function for `showMessage` option */ export interface ShowMessageFunction { - (message: string): PromiseOptions | void; + (message: string): Promise | void; } /** * function for `showConfirm` option */ export interface ShowConfirmFunction { - (message: string): PromiseOptions | void; + (message: string): Promise | void; } /** * function for `showPrompt` option */ export interface ShowPromptFunction { - (message: string, defaultValue: string): PromiseOptions | void; + (message: string, defaultValue: string): Promise | void; } /** @@ -2564,7 +2518,7 @@ declare module "fine-uploader" { * Ignored if the current browser does not support image previews. * * If you want to use an alternate library to resize the image, you must contribute a function for this option that returns a Promise. - * Once the resize is complete, your promise must be fulfilled. + * Once the resize is complete, your promise must be resolved. * * You may, of course, reject your returned Promise is the resize fails in some way * @@ -2710,8 +2664,7 @@ declare module "fine-uploader/lib/azure" { CorsOptions, RequestOptions, CoreOptions, - ResumableFileObject, - PromiseOptions + ResumableFileObject } from 'fine-uploader/lib/core'; @@ -2859,7 +2812,7 @@ declare module "fine-uploader/lib/azure" { * AzureBlobPropertyNameFunction */ export interface AzureBlobPropertyNameFunction { - (id: number): PromiseOptions | string; + (id: number): Promise | string; } /** @@ -3090,8 +3043,7 @@ declare module "fine-uploader/lib/s3" { RequestOptions, CoreOptions, ResumableFileObject, - CoreEvents, - PromiseOptions + CoreEvents } from 'fine-uploader/lib/core'; @@ -3324,21 +3276,21 @@ declare module "fine-uploader/lib/s3" { * type for S3's bucket object property */ export interface BucketFunction { - (id: number): PromiseOptions | string; + (id: number): Promise | string; } /** * type for S3's host object property */ export interface HostFunction { - (id: number): PromiseOptions | string; + (id: number): Promise | string; } /** * type for S3's key object property */ export interface KeyFunction { - (id: number): PromiseOptions | string; + (id: number): Promise | string; } /** @@ -3567,7 +3519,7 @@ declare module "fine-uploader/lib/s3" { * onCredentialsExpired function type */ export interface OnCredentialsExpired { - (): PromiseOptions; + (): Promise; } /** @@ -3577,8 +3529,8 @@ declare module "fine-uploader/lib/s3" { /** * Called before a request is sent to S3 if the temporary credentials have expired. * - * You must return a promise. If your attempt to refresh the temporary credentials is successful, you must fulfill the promise via the success method, passing the new credentials object. - * Otherwise, call failure with a descriptive reason. + * You must return a promise. If your attempt to refresh the temporary credentials is successful, you must resolve the promise, passing the new credentials object. + * Otherwise, the promise should be rejected. */ onCredentialsExpired?: OnCredentialsExpired; } diff --git a/client/typescript/fine-uploader.test.ts b/client/typescript/fine-uploader.test.ts index 0b416872d..a4abae6b5 100644 --- a/client/typescript/fine-uploader.test.ts +++ b/client/typescript/fine-uploader.test.ts @@ -1,7 +1,6 @@ import { FineUploader, UIOptions } from 'fine-uploader'; import { s3 } from 'fine-uploader/lib/s3'; import { azure } from 'fine-uploader/lib/azure'; -import { PromiseOptions } from 'fine-uploader/lib/core'; /** * Prepare/set options for the core + UI FineUploader @@ -89,17 +88,3 @@ let azureUploader = new azure.FineUploader(azureUIOptions); uploader.uploadStoredFiles(); s3Uploader.uploadStoredFiles(); azureUploader.uploadStoredFiles(); - -//FineUploader's Promise Implementation -let promise: PromiseOptions = new uploader.Promise(); -let result = {}; -promise.failure(result); -promise.success(result); -promise.then(() => { - //promise is successfully fulfilled, do something here -}, () => { - //promise is un-successfully fulfilled, do something here -}); -promise.done(() => { - //promise is fulfilled whether successful or not, do something here -}); \ No newline at end of file