From 694f05bc4e4d1e1bea55acec9a334fa45af0a3ba Mon Sep 17 00:00:00 2001 From: Lin Jian Date: Fri, 30 Oct 2020 21:01:42 +0800 Subject: [PATCH 1/3] uploadData for Node.js and browsers, refactor duplicated code --- sdk/storage/storage-blob/README.md | 2 +- .../highlevel/recording_after_all_hook.js | 2 +- .../highlevel/recording_before_all_hook.js | 2 +- ..._buffer_arraybuffer_and_arraybufferview.js | 545 +++++++++++++ .../storage-blob/review/storage-blob.api.md | 2 + sdk/storage/storage-blob/src/Clients.ts | 237 ++---- .../test/node/highlevel.node.spec.ts | 28 + sdk/storage/storage-file-datalake/README.md | 5 + .../recording_after_all_hook.js | 2 +- .../recording_before_all_hook.js | 2 +- ...ffer_and_arraybufferview_should_succeed.js | 495 ++++++++++++ .../storage-file-datalake/src/clients.ts | 38 +- .../test/node/highlevel.node.spec.ts | 23 + sdk/storage/storage-file-share/README.md | 5 +- ..._buffer_arraybuffer_and_arraybufferview.js | 743 ++++++++++++++++++ sdk/storage/storage-file-share/src/Clients.ts | 166 +--- .../test/node/highlevel.node.spec.ts | 28 + 17 files changed, 2025 insertions(+), 300 deletions(-) create mode 100644 sdk/storage/storage-blob/recordings/node/highlevel/recording_uploaddata_should_work_with_buffer_arraybuffer_and_arraybufferview.js create mode 100644 sdk/storage/storage-file-datalake/recordings/node/highlevel_nodejs_only/recording_upload_arraybuffer_and_arraybufferview_should_succeed.js create mode 100644 sdk/storage/storage-file-share/recordings/node/highlevel_nodejs_only/recording_uploaddata_should_work_with_buffer_arraybuffer_and_arraybufferview.js diff --git a/sdk/storage/storage-blob/README.md b/sdk/storage/storage-blob/README.md index db4c54ee5866..c40b938ae232 100644 --- a/sdk/storage/storage-blob/README.md +++ b/sdk/storage/storage-blob/README.md @@ -78,7 +78,7 @@ There are differences between Node.js and browsers runtime. When getting started - Shared Access Signature(SAS) generation - `generateAccountSASQueryParameters()` - `generateBlobSASQueryParameters()` -- Parallel uploading and downloading +- Parallel uploading and downloading. Note that `BlockBlobClient.uploadData()` is available in both Node.js and browsers. - `BlockBlobClient.uploadFile()` - `BlockBlobClient.uploadStream()` - `BlobClient.downloadToBuffer()` diff --git a/sdk/storage/storage-blob/recordings/node/highlevel/recording_after_all_hook.js b/sdk/storage/storage-blob/recordings/node/highlevel/recording_after_all_hook.js index cab06e6bc8a9..6828db7ea055 100644 --- a/sdk/storage/storage-blob/recordings/node/highlevel/recording_after_all_hook.js +++ b/sdk/storage/storage-blob/recordings/node/highlevel/recording_after_all_hook.js @@ -1,5 +1,5 @@ let nock = require('nock'); -module.exports.hash = "a517c9a2f9f67f81c0cd8de67eb9a59a"; +module.exports.hash = "75b23bd223fca880219ec1f5ec5fe605"; module.exports.testInfo = {"uniqueName":{},"newDate":{}} diff --git a/sdk/storage/storage-blob/recordings/node/highlevel/recording_before_all_hook.js b/sdk/storage/storage-blob/recordings/node/highlevel/recording_before_all_hook.js index cab06e6bc8a9..6828db7ea055 100644 --- a/sdk/storage/storage-blob/recordings/node/highlevel/recording_before_all_hook.js +++ b/sdk/storage/storage-blob/recordings/node/highlevel/recording_before_all_hook.js @@ -1,5 +1,5 @@ let nock = require('nock'); -module.exports.hash = "a517c9a2f9f67f81c0cd8de67eb9a59a"; +module.exports.hash = "75b23bd223fca880219ec1f5ec5fe605"; module.exports.testInfo = {"uniqueName":{},"newDate":{}} diff --git a/sdk/storage/storage-blob/recordings/node/highlevel/recording_uploaddata_should_work_with_buffer_arraybuffer_and_arraybufferview.js b/sdk/storage/storage-blob/recordings/node/highlevel/recording_uploaddata_should_work_with_buffer_arraybuffer_and_arraybufferview.js new file mode 100644 index 000000000000..e6d2d9c1ac1f --- /dev/null +++ b/sdk/storage/storage-blob/recordings/node/highlevel/recording_uploaddata_should_work_with_buffer_arraybuffer_and_arraybufferview.js @@ -0,0 +1,545 @@ +let nock = require('nock'); + +module.exports.hash = "75b23bd223fca880219ec1f5ec5fe605"; + +module.exports.testInfo = {"uniqueName":{"container":"container160406213443204111","blob":"blob160406213578407617"},"newDate":{}} + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .put('/container160406213443204111') + .query(true) + .reply(201, "", [ + 'Content-Length', + '0', + 'Last-Modified', + 'Fri, 30 Oct 2020 12:48:55 GMT', + 'ETag', + '"0x8D87CD229A26E7F"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '4b7e89f9-601e-0035-4abb-ae39e9000000', + 'x-ms-client-request-id', + 'e1fe02fd-033a-4f0c-8986-67b276c227ed', + 'x-ms-version', + '2020-02-10', + 'Date', + 'Fri, 30 Oct 2020 12:48:55 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .put('/container160406213443204111/blob160406213578407617', "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t") + .reply(201, "", [ + 'Content-Length', + '0', + 'Content-MD5', + 'xWvVSA9uVBPLYqCtlmZhOg==', + 'Last-Modified', + 'Fri, 30 Oct 2020 12:48:55 GMT', + 'ETag', + '"0x8D87CD229D5CB13"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '4b7e8a57-601e-0035-22bb-ae39e9000000', + 'x-ms-client-request-id', + '33481bc5-ff0e-4b33-9c7d-dd84d0678432', + 'x-ms-version', + '2020-02-10', + 'x-ms-content-crc64', + 'l0UONCoHCSs=', + 'x-ms-request-server-encrypted', + 'true', + 'x-ms-version-id', + '2020-10-30T12:48:55.9778579Z', + 'Date', + 'Fri, 30 Oct 2020 12:48:55 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .head('/container160406213443204111/blob160406213578407617') + .reply(200, "", [ + 'Content-Length', + '10', + 'Content-Type', + 'application/octet-stream', + 'Content-MD5', + 'xWvVSA9uVBPLYqCtlmZhOg==', + 'Last-Modified', + 'Fri, 30 Oct 2020 12:48:55 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87CD229D5CB13"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '4b7e8ad2-601e-0035-08bb-ae39e9000000', + 'x-ms-client-request-id', + 'cbc6421c-12f8-4ba0-9699-fe38f384f7a7', + 'x-ms-version', + '2020-02-10', + 'x-ms-version-id', + '2020-10-30T12:48:55.9778579Z', + 'x-ms-is-current-version', + 'true', + 'x-ms-creation-time', + 'Fri, 30 Oct 2020 12:48:55 GMT', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-blob-type', + 'BlockBlob', + 'x-ms-server-encrypted', + 'true', + 'x-ms-access-tier', + 'Hot', + 'x-ms-access-tier-inferred', + 'true', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,x-ms-version-id,x-ms-is-current-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,Content-MD5,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,x-ms-server-encrypted,x-ms-access-tier,x-ms-access-tier-inferred,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 12:48:55 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .get('/container160406213443204111/blob160406213578407617') + .reply(206, "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t", [ + 'Content-Length', + '10', + 'Content-Type', + 'application/octet-stream', + 'Content-Range', + 'bytes 0-9/10', + 'Last-Modified', + 'Fri, 30 Oct 2020 12:48:55 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87CD229D5CB13"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '4b7e8b16-601e-0035-41bb-ae39e9000000', + 'x-ms-client-request-id', + 'd2f5bf20-0c06-436b-b2d9-9c47a01ad153', + 'x-ms-version', + '2020-02-10', + 'x-ms-version-id', + '2020-10-30T12:48:55.9778579Z', + 'x-ms-is-current-version', + 'true', + 'x-ms-creation-time', + 'Fri, 30 Oct 2020 12:48:55 GMT', + 'x-ms-blob-content-md5', + 'xWvVSA9uVBPLYqCtlmZhOg==', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-blob-type', + 'BlockBlob', + 'x-ms-server-encrypted', + 'true', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,x-ms-version-id,x-ms-is-current-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,x-ms-blob-content-md5,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,x-ms-server-encrypted,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 12:48:55 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .put('/container160406213443204111/blob160406213578407617', "\u0001\u0002\u0003") + .reply(201, "", [ + 'Content-Length', + '0', + 'Content-MD5', + 'Uonfc331cyb83SJZevsfrA==', + 'Last-Modified', + 'Fri, 30 Oct 2020 12:48:56 GMT', + 'ETag', + '"0x8D87CD22A5C2ADB"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '4b7e8b83-601e-0035-1dbb-ae39e9000000', + 'x-ms-client-request-id', + 'ce93d4d5-ae15-4fce-a234-e0e35700a7e7', + 'x-ms-version', + '2020-02-10', + 'x-ms-content-crc64', + 'wBdArCrzewI=', + 'x-ms-request-server-encrypted', + 'true', + 'x-ms-version-id', + '2020-10-30T12:48:56.8604923Z', + 'Date', + 'Fri, 30 Oct 2020 12:48:56 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .head('/container160406213443204111/blob160406213578407617') + .reply(200, "", [ + 'Content-Length', + '3', + 'Content-Type', + 'application/octet-stream', + 'Content-MD5', + 'Uonfc331cyb83SJZevsfrA==', + 'Last-Modified', + 'Fri, 30 Oct 2020 12:48:56 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87CD22A5C2ADB"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '4b7e8c2a-601e-0035-21bb-ae39e9000000', + 'x-ms-client-request-id', + '7cdcce46-02fc-441b-818f-275f909c7df9', + 'x-ms-version', + '2020-02-10', + 'x-ms-version-id', + '2020-10-30T12:48:56.8604923Z', + 'x-ms-is-current-version', + 'true', + 'x-ms-creation-time', + 'Fri, 30 Oct 2020 12:48:56 GMT', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-blob-type', + 'BlockBlob', + 'x-ms-server-encrypted', + 'true', + 'x-ms-access-tier', + 'Hot', + 'x-ms-access-tier-inferred', + 'true', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,x-ms-version-id,x-ms-is-current-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,Content-MD5,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,x-ms-server-encrypted,x-ms-access-tier,x-ms-access-tier-inferred,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 12:48:56 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .get('/container160406213443204111/blob160406213578407617') + .reply(206, "\u0001\u0002\u0003", [ + 'Content-Length', + '3', + 'Content-Type', + 'application/octet-stream', + 'Content-Range', + 'bytes 0-2/3', + 'Last-Modified', + 'Fri, 30 Oct 2020 12:48:56 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87CD22A5C2ADB"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '4b7e8cb3-601e-0035-0fbb-ae39e9000000', + 'x-ms-client-request-id', + '8b440850-d73c-43cf-89f2-a39be5bd6768', + 'x-ms-version', + '2020-02-10', + 'x-ms-version-id', + '2020-10-30T12:48:56.8604923Z', + 'x-ms-is-current-version', + 'true', + 'x-ms-creation-time', + 'Fri, 30 Oct 2020 12:48:56 GMT', + 'x-ms-blob-content-md5', + 'Uonfc331cyb83SJZevsfrA==', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-blob-type', + 'BlockBlob', + 'x-ms-server-encrypted', + 'true', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,x-ms-version-id,x-ms-is-current-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,x-ms-blob-content-md5,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,x-ms-server-encrypted,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 12:48:56 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .put('/container160406213443204111/blob160406213578407617', "\u0004\u0005\u0006\u0007") + .reply(201, "", [ + 'Content-Length', + '0', + 'Content-MD5', + 'prhTe5fVi0F9Pf3RAwsV0g==', + 'Last-Modified', + 'Fri, 30 Oct 2020 12:48:57 GMT', + 'ETag', + '"0x8D87CD22AE23C85"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '4b7e8d18-601e-0035-64bb-ae39e9000000', + 'x-ms-client-request-id', + 'a5734329-620b-4412-b9b2-46cb306d3cf1', + 'x-ms-version', + '2020-02-10', + 'x-ms-content-crc64', + '3s7Dbfd5f1U=', + 'x-ms-request-server-encrypted', + 'true', + 'x-ms-version-id', + '2020-10-30T12:48:57.7381269Z', + 'Date', + 'Fri, 30 Oct 2020 12:48:57 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .head('/container160406213443204111/blob160406213578407617') + .reply(200, "", [ + 'Content-Length', + '4', + 'Content-Type', + 'application/octet-stream', + 'Content-MD5', + 'prhTe5fVi0F9Pf3RAwsV0g==', + 'Last-Modified', + 'Fri, 30 Oct 2020 12:48:57 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87CD22AE23C85"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '4b7e8d80-601e-0035-3bbb-ae39e9000000', + 'x-ms-client-request-id', + '44406d00-8020-407f-b9ae-6e45aa4105ca', + 'x-ms-version', + '2020-02-10', + 'x-ms-version-id', + '2020-10-30T12:48:57.7381269Z', + 'x-ms-is-current-version', + 'true', + 'x-ms-creation-time', + 'Fri, 30 Oct 2020 12:48:57 GMT', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-blob-type', + 'BlockBlob', + 'x-ms-server-encrypted', + 'true', + 'x-ms-access-tier', + 'Hot', + 'x-ms-access-tier-inferred', + 'true', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,x-ms-version-id,x-ms-is-current-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,Content-MD5,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,x-ms-server-encrypted,x-ms-access-tier,x-ms-access-tier-inferred,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 12:48:57 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .get('/container160406213443204111/blob160406213578407617') + .reply(206, "\u0004\u0005\u0006\u0007", [ + 'Content-Length', + '4', + 'Content-Type', + 'application/octet-stream', + 'Content-Range', + 'bytes 0-3/4', + 'Last-Modified', + 'Fri, 30 Oct 2020 12:48:57 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87CD22AE23C85"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '4b7e8dff-601e-0035-2cbb-ae39e9000000', + 'x-ms-client-request-id', + 'a053a041-0092-47bc-80a6-fe5919b0f9ed', + 'x-ms-version', + '2020-02-10', + 'x-ms-version-id', + '2020-10-30T12:48:57.7381269Z', + 'x-ms-is-current-version', + 'true', + 'x-ms-creation-time', + 'Fri, 30 Oct 2020 12:48:57 GMT', + 'x-ms-blob-content-md5', + 'prhTe5fVi0F9Pf3RAwsV0g==', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-blob-type', + 'BlockBlob', + 'x-ms-server-encrypted', + 'true', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,x-ms-version-id,x-ms-is-current-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,x-ms-blob-content-md5,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,x-ms-server-encrypted,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 12:48:57 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .put('/container160406213443204111/blob160406213578407617', "\u0000\u0001\u0002\u0003\u0004") + .reply(201, "", [ + 'Content-Length', + '0', + 'Content-MD5', + '0FN03Dgdm1KAZEanHI55sQ==', + 'Last-Modified', + 'Fri, 30 Oct 2020 12:48:58 GMT', + 'ETag', + '"0x8D87CD22B682724"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '4b7e8e5d-601e-0035-7dbb-ae39e9000000', + 'x-ms-client-request-id', + 'b0535608-aa46-45fc-805f-ead18c0d17e9', + 'x-ms-version', + '2020-02-10', + 'x-ms-content-crc64', + 'u/GOqeRlINE=', + 'x-ms-request-server-encrypted', + 'true', + 'x-ms-version-id', + '2020-10-30T12:48:58.6167621Z', + 'Date', + 'Fri, 30 Oct 2020 12:48:58 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .head('/container160406213443204111/blob160406213578407617') + .reply(200, "", [ + 'Content-Length', + '5', + 'Content-Type', + 'application/octet-stream', + 'Content-MD5', + '0FN03Dgdm1KAZEanHI55sQ==', + 'Last-Modified', + 'Fri, 30 Oct 2020 12:48:58 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87CD22B682724"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '4b7e8eb5-601e-0035-4dbb-ae39e9000000', + 'x-ms-client-request-id', + 'e6f7b040-2d98-4506-98a7-fb970b800f1f', + 'x-ms-version', + '2020-02-10', + 'x-ms-version-id', + '2020-10-30T12:48:58.6167621Z', + 'x-ms-is-current-version', + 'true', + 'x-ms-creation-time', + 'Fri, 30 Oct 2020 12:48:58 GMT', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-blob-type', + 'BlockBlob', + 'x-ms-server-encrypted', + 'true', + 'x-ms-access-tier', + 'Hot', + 'x-ms-access-tier-inferred', + 'true', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,x-ms-version-id,x-ms-is-current-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,Content-MD5,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,x-ms-server-encrypted,x-ms-access-tier,x-ms-access-tier-inferred,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 12:48:58 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .get('/container160406213443204111/blob160406213578407617') + .reply(206, "\u0000\u0001\u0002\u0003\u0004", [ + 'Content-Length', + '5', + 'Content-Type', + 'application/octet-stream', + 'Content-Range', + 'bytes 0-4/5', + 'Last-Modified', + 'Fri, 30 Oct 2020 12:48:58 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87CD22B682724"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '4b7e8f19-601e-0035-2cbb-ae39e9000000', + 'x-ms-client-request-id', + '0a3aed6f-95ec-4e49-929d-ccf762c18788', + 'x-ms-version', + '2020-02-10', + 'x-ms-version-id', + '2020-10-30T12:48:58.6167621Z', + 'x-ms-is-current-version', + 'true', + 'x-ms-creation-time', + 'Fri, 30 Oct 2020 12:48:58 GMT', + 'x-ms-blob-content-md5', + '0FN03Dgdm1KAZEanHI55sQ==', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-blob-type', + 'BlockBlob', + 'x-ms-server-encrypted', + 'true', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,x-ms-version-id,x-ms-is-current-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,x-ms-blob-content-md5,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,x-ms-server-encrypted,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 12:48:58 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .delete('/container160406213443204111') + .query(true) + .reply(202, "", [ + 'Content-Length', + '0', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '4b7e8f7e-601e-0035-02bb-ae39e9000000', + 'x-ms-client-request-id', + '71980dc3-7f95-435f-80d2-0b94fb06bfef', + 'x-ms-version', + '2020-02-10', + 'Date', + 'Fri, 30 Oct 2020 12:48:58 GMT' +]); diff --git a/sdk/storage/storage-blob/review/storage-blob.api.md b/sdk/storage/storage-blob/review/storage-blob.api.md index 6348bb28591d..16513399f827 100644 --- a/sdk/storage/storage-blob/review/storage-blob.api.md +++ b/sdk/storage/storage-blob/review/storage-blob.api.md @@ -1283,7 +1283,9 @@ export class BlockBlobClient extends BlobClient { stageBlock(blockId: string, body: HttpRequestBody, contentLength: number, options?: BlockBlobStageBlockOptions): Promise; stageBlockFromURL(blockId: string, sourceURL: string, offset?: number, count?: number, options?: BlockBlobStageBlockFromURLOptions): Promise; upload(body: HttpRequestBody, contentLength: number, options?: BlockBlobUploadOptions): Promise; + // @deprecated uploadBrowserData(browserData: Blob | ArrayBuffer | ArrayBufferView, options?: BlockBlobParallelUploadOptions): Promise; + uploadData(data: Buffer | Blob | ArrayBuffer | ArrayBufferView, options?: BlockBlobParallelUploadOptions): Promise; uploadFile(filePath: string, options?: BlockBlobParallelUploadOptions): Promise; uploadStream(stream: Readable, bufferSize?: number, maxConcurrency?: number, options?: BlockBlobUploadStreamOptions): Promise; withSnapshot(snapshot: string): BlockBlobClient; diff --git a/sdk/storage/storage-blob/src/Clients.ts b/sdk/storage/storage-blob/src/Clients.ts index 38f9731f3246..7545cd2710f8 100644 --- a/sdk/storage/storage-blob/src/Clients.ts +++ b/sdk/storage/storage-blob/src/Clients.ts @@ -4365,6 +4365,68 @@ export class BlockBlobClient extends BlobClient { // High level functions + /** + * Uploads a Buffer(Node.js)/Blob(browsers)/ArrayBuffer/ArrayBufferView object to a BlockBlob. + * + * When data length is no more than the specifiled {@link BlockBlobParallelUploadOptions.maxSingleShotSize} (default is + * {@link BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES}), this method will use 1 {@link upload} call to finish the upload. + * Otherwise, this method will call {@link stageBlock} to upload blocks, and finally call {@link commitBlockList} + * to commit the block list. + * + * @export + * @param {Buffer | Blob | ArrayBuffer | ArrayBufferView} data Buffer(Node.js), Blob, ArrayBuffer or ArrayBufferView + * @param {BlockBlobParallelUploadOptions} [options] + * @returns {Promise} + * @memberof BlockBlobClient + */ + public async uploadData( + data: Buffer | Blob | ArrayBuffer | ArrayBufferView, + options: BlockBlobParallelUploadOptions = {} + ): Promise { + const { span, spanOptions } = createSpan("BlockBlobClient-uploadData", options.tracingOptions); + try { + if (isNode) { + let buffer: Buffer; + if (data instanceof Buffer) { + buffer = data; + } else if (data instanceof ArrayBuffer) { + buffer = Buffer.from(data); + } else { + data = data as ArrayBufferView; + buffer = Buffer.from(data.buffer, data.byteOffset, data.byteLength); + } + + return this.uploadSeekableInternal( + (offset: number, size: number): Buffer => { + return buffer.slice(offset, offset + size); + }, + buffer.byteLength, + { + ...options, + tracingOptions: { ...options!.tracingOptions, spanOptions } + } + ); + } else { + const browserBlob = new Blob([data]); + return this.uploadSeekableInternal( + (offset: number, size: number): Blob => { + return browserBlob.slice(offset, offset + size); + }, + browserBlob.size, + { ...options, tracingOptions: { ...options!.tracingOptions, spanOptions } } + ); + } + } catch (e) { + span.setStatus({ + code: CanonicalCode.UNKNOWN, + message: e.message + }); + throw e; + } finally { + span.end(); + } + } + /** * ONLY AVAILABLE IN BROWSERS. * @@ -4374,6 +4436,8 @@ export class BlockBlobClient extends BlobClient { * Otherwise, this method will call {@link stageBlock} to upload blocks, and finally call * {@link commitBlockList} to commit the block list. * + * @deprecated Use {@link uploadData} instead. + * * @export * @param {Blob | ArrayBuffer | ArrayBufferView} browserData Blob, File, ArrayBuffer or ArrayBufferView * @param {BlockBlobParallelUploadOptions} [options] Options to upload browser data. @@ -4390,7 +4454,7 @@ export class BlockBlobClient extends BlobClient { ); try { const browserBlob = new Blob([browserData]); - return await this.uploadSeekableBlob( + return await this.uploadSeekableInternal( (offset: number, size: number): Blob => { return browserBlob.slice(offset, offset + size); }, @@ -4409,23 +4473,23 @@ export class BlockBlobClient extends BlobClient { } /** - * ONLY AVAILABLE IN BROWSERS. * - * Uploads a browser {@link Blob} object to block blob. Requires a blobFactory as the data source, - * which need to return a {@link Blob} object with the offset and size provided. + * Uploads data to block blob. Requires a bodyFactory as the data source, + * which need to return a {@link HttpRequestBody} object with the offset and size provided. * - * When buffer length <= 256MB, this method will use 1 upload call to finish the upload. - * Otherwise, this method will call stageBlock to upload blocks, and finally call commitBlockList + * When data length is no more than the specifiled {@link BlockBlobParallelUploadOptions.maxSingleShotSize} (default is + * {@link BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES}), this method will use 1 {@link upload} call to finish the upload. + * Otherwise, this method will call {@link stageBlock} to upload blocks, and finally call {@link commitBlockList} * to commit the block list. * - * @param {(offset: number, size: number) => Blob} blobFactory + * @param {(offset: number, size: number) => HttpRequestBody} bodyFactory * @param {number} size size of the data to upload. * @param {BlockBlobParallelUploadOptions} [options] Options to Upload to Block Blob operation. * @returns {Promise} Response data for the Blob Upload operation. * @memberof BlockBlobClient */ - private async uploadSeekableBlob( - blobFactory: (offset: number, size: number) => Blob, + private async uploadSeekableInternal( + bodyFactory: (offset: number, size: number) => HttpRequestBody, size: number, options: BlockBlobParallelUploadOptions = {} ): Promise { @@ -4469,13 +4533,13 @@ export class BlockBlobClient extends BlobClient { } const { span, spanOptions } = createSpan( - "BlockBlobClient-UploadSeekableBlob", + "BlockBlobClient-uploadSeekableInternal", options.tracingOptions ); try { if (size <= options.maxSingleShotSize) { - return await this.upload(blobFactory(0, size), size, { + return await this.upload(bodyFactory(0, size), size, { ...options, tracingOptions: { ...options!.tracingOptions, spanOptions } }); @@ -4502,7 +4566,7 @@ export class BlockBlobClient extends BlobClient { const end = i === numBlocks - 1 ? size : start + options.blockSize!; const contentLength = end - start; blockList.push(blockID); - await this.stageBlock(blockID, blobFactory(start, contentLength), contentLength, { + await this.stageBlock(blockID, bodyFactory(start, contentLength), contentLength, { abortSignal: options.abortSignal, conditions: options.conditions, encryptionScope: options.encryptionScope, @@ -4557,13 +4621,15 @@ export class BlockBlobClient extends BlobClient { const { span, spanOptions } = createSpan("BlockBlobClient-uploadFile", options.tracingOptions); try { const size = (await fsStat(filePath)).size; - return await this.uploadResetableStream( - (offset, count) => - fsCreateReadStream(filePath, { - autoClose: true, - end: count ? offset + count - 1 : Infinity, - start: offset - }), + return await this.uploadSeekableInternal( + (offset, count) => { + return () => + fsCreateReadStream(filePath, { + autoClose: true, + end: count ? offset + count - 1 : Infinity, + start: offset + }); + }, size, { ...options, tracingOptions: { ...options!.tracingOptions, spanOptions } } ); @@ -4662,139 +4728,6 @@ export class BlockBlobClient extends BlobClient { span.end(); } } - - /** - * ONLY AVAILABLE IN NODE.JS RUNTIME. - * - * Accepts a Node.js Readable stream factory, and uploads in blocks to a block blob. - * The Readable stream factory must returns a Node.js Readable stream starting from the offset defined. The offset - * is the offset in the block blob to be uploaded. - * - * When buffer length <= 256MB, this method will use 1 upload call to finish the upload. - * Otherwise, this method will call {@link stageBlock} to upload blocks, and finally call {@link commitBlockList} - * to commit the block list. - * - * @export - * @param {(offset: number) => NodeJS.ReadableStream} streamFactory Returns a Node.js Readable stream starting - * from the offset defined - * @param {number} size Size of the block blob - * @param {BlockBlobParallelUploadOptions} [options] Options to Upload to Block Blob operation. - * @returns {(Promise)} Response data for the Blob Upload operation. - * @memberof BlockBlobClient - */ - private async uploadResetableStream( - streamFactory: (offset: number, count?: number) => NodeJS.ReadableStream, - size: number, - options: BlockBlobParallelUploadOptions = {} - ): Promise { - if (!options.blockSize) { - options.blockSize = 0; - } - if (options.blockSize < 0 || options.blockSize > BLOCK_BLOB_MAX_STAGE_BLOCK_BYTES) { - throw new RangeError( - `blockSize option must be >= 0 and <= ${BLOCK_BLOB_MAX_STAGE_BLOCK_BYTES}` - ); - } - - if (options.maxSingleShotSize !== 0 && !options.maxSingleShotSize) { - options.maxSingleShotSize = BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES; - } - if ( - options.maxSingleShotSize < 0 || - options.maxSingleShotSize > BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES - ) { - throw new RangeError( - `maxSingleShotSize option must be >= 0 and <= ${BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES}` - ); - } - - if (options.blockSize === 0) { - if (size > BLOCK_BLOB_MAX_BLOCKS * BLOCK_BLOB_MAX_STAGE_BLOCK_BYTES) { - throw new RangeError(`${size} is too larger to upload to a block blob.`); - } - if (size > options.maxSingleShotSize) { - options.blockSize = Math.ceil(size / BLOCK_BLOB_MAX_BLOCKS); - if (options.blockSize < DEFAULT_BLOB_DOWNLOAD_BLOCK_BYTES) { - options.blockSize = DEFAULT_BLOB_DOWNLOAD_BLOCK_BYTES; - } - } - } - if (!options.blobHTTPHeaders) { - options.blobHTTPHeaders = {}; - } - if (!options.conditions) { - options.conditions = {}; - } - - const { span, spanOptions } = createSpan( - "BlockBlobClient-uploadResetableStream", - options.tracingOptions - ); - - try { - if (size <= options.maxSingleShotSize) { - return await this.upload(() => streamFactory(0), size, { - ...options, - tracingOptions: { ...options!.tracingOptions, spanOptions } - }); - } - - const numBlocks: number = Math.floor((size - 1) / options.blockSize) + 1; - if (numBlocks > BLOCK_BLOB_MAX_BLOCKS) { - throw new RangeError( - `The buffer's size is too big or the BlockSize is too small;` + - `the number of blocks must be <= ${BLOCK_BLOB_MAX_BLOCKS}` - ); - } - - const blockList: string[] = []; - const blockIDPrefix = generateUuid(); - let transferProgress: number = 0; - - const batch = new Batch(options.concurrency); - for (let i = 0; i < numBlocks; i++) { - batch.addOperation( - async (): Promise => { - const blockID = generateBlockID(blockIDPrefix, i); - const start = options.blockSize! * i; - const end = i === numBlocks - 1 ? size : start + options.blockSize!; - const contentLength = end - start; - blockList.push(blockID); - await this.stageBlock( - blockID, - () => streamFactory(start, contentLength), - contentLength, - { - abortSignal: options.abortSignal, - conditions: options.conditions, - encryptionScope: options.encryptionScope, - tracingOptions: { ...options!.tracingOptions, spanOptions } - } - ); - // Update progress after block is successfully uploaded to server, in case of block trying - transferProgress += contentLength; - if (options.onProgress) { - options.onProgress({ loadedBytes: transferProgress }); - } - } - ); - } - await batch.do(); - - return await this.commitBlockList(blockList, { - ...options, - tracingOptions: { ...options!.tracingOptions, spanOptions } - }); - } catch (e) { - span.setStatus({ - code: CanonicalCode.UNKNOWN, - message: e.message - }); - throw e; - } finally { - span.end(); - } - } } /** diff --git a/sdk/storage/storage-blob/test/node/highlevel.node.spec.ts b/sdk/storage/storage-blob/test/node/highlevel.node.spec.ts index 22cf9be21413..2d9cf34e4c25 100644 --- a/sdk/storage/storage-blob/test/node/highlevel.node.spec.ts +++ b/sdk/storage/storage-blob/test/node/highlevel.node.spec.ts @@ -764,4 +764,32 @@ describe("Highlevel", () => { }); assert.equal((await blockBlobClient.getProperties()).accessTier, "Hot"); }); + + it("uploadData should work with Buffer, ArrayBuffer and ArrayBufferView", async () => { + const byteLength = 10; + const arrayBuf = new ArrayBuffer(byteLength); + const uint8Array = new Uint8Array(arrayBuf); + for (let i = 0; i < byteLength; i++) { + uint8Array[i] = i; + } + + await blockBlobClient.uploadData(arrayBuf); + const res = await blockBlobClient.downloadToBuffer(); + assert.ok(res.equals(Buffer.from(arrayBuf))); + + const uint8ArrayPartial = new Uint8Array(arrayBuf, 1, 3); + await blockBlobClient.uploadData(uint8ArrayPartial); + const res1 = await blockBlobClient.downloadToBuffer(); + assert.ok(res1.equals(Buffer.from(arrayBuf, 1, 3))); + + const uint16Array = new Uint16Array(arrayBuf, 4, 2); + await blockBlobClient.uploadData(uint16Array); + const res2 = await blockBlobClient.downloadToBuffer(); + assert.ok(res2.equals(Buffer.from(arrayBuf, 4, 2 * 2))); + + const buf = Buffer.from(arrayBuf, 0, 5); + await blockBlobClient.uploadData(buf); + const res3 = await blockBlobClient.downloadToBuffer(); + assert.ok(res3.equals(buf)); + }); }); diff --git a/sdk/storage/storage-file-datalake/README.md b/sdk/storage/storage-file-datalake/README.md index 319b4e0d6156..7667a425f298 100644 --- a/sdk/storage/storage-file-datalake/README.md +++ b/sdk/storage/storage-file-datalake/README.md @@ -75,6 +75,11 @@ There are differences between Node.js and browsers runtime. When getting started - Shared Access Signature(SAS) generation - `generateAccountSASQueryParameters()` - `generateDataLakeSASQueryParameters()` +- Parallel uploading and downloading. Note that `DataLakeFileClient.upload()` is available in both Node.js and browsers. + - `DataLakeFileClient.uploadFile()` + - `DataLakeFileClient.uploadStream()` + - `DataLakeFileClient.readToBuffer()` + - `DataLakeFileClient.readToFile()` ##### Features, interfaces, classes or functions only available in browsers diff --git a/sdk/storage/storage-file-datalake/recordings/node/highlevel_nodejs_only/recording_after_all_hook.js b/sdk/storage/storage-file-datalake/recordings/node/highlevel_nodejs_only/recording_after_all_hook.js index 580ce0c38135..3e19f2c3e370 100644 --- a/sdk/storage/storage-file-datalake/recordings/node/highlevel_nodejs_only/recording_after_all_hook.js +++ b/sdk/storage/storage-file-datalake/recordings/node/highlevel_nodejs_only/recording_after_all_hook.js @@ -1,5 +1,5 @@ let nock = require('nock'); -module.exports.hash = "0697e332fa9a18057fbe5715cdae2b0c"; +module.exports.hash = "317a29501ad34bbbedc35c3dc7695de7"; module.exports.testInfo = {"uniqueName":{},"newDate":{}} diff --git a/sdk/storage/storage-file-datalake/recordings/node/highlevel_nodejs_only/recording_before_all_hook.js b/sdk/storage/storage-file-datalake/recordings/node/highlevel_nodejs_only/recording_before_all_hook.js index adee042c67e0..3e19f2c3e370 100644 --- a/sdk/storage/storage-file-datalake/recordings/node/highlevel_nodejs_only/recording_before_all_hook.js +++ b/sdk/storage/storage-file-datalake/recordings/node/highlevel_nodejs_only/recording_before_all_hook.js @@ -1,5 +1,5 @@ let nock = require('nock'); -module.exports.hash = "4bd8dad5861576a9d3600f6f4f6f37fe"; +module.exports.hash = "317a29501ad34bbbedc35c3dc7695de7"; module.exports.testInfo = {"uniqueName":{},"newDate":{}} diff --git a/sdk/storage/storage-file-datalake/recordings/node/highlevel_nodejs_only/recording_upload_arraybuffer_and_arraybufferview_should_succeed.js b/sdk/storage/storage-file-datalake/recordings/node/highlevel_nodejs_only/recording_upload_arraybuffer_and_arraybufferview_should_succeed.js new file mode 100644 index 000000000000..662fa7dba6e6 --- /dev/null +++ b/sdk/storage/storage-file-datalake/recordings/node/highlevel_nodejs_only/recording_upload_arraybuffer_and_arraybufferview_should_succeed.js @@ -0,0 +1,495 @@ +let nock = require('nock'); + +module.exports.hash = "317a29501ad34bbbedc35c3dc7695de7"; + +module.exports.testInfo = {"uniqueName":{"filesystem":"filesystem160403933726809292","file":"file160403933869909908"},"newDate":{}} + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .put('/filesystem160403933726809292') + .query(true) + .reply(201, "", [ + 'Content-Length', + '0', + 'Last-Modified', + 'Fri, 30 Oct 2020 06:28:58 GMT', + 'ETag', + '"0x8D87C9D157B615D"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'b2801a26-b01e-009e-5885-ae3cd9000000', + 'x-ms-client-request-id', + '4282d7df-5fac-4615-bd7c-abca6735fc6f', + 'x-ms-version', + '2020-02-10', + 'Date', + 'Fri, 30 Oct 2020 06:28:57 GMT' +]); + +nock('https://fakestorageaccount.dfs.core.windows.net:443', {"encodedQueryParams":true}) + .put('/filesystem160403933726809292/file160403933869909908') + .query(true) + .reply(201, "", [ + 'Last-Modified', + 'Fri, 30 Oct 2020 06:29:02 GMT', + 'ETag', + '"0x8D87C9D18271DC3"', + 'Server', + 'Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '3641220f-301f-000c-0185-aeab6f000000', + 'x-ms-version', + '2020-02-10', + 'x-ms-client-request-id', + 'ee028588-a40c-4355-a9eb-c84f4dcad62a', + 'Date', + 'Fri, 30 Oct 2020 06:29:02 GMT', + 'Content-Length', + '0' +]); + +nock('https://fakestorageaccount.dfs.core.windows.net:443', {"encodedQueryParams":true}) + .patch('/filesystem160403933726809292/file160403933869909908', "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t") + .query(true) + .reply(202, "", [ + 'Server', + 'Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-server-encrypted', + 'true', + 'x-ms-request-id', + '36412214-301f-000c-0385-aeab6f000000', + 'x-ms-version', + '2020-02-10', + 'x-ms-client-request-id', + '1121a936-5a68-47cc-a8dd-d47678b8caab', + 'Date', + 'Fri, 30 Oct 2020 06:29:03 GMT', + 'Content-Length', + '0' +]); + +nock('https://fakestorageaccount.dfs.core.windows.net:443', {"encodedQueryParams":true}) + .patch('/filesystem160403933726809292/file160403933869909908') + .query(true) + .reply(200, "", [ + 'Last-Modified', + 'Fri, 30 Oct 2020 06:29:03 GMT', + 'ETag', + '"0x8D87C9D188392B7"', + 'Server', + 'Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-server-encrypted', + 'false', + 'x-ms-request-id', + '36412217-301f-000c-0685-aeab6f000000', + 'x-ms-version', + '2020-02-10', + 'x-ms-client-request-id', + 'af3364e7-5345-44a8-8ecc-55f23e03b0f0', + 'Date', + 'Fri, 30 Oct 2020 06:29:03 GMT', + 'Content-Length', + '0' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .head('/filesystem160403933726809292/file160403933869909908') + .reply(200, "", [ + 'Content-Length', + '10', + 'Content-Type', + 'application/octet-stream', + 'Last-Modified', + 'Fri, 30 Oct 2020 06:29:03 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87C9D188392B7"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'b2801fc7-b01e-009e-1485-ae3cd9000000', + 'x-ms-client-request-id', + '1bf051c0-a500-4bad-9da3-ed93fbcbd483', + 'x-ms-version', + '2020-02-10', + 'x-ms-creation-time', + 'Fri, 30 Oct 2020 06:29:02 GMT', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-blob-type', + 'BlockBlob', + 'x-ms-server-encrypted', + 'true', + 'x-ms-access-tier', + 'Hot', + 'x-ms-access-tier-inferred', + 'true', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,x-ms-server-encrypted,x-ms-access-tier,x-ms-access-tier-inferred,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 06:29:03 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .get('/filesystem160403933726809292/file160403933869909908') + .reply(206, "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t", [ + 'Content-Length', + '10', + 'Content-Type', + 'application/octet-stream', + 'Content-Range', + 'bytes 0-9/10', + 'Last-Modified', + 'Fri, 30 Oct 2020 06:29:03 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87C9D188392B7"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'b2802033-b01e-009e-6985-ae3cd9000000', + 'x-ms-client-request-id', + '9849968a-8e18-4b04-a7d1-750b33dfc62b', + 'x-ms-version', + '2020-02-10', + 'x-ms-creation-time', + 'Fri, 30 Oct 2020 06:29:02 GMT', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-blob-type', + 'BlockBlob', + 'x-ms-server-encrypted', + 'true', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,x-ms-server-encrypted,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 06:29:03 GMT' +]); + +nock('https://fakestorageaccount.dfs.core.windows.net:443', {"encodedQueryParams":true}) + .put('/filesystem160403933726809292/file160403933869909908') + .query(true) + .reply(201, "", [ + 'Last-Modified', + 'Fri, 30 Oct 2020 06:29:04 GMT', + 'ETag', + '"0x8D87C9D190B4C8F"', + 'Server', + 'Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '3641221c-301f-000c-0b85-aeab6f000000', + 'x-ms-version', + '2020-02-10', + 'x-ms-client-request-id', + 'bb4aeb34-077f-4a16-b407-0aef0b201028', + 'Date', + 'Fri, 30 Oct 2020 06:29:04 GMT', + 'Content-Length', + '0' +]); + +nock('https://fakestorageaccount.dfs.core.windows.net:443', {"encodedQueryParams":true}) + .patch('/filesystem160403933726809292/file160403933869909908', "\u0001\u0002\u0003") + .query(true) + .reply(202, "", [ + 'Server', + 'Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-server-encrypted', + 'true', + 'x-ms-request-id', + '3641221e-301f-000c-0d85-aeab6f000000', + 'x-ms-version', + '2020-02-10', + 'x-ms-client-request-id', + '45e87dca-c67e-484d-95e7-5bb11a54ade0', + 'Date', + 'Fri, 30 Oct 2020 06:29:04 GMT', + 'Content-Length', + '0' +]); + +nock('https://fakestorageaccount.dfs.core.windows.net:443', {"encodedQueryParams":true}) + .patch('/filesystem160403933726809292/file160403933869909908') + .query(true) + .reply(200, "", [ + 'Last-Modified', + 'Fri, 30 Oct 2020 06:29:05 GMT', + 'ETag', + '"0x8D87C9D1965D27D"', + 'Server', + 'Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-server-encrypted', + 'false', + 'x-ms-request-id', + '36412220-301f-000c-0f85-aeab6f000000', + 'x-ms-version', + '2020-02-10', + 'x-ms-client-request-id', + '5639daf2-b7e6-4603-be31-869ce2bc2086', + 'Date', + 'Fri, 30 Oct 2020 06:29:04 GMT', + 'Content-Length', + '0' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .head('/filesystem160403933726809292/file160403933869909908') + .reply(200, "", [ + 'Content-Length', + '3', + 'Content-Type', + 'application/octet-stream', + 'Last-Modified', + 'Fri, 30 Oct 2020 06:29:05 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87C9D1965D27D"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'b2802180-b01e-009e-7d85-ae3cd9000000', + 'x-ms-client-request-id', + '8588a60c-2aeb-4ba8-8d6b-12d40c0d56dc', + 'x-ms-version', + '2020-02-10', + 'x-ms-creation-time', + 'Fri, 30 Oct 2020 06:29:04 GMT', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-blob-type', + 'BlockBlob', + 'x-ms-server-encrypted', + 'true', + 'x-ms-access-tier', + 'Hot', + 'x-ms-access-tier-inferred', + 'true', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,x-ms-server-encrypted,x-ms-access-tier,x-ms-access-tier-inferred,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 06:29:04 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .get('/filesystem160403933726809292/file160403933869909908') + .reply(206, "\u0001\u0002\u0003", [ + 'Content-Length', + '3', + 'Content-Type', + 'application/octet-stream', + 'Content-Range', + 'bytes 0-2/3', + 'Last-Modified', + 'Fri, 30 Oct 2020 06:29:05 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87C9D1965D27D"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'b28021ee-b01e-009e-5785-ae3cd9000000', + 'x-ms-client-request-id', + '52fd9f09-9026-4360-b6ea-5ff0a42ed288', + 'x-ms-version', + '2020-02-10', + 'x-ms-creation-time', + 'Fri, 30 Oct 2020 06:29:04 GMT', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-blob-type', + 'BlockBlob', + 'x-ms-server-encrypted', + 'true', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,x-ms-server-encrypted,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 06:29:04 GMT' +]); + +nock('https://fakestorageaccount.dfs.core.windows.net:443', {"encodedQueryParams":true}) + .put('/filesystem160403933726809292/file160403933869909908') + .query(true) + .reply(201, "", [ + 'Last-Modified', + 'Fri, 30 Oct 2020 06:29:05 GMT', + 'ETag', + '"0x8D87C9D19F25943"', + 'Server', + 'Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '36412221-301f-000c-1085-aeab6f000000', + 'x-ms-version', + '2020-02-10', + 'x-ms-client-request-id', + 'c0c72a6e-1228-44e4-a9ff-f8d50e2c21ea', + 'Date', + 'Fri, 30 Oct 2020 06:29:05 GMT', + 'Content-Length', + '0' +]); + +nock('https://fakestorageaccount.dfs.core.windows.net:443', {"encodedQueryParams":true}) + .patch('/filesystem160403933726809292/file160403933869909908', "\u0004\u0005\u0006\u0007") + .query(true) + .reply(202, "", [ + 'Server', + 'Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-server-encrypted', + 'true', + 'x-ms-request-id', + '36412222-301f-000c-1185-aeab6f000000', + 'x-ms-version', + '2020-02-10', + 'x-ms-client-request-id', + 'fe79cef6-bd0d-4e3b-ab94-880362f18c09', + 'Date', + 'Fri, 30 Oct 2020 06:29:06 GMT', + 'Content-Length', + '0' +]); + +nock('https://fakestorageaccount.dfs.core.windows.net:443', {"encodedQueryParams":true}) + .patch('/filesystem160403933726809292/file160403933869909908') + .query(true) + .reply(200, "", [ + 'Last-Modified', + 'Fri, 30 Oct 2020 06:29:06 GMT', + 'ETag', + '"0x8D87C9D1A4EDBF7"', + 'Server', + 'Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-server-encrypted', + 'false', + 'x-ms-request-id', + '36412223-301f-000c-1285-aeab6f000000', + 'x-ms-version', + '2020-02-10', + 'x-ms-client-request-id', + '6f10ae13-fc74-4973-a9b9-5ab39c914e17', + 'Date', + 'Fri, 30 Oct 2020 06:29:06 GMT', + 'Content-Length', + '0' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .head('/filesystem160403933726809292/file160403933869909908') + .reply(200, "", [ + 'Content-Length', + '4', + 'Content-Type', + 'application/octet-stream', + 'Last-Modified', + 'Fri, 30 Oct 2020 06:29:06 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87C9D1A4EDBF7"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'b280232f-b01e-009e-7185-ae3cd9000000', + 'x-ms-client-request-id', + '16ca66a1-b9ea-4491-8edd-3d0521fb768a', + 'x-ms-version', + '2020-02-10', + 'x-ms-creation-time', + 'Fri, 30 Oct 2020 06:29:05 GMT', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-blob-type', + 'BlockBlob', + 'x-ms-server-encrypted', + 'true', + 'x-ms-access-tier', + 'Hot', + 'x-ms-access-tier-inferred', + 'true', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,x-ms-server-encrypted,x-ms-access-tier,x-ms-access-tier-inferred,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 06:29:06 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .get('/filesystem160403933726809292/file160403933869909908') + .reply(206, "\u0004\u0005\u0006\u0007", [ + 'Content-Length', + '4', + 'Content-Type', + 'application/octet-stream', + 'Content-Range', + 'bytes 0-3/4', + 'Last-Modified', + 'Fri, 30 Oct 2020 06:29:06 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87C9D1A4EDBF7"', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'b28023a1-b01e-009e-5885-ae3cd9000000', + 'x-ms-client-request-id', + 'e028f6cf-73c1-4d02-be9e-f525c16e8606', + 'x-ms-version', + '2020-02-10', + 'x-ms-creation-time', + 'Fri, 30 Oct 2020 06:29:05 GMT', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-blob-type', + 'BlockBlob', + 'x-ms-server-encrypted', + 'true', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-creation-time,x-ms-lease-status,x-ms-lease-state,x-ms-blob-type,x-ms-server-encrypted,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 06:29:06 GMT' +]); + +nock('https://fakestorageaccount.blob.core.windows.net:443', {"encodedQueryParams":true}) + .delete('/filesystem160403933726809292') + .query(true) + .reply(202, "", [ + 'Content-Length', + '0', + 'Server', + 'Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'b2802429-b01e-009e-4c85-ae3cd9000000', + 'x-ms-client-request-id', + '31149b2f-23c7-443b-97b7-d19e9aa15c25', + 'x-ms-version', + '2020-02-10', + 'Date', + 'Fri, 30 Oct 2020 06:29:07 GMT' +]); diff --git a/sdk/storage/storage-file-datalake/src/clients.ts b/sdk/storage/storage-file-datalake/src/clients.ts index bae80d10734c..09671bb565e2 100644 --- a/sdk/storage/storage-file-datalake/src/clients.ts +++ b/sdk/storage/storage-file-datalake/src/clients.ts @@ -1539,7 +1539,7 @@ export class DataLakeFileClient extends DataLakePathClient { ); try { const size = (await fsStat(filePath)).size; - return await this.uploadData( + return await this.uploadSeekableInternal( (offset: number, size: number) => { return () => fsCreateReadStream(filePath, { @@ -1576,17 +1576,30 @@ export class DataLakeFileClient extends DataLakePathClient { ): Promise { const { span, spanOptions } = createSpan("DataLakeFileClient-upload", options.tracingOptions); try { - if (isNode && data instanceof Buffer) { - return this.uploadData( + if (isNode) { + let buffer: Buffer; + if (data instanceof Buffer) { + buffer = data; + } else if (data instanceof ArrayBuffer) { + buffer = Buffer.from(data); + } else { + data = data as ArrayBufferView; + buffer = Buffer.from(data.buffer, data.byteOffset, data.byteLength); + } + + return this.uploadSeekableInternal( (offset: number, size: number): Buffer => { - return data.slice(offset, offset + size); + return buffer.slice(offset, offset + size); }, - data.length, - { ...options, tracingOptions: { ...options!.tracingOptions, spanOptions } } + buffer.length, + { + ...options, + tracingOptions: { ...options!.tracingOptions, spanOptions } + } ); } else { const browserBlob = new Blob([data]); - return this.uploadData( + return this.uploadSeekableInternal( (offset: number, size: number): Blob => { return browserBlob.slice(offset, offset + size); }, @@ -1605,11 +1618,8 @@ export class DataLakeFileClient extends DataLakePathClient { } } - private async uploadData( - contentFactory: - | ((offset: number, size: number) => Buffer) - | ((offset: number, size: number) => Blob) - | ((offset: number, size: number) => () => NodeJS.ReadableStream), + private async uploadSeekableInternal( + bodyFactory: (offset: number, count: number) => HttpRequestBody, size: number, options: FileParallelUploadOptions = {} ): Promise { @@ -1673,7 +1683,7 @@ export class DataLakeFileClient extends DataLakePathClient { // When buffer length <= singleUploadThreshold, this method will use one append/flush call to finish the upload. if (size <= options.singleUploadThreshold) { - await this.append(contentFactory(0, size), 0, size, { + await this.append(bodyFactory(0, size), 0, size, { abortSignal: options.abortSignal, conditions: options.conditions, onProgress: options.onProgress, @@ -1706,7 +1716,7 @@ export class DataLakeFileClient extends DataLakePathClient { const start = options.chunkSize! * i; const end = i === numBlocks - 1 ? size : start + options.chunkSize!; const contentLength = end - start; - await this.append(contentFactory(start, contentLength), start, contentLength, { + await this.append(bodyFactory(start, contentLength), start, contentLength, { abortSignal: options.abortSignal, conditions: options.conditions, tracingOptions: { ...options!.tracingOptions, spanOptions } diff --git a/sdk/storage/storage-file-datalake/test/node/highlevel.node.spec.ts b/sdk/storage/storage-file-datalake/test/node/highlevel.node.spec.ts index ea0399330956..6ac264561820 100644 --- a/sdk/storage/storage-file-datalake/test/node/highlevel.node.spec.ts +++ b/sdk/storage/storage-file-datalake/test/node/highlevel.node.spec.ts @@ -540,6 +540,29 @@ describe("Highlevel Node.js only", () => { } }).timeout(timeoutForLargeFileUploadingTest); + it("upload ArrayBuffer and ArrayBufferView should succeed", async () => { + const byteLength = 10; + const arrayBuf = new ArrayBuffer(byteLength); + const uint8Array = new Uint8Array(arrayBuf); + for (let i = 0; i < byteLength; i++) { + uint8Array[i] = i; + } + + await fileClient.upload(arrayBuf); + const res = await fileClient.readToBuffer(); + assert.ok(res.equals(Buffer.from(arrayBuf))); + + const uint8ArrayPartial = new Uint8Array(arrayBuf, 1, 3); + await fileClient.upload(uint8ArrayPartial); + const res1 = await fileClient.readToBuffer(); + assert.ok(res1.equals(Buffer.from(arrayBuf, 1, 3))); + + const uint16Array = new Uint16Array(arrayBuf, 4, 2); + await fileClient.upload(uint16Array); + const res2 = await fileClient.readToBuffer(); + assert.ok(res2.equals(Buffer.from(arrayBuf, 4, 2 * 2))); + }); + it("readToBuffer should work", async () => { recorder.skip("node", "Temp file - recorder doesn't support saving the file"); diff --git a/sdk/storage/storage-file-share/README.md b/sdk/storage/storage-file-share/README.md index 40476a02fb23..f5bf4c5b9199 100644 --- a/sdk/storage/storage-file-share/README.md +++ b/sdk/storage/storage-file-share/README.md @@ -76,7 +76,7 @@ There are differences between Node.js and browsers runtime. When getting started - Shared Access Signature(SAS) generation - `generateAccountSASQueryParameters()` - `generateFileSASQueryParameters()` -- Parallel uploading and downloading +- Parallel uploading and downloading. Note that `ShareFileClient.uploadData()` is available in both Node.js and browsers. - `ShareFileClient.uploadFile()` - `ShareFileClient.uploadStream()` - `ShareFileClient.downloadToBuffer()` @@ -84,8 +84,7 @@ There are differences between Node.js and browsers runtime. When getting started ##### Following features, interfaces, classes or functions are only available in browsers -- Parallel uploading and downloading - - `ShareFileClient.uploadBrowserData()` +N/A ### JavaScript Bundle diff --git a/sdk/storage/storage-file-share/recordings/node/highlevel_nodejs_only/recording_uploaddata_should_work_with_buffer_arraybuffer_and_arraybufferview.js b/sdk/storage/storage-file-share/recordings/node/highlevel_nodejs_only/recording_uploaddata_should_work_with_buffer_arraybuffer_and_arraybufferview.js new file mode 100644 index 000000000000..494a3d3e4d2a --- /dev/null +++ b/sdk/storage/storage-file-share/recordings/node/highlevel_nodejs_only/recording_uploaddata_should_work_with_buffer_arraybuffer_and_arraybufferview.js @@ -0,0 +1,743 @@ +let nock = require('nock'); + +module.exports.hash = "77e064e623ab07ce5f665c69eece0f57"; + +module.exports.testInfo = {"uniqueName":{"share":"share160404454791204048","dir":"dir160404454936709291","file":"file160404454967306008"},"newDate":{}} + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160404454791204048') + .query(true) + .reply(201, "", [ + 'Content-Length', + '0', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:49 GMT', + 'ETag', + '"0x8D87CA9374DC779"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671b9fec-001a-008a-3392-ae0e4c000000', + 'x-ms-client-request-id', + 'e0dfacdf-cac0-447e-bb87-ec65795e6827', + 'x-ms-version', + '2020-02-10', + 'Date', + 'Fri, 30 Oct 2020 07:55:48 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160404454791204048/dir160404454936709291') + .query(true) + .reply(201, "", [ + 'Content-Length', + '0', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:49 GMT', + 'ETag', + '"0x8D87CA9377F42C4"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671b9fef-001a-008a-3492-ae0e4c000000', + 'x-ms-client-request-id', + 'faaf5515-48eb-465c-bb6e-2c44f7fb8cbc', + 'x-ms-version', + '2020-02-10', + 'x-ms-file-change-time', + '2020-10-30T07:55:49.5329476Z', + 'x-ms-file-last-write-time', + '2020-10-30T07:55:49.5329476Z', + 'x-ms-file-creation-time', + '2020-10-30T07:55:49.5329476Z', + 'x-ms-file-permission-key', + '18253506462963126402*10775527834424002315', + 'x-ms-file-attributes', + 'Directory', + 'x-ms-file-id', + '13835128424026341376', + 'x-ms-file-parent-id', + '0', + 'x-ms-request-server-encrypted', + 'true', + 'Date', + 'Fri, 30 Oct 2020 07:55:48 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160404454791204048/dir160404454936709291/file160404454967306008') + .reply(201, "", [ + 'Content-Length', + '0', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:49 GMT', + 'ETag', + '"0x8D87CA937AD8748"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671b9ff0-001a-008a-3592-ae0e4c000000', + 'x-ms-client-request-id', + 'd8d47dfb-c1d3-4b00-a02b-4de94858779d', + 'x-ms-version', + '2020-02-10', + 'x-ms-file-change-time', + '2020-10-30T07:55:49.8361672Z', + 'x-ms-file-last-write-time', + '2020-10-30T07:55:49.8361672Z', + 'x-ms-file-creation-time', + '2020-10-30T07:55:49.8361672Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'x-ms-request-server-encrypted', + 'true', + 'Date', + 'Fri, 30 Oct 2020 07:55:49 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160404454791204048/dir160404454936709291/file160404454967306008', "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t") + .query(true) + .reply(201, "", [ + 'Content-Length', + '0', + 'Content-MD5', + 'xWvVSA9uVBPLYqCtlmZhOg==', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:50 GMT', + 'ETag', + '"0x8D87CA937DC6809"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671b9ff1-001a-008a-3692-ae0e4c000000', + 'x-ms-client-request-id', + '0c7c4598-d9a6-46ef-af41-c65b992ba1d1', + 'x-ms-version', + '2020-02-10', + 'x-ms-request-server-encrypted', + 'true', + 'Date', + 'Fri, 30 Oct 2020 07:55:49 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .head('/share160404454791204048/dir160404454936709291/file160404454967306008') + .reply(200, "", [ + 'Content-Length', + '10', + 'Content-Type', + 'application/octet-stream', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:50 GMT', + 'ETag', + '"0x8D87CA937DC6809"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671b9ff2-001a-008a-3792-ae0e4c000000', + 'x-ms-client-request-id', + '425ab7aa-b433-4f45-9990-ea379e5291fa', + 'x-ms-version', + '2020-02-10', + 'x-ms-type', + 'File', + 'x-ms-server-encrypted', + 'true', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-file-change-time', + '2020-10-30T07:55:49.8361672Z', + 'x-ms-file-last-write-time', + '2020-10-30T07:55:49.8361672Z', + 'x-ms-file-creation-time', + '2020-10-30T07:55:49.8361672Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-type,x-ms-server-encrypted,x-ms-lease-status,x-ms-lease-state,x-ms-file-change-time,x-ms-file-last-write-time,x-ms-file-creation-time,x-ms-file-permission-key,x-ms-file-attributes,x-ms-file-id,x-ms-file-parent-id,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 07:55:49 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .get('/share160404454791204048/dir160404454936709291/file160404454967306008') + .reply(206, "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t", [ + 'Content-Length', + '10', + 'Content-Type', + 'application/octet-stream', + 'Content-Range', + 'bytes 0-9/10', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:50 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87CA937DC6809"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671b9ff4-001a-008a-3892-ae0e4c000000', + 'x-ms-client-request-id', + '49645f25-119e-4294-9462-8664b2fc5c3a', + 'x-ms-version', + '2020-02-10', + 'x-ms-type', + 'File', + 'x-ms-server-encrypted', + 'true', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-file-change-time', + '2020-10-30T07:55:49.8361672Z', + 'x-ms-file-last-write-time', + '2020-10-30T07:55:49.8361672Z', + 'x-ms-file-creation-time', + '2020-10-30T07:55:49.8361672Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-type,x-ms-server-encrypted,x-ms-lease-status,x-ms-lease-state,x-ms-file-change-time,x-ms-file-last-write-time,x-ms-file-creation-time,x-ms-file-permission-key,x-ms-file-attributes,x-ms-file-id,x-ms-file-parent-id,Content-Range,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 07:55:50 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160404454791204048/dir160404454936709291/file160404454967306008') + .reply(201, "", [ + 'Content-Length', + '0', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:51 GMT', + 'ETag', + '"0x8D87CA93868E323"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671b9ff5-001a-008a-3992-ae0e4c000000', + 'x-ms-client-request-id', + 'c077707d-d0b1-43d3-847c-2a25458cea33', + 'x-ms-version', + '2020-02-10', + 'x-ms-file-change-time', + '2020-10-30T07:55:51.0640419Z', + 'x-ms-file-last-write-time', + '2020-10-30T07:55:51.0640419Z', + 'x-ms-file-creation-time', + '2020-10-30T07:55:51.0640419Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'x-ms-request-server-encrypted', + 'true', + 'Date', + 'Fri, 30 Oct 2020 07:55:50 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160404454791204048/dir160404454936709291/file160404454967306008', "\u0001\u0002\u0003") + .query(true) + .reply(201, "", [ + 'Content-Length', + '0', + 'Content-MD5', + 'Uonfc331cyb83SJZevsfrA==', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:51 GMT', + 'ETag', + '"0x8D87CA93898391D"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671b9ff7-001a-008a-3a92-ae0e4c000000', + 'x-ms-client-request-id', + 'af10984c-0349-49d7-8b08-475b98293e73', + 'x-ms-version', + '2020-02-10', + 'x-ms-request-server-encrypted', + 'true', + 'Date', + 'Fri, 30 Oct 2020 07:55:50 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .head('/share160404454791204048/dir160404454936709291/file160404454967306008') + .reply(200, "", [ + 'Content-Length', + '3', + 'Content-Type', + 'application/octet-stream', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:51 GMT', + 'ETag', + '"0x8D87CA93898391D"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671b9ff8-001a-008a-3b92-ae0e4c000000', + 'x-ms-client-request-id', + '6e93cdf4-526f-4e8b-8c92-53c3495acc72', + 'x-ms-version', + '2020-02-10', + 'x-ms-type', + 'File', + 'x-ms-server-encrypted', + 'true', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-file-change-time', + '2020-10-30T07:55:51.0640419Z', + 'x-ms-file-last-write-time', + '2020-10-30T07:55:51.0640419Z', + 'x-ms-file-creation-time', + '2020-10-30T07:55:51.0640419Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-type,x-ms-server-encrypted,x-ms-lease-status,x-ms-lease-state,x-ms-file-change-time,x-ms-file-last-write-time,x-ms-file-creation-time,x-ms-file-permission-key,x-ms-file-attributes,x-ms-file-id,x-ms-file-parent-id,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 07:55:50 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .get('/share160404454791204048/dir160404454936709291/file160404454967306008') + .reply(206, "\u0001\u0002\u0003", [ + 'Content-Length', + '3', + 'Content-Type', + 'application/octet-stream', + 'Content-Range', + 'bytes 0-2/3', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:51 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87CA93898391D"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671b9ff9-001a-008a-3c92-ae0e4c000000', + 'x-ms-client-request-id', + '09e77a3c-cb63-431f-9cae-ce6d01c4fbbf', + 'x-ms-version', + '2020-02-10', + 'x-ms-type', + 'File', + 'x-ms-server-encrypted', + 'true', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-file-change-time', + '2020-10-30T07:55:51.0640419Z', + 'x-ms-file-last-write-time', + '2020-10-30T07:55:51.0640419Z', + 'x-ms-file-creation-time', + '2020-10-30T07:55:51.0640419Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-type,x-ms-server-encrypted,x-ms-lease-status,x-ms-lease-state,x-ms-file-change-time,x-ms-file-last-write-time,x-ms-file-creation-time,x-ms-file-permission-key,x-ms-file-attributes,x-ms-file-id,x-ms-file-parent-id,Content-Range,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 07:55:51 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160404454791204048/dir160404454936709291/file160404454967306008') + .reply(201, "", [ + 'Content-Length', + '0', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:52 GMT', + 'ETag', + '"0x8D87CA939263B57"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671b9ffa-001a-008a-3d92-ae0e4c000000', + 'x-ms-client-request-id', + 'c91c8ec8-a70a-424f-803a-d01a599ebab5', + 'x-ms-version', + '2020-02-10', + 'x-ms-file-change-time', + '2020-10-30T07:55:52.3049303Z', + 'x-ms-file-last-write-time', + '2020-10-30T07:55:52.3049303Z', + 'x-ms-file-creation-time', + '2020-10-30T07:55:52.3049303Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'x-ms-request-server-encrypted', + 'true', + 'Date', + 'Fri, 30 Oct 2020 07:55:51 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160404454791204048/dir160404454936709291/file160404454967306008', "\u0004\u0005\u0006\u0007") + .query(true) + .reply(201, "", [ + 'Content-Length', + '0', + 'Content-MD5', + 'prhTe5fVi0F9Pf3RAwsV0g==', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:52 GMT', + 'ETag', + '"0x8D87CA939547FC9"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671b9ffb-001a-008a-3e92-ae0e4c000000', + 'x-ms-client-request-id', + 'f85539a0-9886-4d54-9c75-e304046814ff', + 'x-ms-version', + '2020-02-10', + 'x-ms-request-server-encrypted', + 'true', + 'Date', + 'Fri, 30 Oct 2020 07:55:51 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .head('/share160404454791204048/dir160404454936709291/file160404454967306008') + .reply(200, "", [ + 'Content-Length', + '4', + 'Content-Type', + 'application/octet-stream', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:52 GMT', + 'ETag', + '"0x8D87CA939547FC9"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671b9ffc-001a-008a-3f92-ae0e4c000000', + 'x-ms-client-request-id', + '37e90680-3162-479f-b5af-99d9a8341ab6', + 'x-ms-version', + '2020-02-10', + 'x-ms-type', + 'File', + 'x-ms-server-encrypted', + 'true', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-file-change-time', + '2020-10-30T07:55:52.3049303Z', + 'x-ms-file-last-write-time', + '2020-10-30T07:55:52.3049303Z', + 'x-ms-file-creation-time', + '2020-10-30T07:55:52.3049303Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-type,x-ms-server-encrypted,x-ms-lease-status,x-ms-lease-state,x-ms-file-change-time,x-ms-file-last-write-time,x-ms-file-creation-time,x-ms-file-permission-key,x-ms-file-attributes,x-ms-file-id,x-ms-file-parent-id,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 07:55:52 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .get('/share160404454791204048/dir160404454936709291/file160404454967306008') + .reply(206, "\u0004\u0005\u0006\u0007", [ + 'Content-Length', + '4', + 'Content-Type', + 'application/octet-stream', + 'Content-Range', + 'bytes 0-3/4', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:52 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87CA939547FC9"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671ba000-001a-008a-4292-ae0e4c000000', + 'x-ms-client-request-id', + 'bc7248ee-7e51-4665-becd-69fc7b5aba9a', + 'x-ms-version', + '2020-02-10', + 'x-ms-type', + 'File', + 'x-ms-server-encrypted', + 'true', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-file-change-time', + '2020-10-30T07:55:52.3049303Z', + 'x-ms-file-last-write-time', + '2020-10-30T07:55:52.3049303Z', + 'x-ms-file-creation-time', + '2020-10-30T07:55:52.3049303Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-type,x-ms-server-encrypted,x-ms-lease-status,x-ms-lease-state,x-ms-file-change-time,x-ms-file-last-write-time,x-ms-file-creation-time,x-ms-file-permission-key,x-ms-file-attributes,x-ms-file-id,x-ms-file-parent-id,Content-Range,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 07:55:52 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160404454791204048/dir160404454936709291/file160404454967306008') + .reply(201, "", [ + 'Content-Length', + '0', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:53 GMT', + 'ETag', + '"0x8D87CA939DD50DC"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671ba001-001a-008a-4392-ae0e4c000000', + 'x-ms-client-request-id', + 'cd4d2285-f833-4fe2-8040-3115242ed4ae', + 'x-ms-version', + '2020-02-10', + 'x-ms-file-change-time', + '2020-10-30T07:55:53.5047900Z', + 'x-ms-file-last-write-time', + '2020-10-30T07:55:53.5047900Z', + 'x-ms-file-creation-time', + '2020-10-30T07:55:53.5047900Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'x-ms-request-server-encrypted', + 'true', + 'Date', + 'Fri, 30 Oct 2020 07:55:52 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160404454791204048/dir160404454936709291/file160404454967306008', "\u0000\u0001\u0002\u0003\u0004") + .query(true) + .reply(201, "", [ + 'Content-Length', + '0', + 'Content-MD5', + '0FN03Dgdm1KAZEanHI55sQ==', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:53 GMT', + 'ETag', + '"0x8D87CA93A0BBC4A"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671ba004-001a-008a-4592-ae0e4c000000', + 'x-ms-client-request-id', + 'e1feb32e-5374-42f2-b1f0-5cb3deae017c', + 'x-ms-version', + '2020-02-10', + 'x-ms-request-server-encrypted', + 'true', + 'Date', + 'Fri, 30 Oct 2020 07:55:53 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .head('/share160404454791204048/dir160404454936709291/file160404454967306008') + .reply(200, "", [ + 'Content-Length', + '5', + 'Content-Type', + 'application/octet-stream', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:53 GMT', + 'ETag', + '"0x8D87CA93A0BBC4A"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671ba005-001a-008a-4692-ae0e4c000000', + 'x-ms-client-request-id', + '7ee5233b-ca81-4ed0-b860-4c55699399e5', + 'x-ms-version', + '2020-02-10', + 'x-ms-type', + 'File', + 'x-ms-server-encrypted', + 'true', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-file-change-time', + '2020-10-30T07:55:53.5047900Z', + 'x-ms-file-last-write-time', + '2020-10-30T07:55:53.5047900Z', + 'x-ms-file-creation-time', + '2020-10-30T07:55:53.5047900Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-type,x-ms-server-encrypted,x-ms-lease-status,x-ms-lease-state,x-ms-file-change-time,x-ms-file-last-write-time,x-ms-file-creation-time,x-ms-file-permission-key,x-ms-file-attributes,x-ms-file-id,x-ms-file-parent-id,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 07:55:53 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .get('/share160404454791204048/dir160404454936709291/file160404454967306008') + .reply(206, "\u0000\u0001\u0002\u0003\u0004", [ + 'Content-Length', + '5', + 'Content-Type', + 'application/octet-stream', + 'Content-Range', + 'bytes 0-4/5', + 'Last-Modified', + 'Fri, 30 Oct 2020 07:55:53 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87CA93A0BBC4A"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671ba006-001a-008a-4792-ae0e4c000000', + 'x-ms-client-request-id', + 'f3ed49dd-01db-47dc-b62c-892be610d2e6', + 'x-ms-version', + '2020-02-10', + 'x-ms-type', + 'File', + 'x-ms-server-encrypted', + 'true', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-file-change-time', + '2020-10-30T07:55:53.5047900Z', + 'x-ms-file-last-write-time', + '2020-10-30T07:55:53.5047900Z', + 'x-ms-file-creation-time', + '2020-10-30T07:55:53.5047900Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-type,x-ms-server-encrypted,x-ms-lease-status,x-ms-lease-state,x-ms-file-change-time,x-ms-file-last-write-time,x-ms-file-creation-time,x-ms-file-permission-key,x-ms-file-attributes,x-ms-file-id,x-ms-file-parent-id,Content-Range,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Fri, 30 Oct 2020 07:55:53 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .delete('/share160404454791204048') + .query(true) + .reply(202, "", [ + 'Content-Length', + '0', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + '671ba008-001a-008a-4892-ae0e4c000000', + 'x-ms-client-request-id', + '30af7995-a9e3-4d7e-828f-6d2e23d8c272', + 'x-ms-version', + '2020-02-10', + 'Date', + 'Fri, 30 Oct 2020 07:55:54 GMT' +]); diff --git a/sdk/storage/storage-file-share/src/Clients.ts b/sdk/storage/storage-file-share/src/Clients.ts index 342c8f48be6e..d78db9e61406 100644 --- a/sdk/storage/storage-file-share/src/Clients.ts +++ b/sdk/storage/storage-file-share/src/Clients.ts @@ -4829,10 +4829,22 @@ export class ShareFileClient extends StorageClient { ): Promise { const { span, spanOptions } = createSpan("ShareFileClient-uploadData", options.tracingOptions); try { - if (isNode && data instanceof Buffer) { - return this.uploadBuffer( - (offset, count) => data.slice(offset, offset + count), - data.byteLength, + if (isNode) { + let buffer: Buffer; + if (data instanceof Buffer) { + buffer = data; + } else if (data instanceof ArrayBuffer) { + buffer = Buffer.from(data); + } else { + data = data as ArrayBufferView; + buffer = Buffer.from(data.buffer, data.byteOffset, data.byteLength); + } + + return this.uploadSeekableInternal( + (offset: number, size: number): Buffer => { + return buffer.slice(offset, offset + size); + }, + buffer.byteLength, { ...options, tracingOptions: { ...options!.tracingOptions, spanOptions } @@ -4840,7 +4852,7 @@ export class ShareFileClient extends StorageClient { ); } else { const browserBlob = new Blob([data]); - return this.uploadSeekableBlob( + return this.uploadSeekableInternal( (offset: number, size: number): Blob => { return browserBlob.slice(offset, offset + size); }, @@ -4880,58 +4892,10 @@ export class ShareFileClient extends StorageClient { options.tracingOptions ); try { - if (!options.rangeSize) { - options.rangeSize = FILE_RANGE_MAX_SIZE_BYTES; - } - if (options.rangeSize < 0 || options.rangeSize > FILE_RANGE_MAX_SIZE_BYTES) { - throw new RangeError(`options.rangeSize must be > 0 and <= ${FILE_RANGE_MAX_SIZE_BYTES}`); - } - - if (!options.fileHttpHeaders) { - options.fileHttpHeaders = {}; - } - - if (!options.concurrency) { - options.concurrency = DEFAULT_HIGH_LEVEL_CONCURRENCY; - } - if (options.concurrency < 0) { - throw new RangeError(`options.concurrency cannot less than 0.`); - } - - // Create the file - await this.create(size, { - abortSignal: options.abortSignal, - fileHttpHeaders: options.fileHttpHeaders, - metadata: options.metadata, - leaseAccessConditions: options.leaseAccessConditions, + return this.uploadSeekableInternal(blobFactory, size, { + ...options, tracingOptions: { ...options!.tracingOptions, spanOptions } }); - - const numBlocks: number = Math.floor((size - 1) / options.rangeSize) + 1; - let transferProgress: number = 0; - - const batch = new Batch(options.concurrency); - for (let i = 0; i < numBlocks; i++) { - batch.addOperation( - async (): Promise => { - const start = options.rangeSize! * i; - const end = i === numBlocks - 1 ? size : start + options.rangeSize!; - const contentLength = end - start; - await this.uploadRange(blobFactory(start, contentLength), start, contentLength, { - abortSignal: options.abortSignal, - leaseAccessConditions: options.leaseAccessConditions, - tracingOptions: { ...options!.tracingOptions, spanOptions } - }); - // Update progress after block is successfully uploaded to server, in case of block trying - // TODO: Hook with convenience layer progress event in finer level - transferProgress += contentLength; - if (options.onProgress) { - options.onProgress({ loadedBytes: transferProgress }); - } - } - ); - } - return await batch.do(); } catch (e) { span.setStatus({ code: CanonicalCode.UNKNOWN, @@ -4960,13 +4924,15 @@ export class ShareFileClient extends StorageClient { const { span, spanOptions } = createSpan("ShareFileClient-uploadFile", options.tracingOptions); try { const size = (await fsStat(filePath)).size; - return await this.uploadResetableStream( - (offset, count) => - fsCreateReadStream(filePath, { - autoClose: true, - end: count ? offset + count - 1 : Infinity, - start: offset - }), + return await this.uploadSeekableInternal( + (offset, count) => { + return () => + fsCreateReadStream(filePath, { + autoClose: true, + end: count ? offset + count - 1 : Infinity, + start: offset + }); + }, size, { ...options, tracingOptions: { ...options!.tracingOptions, spanOptions } } ); @@ -5006,62 +4972,13 @@ export class ShareFileClient extends StorageClient { options.tracingOptions ); try { - if (!options.rangeSize) { - options.rangeSize = FILE_RANGE_MAX_SIZE_BYTES; - } - if (options.rangeSize < 0 || options.rangeSize > FILE_RANGE_MAX_SIZE_BYTES) { - throw new RangeError(`options.rangeSize must be > 0 and <= ${FILE_RANGE_MAX_SIZE_BYTES}`); - } - - if (!options.fileHttpHeaders) { - options.fileHttpHeaders = {}; - } - - if (!options.concurrency) { - options.concurrency = DEFAULT_HIGH_LEVEL_CONCURRENCY; - } - if (options.concurrency < 0) { - throw new RangeError(`options.concurrency cannot less than 0.`); - } - - // Create the file - await this.create(size, { - abortSignal: options.abortSignal, - fileHttpHeaders: options.fileHttpHeaders, - metadata: options.metadata, - leaseAccessConditions: options.leaseAccessConditions, - tracingOptions: { ...options!.tracingOptions, spanOptions } - }); - - const numBlocks: number = Math.floor((size - 1) / options.rangeSize) + 1; - let transferProgress: number = 0; - const batch = new Batch(options.concurrency); - - for (let i = 0; i < numBlocks; i++) { - batch.addOperation( - async (): Promise => { - const start = options.rangeSize! * i; - const end = i === numBlocks - 1 ? size : start + options.rangeSize!; - const contentLength = end - start; - await this.uploadRange( - () => streamFactory(start, contentLength), - start, - contentLength, - { - abortSignal: options.abortSignal, - leaseAccessConditions: options.leaseAccessConditions, - tracingOptions: { ...options!.tracingOptions, spanOptions } - } - ); - // Update progress after block is successfully uploaded to server, in case of block trying - transferProgress += contentLength; - if (options.onProgress) { - options.onProgress({ loadedBytes: transferProgress }); - } - } - ); - } - return await batch.do(); + return await this.uploadSeekableInternal( + (offset: number, count?: number) => { + return () => streamFactory(offset, count); + }, + size, + { ...options, tracingOptions: { ...options!.tracingOptions, spanOptions } } + ); } catch (e) { span.setStatus({ code: CanonicalCode.UNKNOWN, @@ -5074,23 +4991,20 @@ export class ShareFileClient extends StorageClient { } /** - * ONLY AVAILABLE IN NODE.JS RUNTIME. * - * @export - * @param {(offset: number, count: number) => Buffer} bufferChunk Returns a Node.js Buffer chunk starting - * from the offset defined till the count + * @param {(offset: number, count: number) => HttpRequestBody} bodyFactory * @param {number} size Size of the Azure file * @param {ShareFileClient} fileClient ShareFileClient * @param {FileParallelUploadOptions} [options] * @returns {(Promise)} */ - private async uploadBuffer( - bufferChunk: (offset: number, count: number) => Buffer, + private async uploadSeekableInternal( + bodyFactory: (offset: number, count: number) => HttpRequestBody, size: number, options: FileParallelUploadOptions = {} ): Promise { const { span, spanOptions } = createSpan( - "ShareFileClient-uploadBuffer", + "ShareFileClient-uploadSeekableInternal", options.tracingOptions ); try { @@ -5131,7 +5045,7 @@ export class ShareFileClient extends StorageClient { const start = options.rangeSize! * i; const end = i === numBlocks - 1 ? size : start + options.rangeSize!; const contentLength = end - start; - await this.uploadRange(bufferChunk(start, contentLength), start, contentLength, { + await this.uploadRange(bodyFactory(start, contentLength), start, contentLength, { abortSignal: options.abortSignal, leaseAccessConditions: options.leaseAccessConditions, tracingOptions: { ...options!.tracingOptions, spanOptions } diff --git a/sdk/storage/storage-file-share/test/node/highlevel.node.spec.ts b/sdk/storage/storage-file-share/test/node/highlevel.node.spec.ts index 6ac0de8d723f..77aedc6c9cc5 100644 --- a/sdk/storage/storage-file-share/test/node/highlevel.node.spec.ts +++ b/sdk/storage/storage-file-share/test/node/highlevel.node.spec.ts @@ -220,6 +220,34 @@ describe("Highlevel Node.js only", () => { assert.ok(eventTriggered); }).timeout(timeoutForLargeFileUploadingTest); + it("uploadData should work with Buffer, ArrayBuffer and ArrayBufferView", async () => { + const byteLength = 10; + const arrayBuf = new ArrayBuffer(byteLength); + const uint8Array = new Uint8Array(arrayBuf); + for (let i = 0; i < byteLength; i++) { + uint8Array[i] = i; + } + + await fileClient.uploadData(arrayBuf); + const res = await fileClient.downloadToBuffer(); + assert.ok(res.equals(Buffer.from(arrayBuf))); + + const uint8ArrayPartial = new Uint8Array(arrayBuf, 1, 3); + await fileClient.uploadData(uint8ArrayPartial); + const res1 = await fileClient.downloadToBuffer(); + assert.ok(res1.equals(Buffer.from(arrayBuf, 1, 3))); + + const uint16Array = new Uint16Array(arrayBuf, 4, 2); + await fileClient.uploadData(uint16Array); + const res2 = await fileClient.downloadToBuffer(); + assert.ok(res2.equals(Buffer.from(arrayBuf, 4, 2 * 2))); + + const buf = Buffer.from(arrayBuf, 0, 5); + await fileClient.uploadData(buf); + const res3 = await fileClient.downloadToBuffer(); + assert.ok(res3.equals(buf)); + }); + it("downloadToBuffer should success", async () => { recorder.skip("node", "Temp file - recorder doesn't support saving the file"); const rs = fs.createReadStream(tempFileLarge); From 033754b6fa9584abf5cde704a6d03b39c5b10c5a Mon Sep 17 00:00:00 2001 From: Lin Jian Date: Mon, 2 Nov 2020 17:30:05 +0800 Subject: [PATCH 2/3] inline, changelog and add test case for browser --- sdk/storage/storage-blob/CHANGELOG.md | 1 + .../highlevel/recording_before_all_hook.json | 6 +- ..._blob_arraybuffer_and_arraybufferview.json | 250 +++++++++++ sdk/storage/storage-blob/src/Clients.ts | 12 +- .../test/browser/highlevel.browser.spec.ts | 28 ++ .../recording_before_all_hook.json | 6 +- ..._blob_arraybuffer_and_arraybufferview.json | 398 ++++++++++++++++ .../storage-file-datalake/src/clients.ts | 8 +- .../test/browser/highlevel.browser.spec.ts | 28 ++ ..._with_arraybuffer_and_arraybufferview.json | 316 +++++++++++++ ...rk_with_arraybuffer_and_arraybufferview.js | 425 ++++++++++++++++++ sdk/storage/storage-file-share/src/Clients.ts | 8 +- .../test/fileclient.spec.ts | 30 +- .../test/utils/index.browser.ts | 29 ++ .../storage-file-share/test/utils/index.ts | 31 ++ 15 files changed, 1548 insertions(+), 28 deletions(-) create mode 100644 sdk/storage/storage-blob/recordings/browsers/highlevel/recording_uploaddata_should_work_with_blob_arraybuffer_and_arraybufferview.json create mode 100644 sdk/storage/storage-file-datalake/recordings/browsers/highlevel_browser_only/recording_upload_should_work_with_blob_arraybuffer_and_arraybufferview.json create mode 100644 sdk/storage/storage-file-share/recordings/browsers/fileclient/recording_uploaddata_should_work_with_arraybuffer_and_arraybufferview.json create mode 100644 sdk/storage/storage-file-share/recordings/node/fileclient/recording_uploaddata_should_work_with_arraybuffer_and_arraybufferview.js diff --git a/sdk/storage/storage-blob/CHANGELOG.md b/sdk/storage/storage-blob/CHANGELOG.md index f3aa2e9117c0..c965e0cb91fd 100644 --- a/sdk/storage/storage-blob/CHANGELOG.md +++ b/sdk/storage/storage-blob/CHANGELOG.md @@ -2,6 +2,7 @@ ## 12.3.0-beta.2 (Unreleased) +- Added `BlockBlobClient.uploadData(data: Buffer | Blob | ArrayBuffer | ArrayBufferView, options)` for parallel uploading. It's avaiable in both Node.js and browsers. ## 12.3.0-beta.1 (2020-10-13) diff --git a/sdk/storage/storage-blob/recordings/browsers/highlevel/recording_before_all_hook.json b/sdk/storage/storage-blob/recordings/browsers/highlevel/recording_before_all_hook.json index f8bb9c4857a8..d8279f9eca42 100644 --- a/sdk/storage/storage-blob/recordings/browsers/highlevel/recording_before_all_hook.json +++ b/sdk/storage/storage-blob/recordings/browsers/highlevel/recording_before_all_hook.json @@ -2,10 +2,10 @@ "recordings": [], "uniqueTestInfo": { "uniqueName": { - "browserfile": "browserfile159247522909007723", - "browserfile2": "browserfile2159247523422700178" + "browserfile": "browserfile160430729782805726", + "browserfile2": "browserfile2160430730315100187" }, "newDate": {} }, - "hash": "fdfc820cfd6c0ef696e7cf3a49267b12" + "hash": "8341858cfb67399c4cce66565343c0b9" } \ No newline at end of file diff --git a/sdk/storage/storage-blob/recordings/browsers/highlevel/recording_uploaddata_should_work_with_blob_arraybuffer_and_arraybufferview.json b/sdk/storage/storage-blob/recordings/browsers/highlevel/recording_uploaddata_should_work_with_blob_arraybuffer_and_arraybufferview.json new file mode 100644 index 000000000000..9ff291b56019 --- /dev/null +++ b/sdk/storage/storage-blob/recordings/browsers/highlevel/recording_uploaddata_should_work_with_blob_arraybuffer_and_arraybufferview.json @@ -0,0 +1,250 @@ +{ + "recordings": [ + { + "method": "PUT", + "url": "https://fakestorageaccount.blob.core.windows.net/container160430730321102384", + "query": { + "restype": "container" + }, + "requestBody": null, + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 08:55:04 GMT", + "etag": "\"0x8D87F0CFDC6D7EA\"", + "last-modified": "Mon, 02 Nov 2020 08:55:04 GMT", + "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "62aa68be-391c-47eb-8098-c55c703d198d", + "x-ms-request-id": "12b33ded-f01e-0027-37f5-b04239000000", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PUT", + "url": "https://fakestorageaccount.blob.core.windows.net/container160430730321102384/blob160430730482507016", + "query": {}, + "requestBody": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t", + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "content-md5": "xWvVSA9uVBPLYqCtlmZhOg==", + "date": "Mon, 02 Nov 2020 08:55:04 GMT", + "etag": "\"0x8D87F0CFE23CA3B\"", + "last-modified": "Mon, 02 Nov 2020 08:55:05 GMT", + "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "76b7a1d8-1c59-4798-886a-62331679a271", + "x-ms-content-crc64": "l0UONCoHCSs=", + "x-ms-request-id": "12b33e7b-f01e-0027-33f5-b04239000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2020-02-10", + "x-ms-version-id": "2020-11-02T08:55:05.3018683Z" + } + }, + { + "method": "GET", + "url": "https://fakestorageaccount.blob.core.windows.net/container160430730321102384/blob160430730482507016", + "query": {}, + "requestBody": null, + "status": 200, + "response": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t", + "responseHeaders": { + "accept-ranges": "bytes", + "content-length": "10", + "content-md5": "xWvVSA9uVBPLYqCtlmZhOg==", + "content-type": "application/octet-stream", + "date": "Mon, 02 Nov 2020 08:55:05 GMT", + "etag": "\"0x8D87F0CFE23CA3B\"", + "last-modified": "Mon, 02 Nov 2020 08:55:05 GMT", + "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-blob-type": "BlockBlob", + "x-ms-client-request-id": "6044e02f-2472-4f80-bef3-0c6b9d2fd029", + "x-ms-creation-time": "Mon, 02 Nov 2020 08:55:05 GMT", + "x-ms-is-current-version": "true", + "x-ms-lease-state": "available", + "x-ms-lease-status": "unlocked", + "x-ms-request-id": "12b33f10-f01e-0027-3df5-b04239000000", + "x-ms-server-encrypted": "true", + "x-ms-version": "2020-02-10", + "x-ms-version-id": "2020-11-02T08:55:05.3018683Z" + } + }, + { + "method": "PUT", + "url": "https://fakestorageaccount.blob.core.windows.net/container160430730321102384/blob160430730482507016", + "query": {}, + "requestBody": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t", + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "content-md5": "xWvVSA9uVBPLYqCtlmZhOg==", + "date": "Mon, 02 Nov 2020 08:55:05 GMT", + "etag": "\"0x8D87F0CFEAB62D3\"", + "last-modified": "Mon, 02 Nov 2020 08:55:06 GMT", + "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "4127bdb3-11c0-4a8b-9b23-0d886eca90c6", + "x-ms-content-crc64": "l0UONCoHCSs=", + "x-ms-request-id": "12b33f9f-f01e-0027-41f5-b04239000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2020-02-10", + "x-ms-version-id": "2020-11-02T08:55:06.1915107Z" + } + }, + { + "method": "GET", + "url": "https://fakestorageaccount.blob.core.windows.net/container160430730321102384/blob160430730482507016", + "query": {}, + "requestBody": null, + "status": 200, + "response": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t", + "responseHeaders": { + "accept-ranges": "bytes", + "content-length": "10", + "content-md5": "xWvVSA9uVBPLYqCtlmZhOg==", + "content-type": "application/octet-stream", + "date": "Mon, 02 Nov 2020 08:55:06 GMT", + "etag": "\"0x8D87F0CFEAB62D3\"", + "last-modified": "Mon, 02 Nov 2020 08:55:06 GMT", + "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-blob-type": "BlockBlob", + "x-ms-client-request-id": "4cd0bd59-58bc-444c-b1e5-cd7b9d00ba95", + "x-ms-creation-time": "Mon, 02 Nov 2020 08:55:06 GMT", + "x-ms-is-current-version": "true", + "x-ms-lease-state": "available", + "x-ms-lease-status": "unlocked", + "x-ms-request-id": "12b34061-f01e-0027-6df5-b04239000000", + "x-ms-server-encrypted": "true", + "x-ms-version": "2020-02-10", + "x-ms-version-id": "2020-11-02T08:55:06.1915107Z" + } + }, + { + "method": "PUT", + "url": "https://fakestorageaccount.blob.core.windows.net/container160430730321102384/blob160430730482507016", + "query": {}, + "requestBody": "\u0001\u0002\u0003", + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "content-md5": "Uonfc331cyb83SJZevsfrA==", + "date": "Mon, 02 Nov 2020 08:55:06 GMT", + "etag": "\"0x8D87F0CFF3370A0\"", + "last-modified": "Mon, 02 Nov 2020 08:55:07 GMT", + "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "308213ef-a92d-4fb8-aa04-037f00e7649f", + "x-ms-content-crc64": "wBdArCrzewI=", + "x-ms-request-id": "12b340ca-f01e-0027-51f5-b04239000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2020-02-10", + "x-ms-version-id": "2020-11-02T08:55:07.0841536Z" + } + }, + { + "method": "GET", + "url": "https://fakestorageaccount.blob.core.windows.net/container160430730321102384/blob160430730482507016", + "query": {}, + "requestBody": null, + "status": 200, + "response": "\u0001\u0002\u0003", + "responseHeaders": { + "accept-ranges": "bytes", + "content-length": "3", + "content-md5": "Uonfc331cyb83SJZevsfrA==", + "content-type": "application/octet-stream", + "date": "Mon, 02 Nov 2020 08:55:07 GMT", + "etag": "\"0x8D87F0CFF3370A0\"", + "last-modified": "Mon, 02 Nov 2020 08:55:07 GMT", + "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-blob-type": "BlockBlob", + "x-ms-client-request-id": "6e55436a-2db0-454f-a6b4-c7c035a61465", + "x-ms-creation-time": "Mon, 02 Nov 2020 08:55:07 GMT", + "x-ms-is-current-version": "true", + "x-ms-lease-state": "available", + "x-ms-lease-status": "unlocked", + "x-ms-request-id": "12b3416e-f01e-0027-5df5-b04239000000", + "x-ms-server-encrypted": "true", + "x-ms-version": "2020-02-10", + "x-ms-version-id": "2020-11-02T08:55:07.0841536Z" + } + }, + { + "method": "PUT", + "url": "https://fakestorageaccount.blob.core.windows.net/container160430730321102384/blob160430730482507016", + "query": {}, + "requestBody": "\u0004\u0005\u0006\u0007", + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "content-md5": "prhTe5fVi0F9Pf3RAwsV0g==", + "date": "Mon, 02 Nov 2020 08:55:07 GMT", + "etag": "\"0x8D87F0CFFBC1AA7\"", + "last-modified": "Mon, 02 Nov 2020 08:55:07 GMT", + "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "a7735306-dd06-4248-9a2a-a9db7edc4c7e", + "x-ms-content-crc64": "3s7Dbfd5f1U=", + "x-ms-request-id": "12b3420e-f01e-0027-6ff5-b04239000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2020-02-10", + "x-ms-version-id": "2020-11-02T08:55:07.9787959Z" + } + }, + { + "method": "GET", + "url": "https://fakestorageaccount.blob.core.windows.net/container160430730321102384/blob160430730482507016", + "query": {}, + "requestBody": null, + "status": 200, + "response": "\u0004\u0005\u0006\u0007", + "responseHeaders": { + "accept-ranges": "bytes", + "content-length": "4", + "content-md5": "prhTe5fVi0F9Pf3RAwsV0g==", + "content-type": "application/octet-stream", + "date": "Mon, 02 Nov 2020 08:55:08 GMT", + "etag": "\"0x8D87F0CFFBC1AA7\"", + "last-modified": "Mon, 02 Nov 2020 08:55:07 GMT", + "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-blob-type": "BlockBlob", + "x-ms-client-request-id": "385cfdd7-20b7-4411-bcee-c87e7cabb5b5", + "x-ms-creation-time": "Mon, 02 Nov 2020 08:55:07 GMT", + "x-ms-is-current-version": "true", + "x-ms-lease-state": "available", + "x-ms-lease-status": "unlocked", + "x-ms-request-id": "12b342bd-f01e-0027-0bf5-b04239000000", + "x-ms-server-encrypted": "true", + "x-ms-version": "2020-02-10", + "x-ms-version-id": "2020-11-02T08:55:07.9787959Z" + } + }, + { + "method": "DELETE", + "url": "https://fakestorageaccount.blob.core.windows.net/container160430730321102384", + "query": { + "restype": "container" + }, + "requestBody": null, + "status": 202, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 08:55:08 GMT", + "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "2bd0ca58-3159-4f24-bdb6-433ec7a2037e", + "x-ms-request-id": "12b34363-f01e-0027-22f5-b04239000000", + "x-ms-version": "2020-02-10" + } + } + ], + "uniqueTestInfo": { + "uniqueName": { + "container": "container160430730321102384", + "blob": "blob160430730482507016" + }, + "newDate": {} + }, + "hash": "8341858cfb67399c4cce66565343c0b9" +} \ No newline at end of file diff --git a/sdk/storage/storage-blob/src/Clients.ts b/sdk/storage/storage-blob/src/Clients.ts index 7545cd2710f8..481d715f1d30 100644 --- a/sdk/storage/storage-blob/src/Clients.ts +++ b/sdk/storage/storage-blob/src/Clients.ts @@ -4397,9 +4397,7 @@ export class BlockBlobClient extends BlobClient { } return this.uploadSeekableInternal( - (offset: number, size: number): Buffer => { - return buffer.slice(offset, offset + size); - }, + (offset: number, size: number): Buffer => buffer.slice(offset, offset + size), buffer.byteLength, { ...options, @@ -4409,9 +4407,7 @@ export class BlockBlobClient extends BlobClient { } else { const browserBlob = new Blob([data]); return this.uploadSeekableInternal( - (offset: number, size: number): Blob => { - return browserBlob.slice(offset, offset + size); - }, + (offset: number, size: number): Blob => browserBlob.slice(offset, offset + size), browserBlob.size, { ...options, tracingOptions: { ...options!.tracingOptions, spanOptions } } ); @@ -4455,9 +4451,7 @@ export class BlockBlobClient extends BlobClient { try { const browserBlob = new Blob([browserData]); return await this.uploadSeekableInternal( - (offset: number, size: number): Blob => { - return browserBlob.slice(offset, offset + size); - }, + (offset: number, size: number): Blob => browserBlob.slice(offset, offset + size), browserBlob.size, { ...options, tracingOptions: { ...options!.tracingOptions, spanOptions } } ); diff --git a/sdk/storage/storage-blob/test/browser/highlevel.browser.spec.ts b/sdk/storage/storage-blob/test/browser/highlevel.browser.spec.ts index 4858c59b0e58..daaf173eaa45 100644 --- a/sdk/storage/storage-blob/test/browser/highlevel.browser.spec.ts +++ b/sdk/storage/storage-blob/test/browser/highlevel.browser.spec.ts @@ -209,4 +209,32 @@ describe("Highlevel", () => { }); assert.equal((await blockBlobClient.getProperties()).accessTier, "Cool"); }); + + it("uploadData should work with Blob, ArrayBuffer and ArrayBufferView", async () => { + const byteLength = 10; + const arrayBuf = new ArrayBuffer(byteLength); + const uint8Array = new Uint8Array(arrayBuf); + for (let i = 0; i < byteLength; i++) { + uint8Array[i] = i; + } + + const blob = new Blob([arrayBuf]); + await blockBlobClient.uploadData(blob); + const downloadedBlob = await (await blockBlobClient.download()).blobBody; + assert.deepStrictEqual(downloadedBlob, blob); + + await blockBlobClient.uploadData(arrayBuf); + const downloadedBlob1 = await (await blockBlobClient.download()).blobBody; + assert.deepStrictEqual(downloadedBlob1, blob); + + const uint8ArrayPartial = new Uint8Array(arrayBuf, 1, 3); + await blockBlobClient.uploadData(uint8ArrayPartial); + const downloadedBlob2 = await (await blockBlobClient.download()).blobBody!; + assert.deepStrictEqual(downloadedBlob2, new Blob([uint8ArrayPartial])); + + const uint16Array = new Uint16Array(arrayBuf, 4, 2); + await blockBlobClient.uploadData(uint16Array); + const downloadedBlob3 = await (await blockBlobClient.download()).blobBody!; + assert.deepStrictEqual(downloadedBlob3, new Blob([uint16Array])); + }); }); diff --git a/sdk/storage/storage-file-datalake/recordings/browsers/highlevel_browser_only/recording_before_all_hook.json b/sdk/storage/storage-file-datalake/recordings/browsers/highlevel_browser_only/recording_before_all_hook.json index 676bfef4ad10..12cca392bc3d 100644 --- a/sdk/storage/storage-file-datalake/recordings/browsers/highlevel_browser_only/recording_before_all_hook.json +++ b/sdk/storage/storage-file-datalake/recordings/browsers/highlevel_browser_only/recording_before_all_hook.json @@ -2,10 +2,10 @@ "recordings": [], "uniqueTestInfo": { "uniqueName": { - "browserfilesmall": "browserfilesmall158368245771601541", - "browserfilelarge": "browserfilelarge158368246325508586" + "browserfilesmall": "browserfilesmall160430749826909561", + "browserfilelarge": "browserfilelarge160430750321408890" }, "newDate": {} }, - "hash": "f00817fa26a85d954230cc7e97929d43" + "hash": "a4af5d10545b51e2971cb0c6ea5af077" } \ No newline at end of file diff --git a/sdk/storage/storage-file-datalake/recordings/browsers/highlevel_browser_only/recording_upload_should_work_with_blob_arraybuffer_and_arraybufferview.json b/sdk/storage/storage-file-datalake/recordings/browsers/highlevel_browser_only/recording_upload_should_work_with_blob_arraybuffer_and_arraybufferview.json new file mode 100644 index 000000000000..970db0ca97c6 --- /dev/null +++ b/sdk/storage/storage-file-datalake/recordings/browsers/highlevel_browser_only/recording_upload_should_work_with_blob_arraybuffer_and_arraybufferview.json @@ -0,0 +1,398 @@ +{ + "recordings": [ + { + "method": "PUT", + "url": "https://fakestorageaccount.blob.core.windows.net/filesystem160430750327506180", + "query": { + "restype": "container" + }, + "requestBody": null, + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 08:58:24 GMT", + "etag": "\"0x8D87F0D7509E648\"", + "last-modified": "Mon, 02 Nov 2020 08:58:24 GMT", + "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "2c1da690-8d95-4f49-8148-a30c4e509de6", + "x-ms-request-id": "f688c958-601e-0014-04f6-b086fa000000", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PUT", + "url": "https://fakestorageaccount.dfs.core.windows.net/filesystem160430750327506180/file160430750492500410", + "query": { + "resource": "file" + }, + "requestBody": null, + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 08:58:26 GMT", + "etag": "\"0x8D87F0D7612F12F\"", + "last-modified": "Mon, 02 Nov 2020 08:58:26 GMT", + "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "bd93e374-054d-4bb3-946e-9be58c38259d", + "x-ms-request-id": "a2f0603f-801f-003c-2bf6-b0f145000000", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PATCH", + "url": "https://fakestorageaccount.dfs.core.windows.net/filesystem160430750327506180/file160430750492500410", + "query": { + "position": "0", + "action": "append" + }, + "requestBody": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t", + "status": 202, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 08:58:26 GMT", + "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "62d650ab-3014-42e4-b6e1-30d370f0bbaf", + "x-ms-request-id": "a2f06045-801f-003c-2ef6-b0f145000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PATCH", + "url": "https://fakestorageaccount.dfs.core.windows.net/filesystem160430750327506180/file160430750492500410", + "query": { + "position": "10", + "action": "flush" + }, + "requestBody": "", + "status": 200, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 08:58:27 GMT", + "etag": "\"0x8D87F0D76C4951E\"", + "last-modified": "Mon, 02 Nov 2020 08:58:27 GMT", + "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "a6eeb4fa-62a4-4719-8125-8bb70a4b838b", + "x-ms-request-id": "a2f06053-801f-003c-3af6-b0f145000000", + "x-ms-request-server-encrypted": "false", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "GET", + "url": "https://fakestorageaccount.blob.core.windows.net/filesystem160430750327506180/file160430750492500410", + "query": {}, + "requestBody": null, + "status": 200, + "response": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t", + "responseHeaders": { + "accept-ranges": "bytes", + "content-length": "10", + "content-type": "text/plain;charset=UTF-8", + "date": "Mon, 02 Nov 2020 08:58:27 GMT", + "etag": "\"0x8D87F0D76C4951E\"", + "last-modified": "Mon, 02 Nov 2020 08:58:27 GMT", + "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-blob-type": "BlockBlob", + "x-ms-client-request-id": "56800df8-9799-445c-91db-f268c4bd1272", + "x-ms-creation-time": "Mon, 02 Nov 2020 08:58:26 GMT", + "x-ms-lease-state": "available", + "x-ms-lease-status": "unlocked", + "x-ms-request-id": "f688ce49-601e-0014-09f6-b086fa000000", + "x-ms-server-encrypted": "true", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PUT", + "url": "https://fakestorageaccount.dfs.core.windows.net/filesystem160430750327506180/file160430750492500410", + "query": { + "resource": "file" + }, + "requestBody": null, + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 08:58:28 GMT", + "etag": "\"0x8D87F0D774A7CFD\"", + "last-modified": "Mon, 02 Nov 2020 08:58:28 GMT", + "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "df294c9c-8749-407b-a6d0-1cbedd93d415", + "x-ms-request-id": "a2f06058-801f-003c-3ef6-b0f145000000", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PATCH", + "url": "https://fakestorageaccount.dfs.core.windows.net/filesystem160430750327506180/file160430750492500410", + "query": { + "position": "0", + "action": "append" + }, + "requestBody": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t", + "status": 202, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 08:58:28 GMT", + "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "74ccd11e-8340-4c49-ae58-23295890f392", + "x-ms-request-id": "a2f0605e-801f-003c-44f6-b0f145000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PATCH", + "url": "https://fakestorageaccount.dfs.core.windows.net/filesystem160430750327506180/file160430750492500410", + "query": { + "position": "10", + "action": "flush" + }, + "requestBody": "", + "status": 200, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 08:58:28 GMT", + "etag": "\"0x8D87F0D77A75D9E\"", + "last-modified": "Mon, 02 Nov 2020 08:58:29 GMT", + "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "84c890d3-b76a-4737-985a-364b0aa8f5c3", + "x-ms-request-id": "a2f06060-801f-003c-46f6-b0f145000000", + "x-ms-request-server-encrypted": "false", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "GET", + "url": "https://fakestorageaccount.blob.core.windows.net/filesystem160430750327506180/file160430750492500410", + "query": {}, + "requestBody": null, + "status": 200, + "response": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t", + "responseHeaders": { + "accept-ranges": "bytes", + "content-length": "10", + "content-type": "text/plain;charset=UTF-8", + "date": "Mon, 02 Nov 2020 08:58:29 GMT", + "etag": "\"0x8D87F0D77A75D9E\"", + "last-modified": "Mon, 02 Nov 2020 08:58:29 GMT", + "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-blob-type": "BlockBlob", + "x-ms-client-request-id": "ffceecd4-18c7-4f28-9f47-1e977e7648b3", + "x-ms-creation-time": "Mon, 02 Nov 2020 08:58:28 GMT", + "x-ms-lease-state": "available", + "x-ms-lease-status": "unlocked", + "x-ms-request-id": "f688d0c0-601e-0014-4af6-b086fa000000", + "x-ms-server-encrypted": "true", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PUT", + "url": "https://fakestorageaccount.dfs.core.windows.net/filesystem160430750327506180/file160430750492500410", + "query": { + "resource": "file" + }, + "requestBody": null, + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 08:58:29 GMT", + "etag": "\"0x8D87F0D782C60FE\"", + "last-modified": "Mon, 02 Nov 2020 08:58:30 GMT", + "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "063b7752-f057-4fb2-a189-87ff69f4574e", + "x-ms-request-id": "a2f06062-801f-003c-48f6-b0f145000000", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PATCH", + "url": "https://fakestorageaccount.dfs.core.windows.net/filesystem160430750327506180/file160430750492500410", + "query": { + "position": "0", + "action": "append" + }, + "requestBody": "\u0001\u0002\u0003", + "status": 202, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 08:58:29 GMT", + "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "b587de81-2801-49f4-bf80-284e70ca952f", + "x-ms-request-id": "a2f06063-801f-003c-49f6-b0f145000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PATCH", + "url": "https://fakestorageaccount.dfs.core.windows.net/filesystem160430750327506180/file160430750492500410", + "query": { + "position": "3", + "action": "flush" + }, + "requestBody": "", + "status": 200, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 08:58:30 GMT", + "etag": "\"0x8D87F0D78B69F46\"", + "last-modified": "Mon, 02 Nov 2020 08:58:30 GMT", + "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "02facfe3-6adf-41a1-9826-f9d8c5d10e55", + "x-ms-request-id": "a2f06065-801f-003c-4bf6-b0f145000000", + "x-ms-request-server-encrypted": "false", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "GET", + "url": "https://fakestorageaccount.blob.core.windows.net/filesystem160430750327506180/file160430750492500410", + "query": {}, + "requestBody": null, + "status": 200, + "response": "\u0001\u0002\u0003", + "responseHeaders": { + "accept-ranges": "bytes", + "content-length": "3", + "content-type": "text/plain;charset=UTF-8", + "date": "Mon, 02 Nov 2020 08:58:31 GMT", + "etag": "\"0x8D87F0D78B69F46\"", + "last-modified": "Mon, 02 Nov 2020 08:58:30 GMT", + "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-blob-type": "BlockBlob", + "x-ms-client-request-id": "fd99ba4d-f7be-4880-a0c9-61c43427db82", + "x-ms-creation-time": "Mon, 02 Nov 2020 08:58:30 GMT", + "x-ms-lease-state": "available", + "x-ms-lease-status": "unlocked", + "x-ms-request-id": "f688d3b8-601e-0014-33f6-b086fa000000", + "x-ms-server-encrypted": "true", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PUT", + "url": "https://fakestorageaccount.dfs.core.windows.net/filesystem160430750327506180/file160430750492500410", + "query": { + "resource": "file" + }, + "requestBody": null, + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 08:58:31 GMT", + "etag": "\"0x8D87F0D793A0973\"", + "last-modified": "Mon, 02 Nov 2020 08:58:31 GMT", + "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "9e22e9b8-642a-4443-97b8-45f4c9c8a239", + "x-ms-request-id": "a2f06067-801f-003c-4df6-b0f145000000", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PATCH", + "url": "https://fakestorageaccount.dfs.core.windows.net/filesystem160430750327506180/file160430750492500410", + "query": { + "position": "0", + "action": "append" + }, + "requestBody": "\u0004\u0005\u0006\u0007", + "status": 202, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 08:58:31 GMT", + "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "83647cf2-29db-4cc9-b8ff-e2ecef00ac14", + "x-ms-request-id": "a2f06068-801f-003c-4ef6-b0f145000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PATCH", + "url": "https://fakestorageaccount.dfs.core.windows.net/filesystem160430750327506180/file160430750492500410", + "query": { + "position": "4", + "action": "flush" + }, + "requestBody": "", + "status": 200, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 08:58:32 GMT", + "etag": "\"0x8D87F0D79BC08C2\"", + "last-modified": "Mon, 02 Nov 2020 08:58:32 GMT", + "server": "Windows-Azure-HDFS/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "84e80d92-a6c6-4ef3-a36a-5dc85fc12aa6", + "x-ms-request-id": "a2f0606c-801f-003c-50f6-b0f145000000", + "x-ms-request-server-encrypted": "false", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "GET", + "url": "https://fakestorageaccount.blob.core.windows.net/filesystem160430750327506180/file160430750492500410", + "query": {}, + "requestBody": null, + "status": 200, + "response": "\u0004\u0005\u0006\u0007", + "responseHeaders": { + "accept-ranges": "bytes", + "content-length": "4", + "content-type": "text/plain;charset=UTF-8", + "date": "Mon, 02 Nov 2020 08:58:32 GMT", + "etag": "\"0x8D87F0D79BC08C2\"", + "last-modified": "Mon, 02 Nov 2020 08:58:32 GMT", + "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-blob-type": "BlockBlob", + "x-ms-client-request-id": "fd6b38c2-b14b-49d3-8a03-4de1c63fdd64", + "x-ms-creation-time": "Mon, 02 Nov 2020 08:58:31 GMT", + "x-ms-lease-state": "available", + "x-ms-lease-status": "unlocked", + "x-ms-request-id": "f688d6c1-601e-0014-4bf6-b086fa000000", + "x-ms-server-encrypted": "true", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "DELETE", + "url": "https://fakestorageaccount.blob.core.windows.net/filesystem160430750327506180", + "query": { + "restype": "container" + }, + "requestBody": null, + "status": 202, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 08:58:33 GMT", + "server": "Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "b19bb6e6-b7cd-491e-80f6-776a64c7800e", + "x-ms-request-id": "f688d7c6-601e-0014-2cf6-b086fa000000", + "x-ms-version": "2020-02-10" + } + } + ], + "uniqueTestInfo": { + "uniqueName": { + "filesystem": "filesystem160430750327506180", + "file": "file160430750492500410" + }, + "newDate": {} + }, + "hash": "a4af5d10545b51e2971cb0c6ea5af077" +} \ No newline at end of file diff --git a/sdk/storage/storage-file-datalake/src/clients.ts b/sdk/storage/storage-file-datalake/src/clients.ts index 09671bb565e2..da9f24389569 100644 --- a/sdk/storage/storage-file-datalake/src/clients.ts +++ b/sdk/storage/storage-file-datalake/src/clients.ts @@ -1588,9 +1588,7 @@ export class DataLakeFileClient extends DataLakePathClient { } return this.uploadSeekableInternal( - (offset: number, size: number): Buffer => { - return buffer.slice(offset, offset + size); - }, + (offset: number, size: number): Buffer => buffer.slice(offset, offset + size), buffer.length, { ...options, @@ -1600,9 +1598,7 @@ export class DataLakeFileClient extends DataLakePathClient { } else { const browserBlob = new Blob([data]); return this.uploadSeekableInternal( - (offset: number, size: number): Blob => { - return browserBlob.slice(offset, offset + size); - }, + (offset: number, size: number): Blob => browserBlob.slice(offset, offset + size), browserBlob.size, { ...options, tracingOptions: { ...options!.tracingOptions, spanOptions } } ); diff --git a/sdk/storage/storage-file-datalake/test/browser/highlevel.browser.spec.ts b/sdk/storage/storage-file-datalake/test/browser/highlevel.browser.spec.ts index cc7890f05ba1..399e6ec898c3 100644 --- a/sdk/storage/storage-file-datalake/test/browser/highlevel.browser.spec.ts +++ b/sdk/storage/storage-file-datalake/test/browser/highlevel.browser.spec.ts @@ -149,4 +149,32 @@ describe("Highlevel browser only", () => { const response = await fileClient.read(); assert.deepStrictEqual(await bodyToString(response), ""); }); + + it("upload should work with Blob, ArrayBuffer and ArrayBufferView", async () => { + const byteLength = 10; + const arrayBuf = new ArrayBuffer(byteLength); + const uint8Array = new Uint8Array(arrayBuf); + for (let i = 0; i < byteLength; i++) { + uint8Array[i] = i; + } + + const blob = new Blob([arrayBuf]); + await fileClient.upload(blob); + const downloadedBlob = await (await fileClient.read()).contentAsBlob; + assert.deepStrictEqual(downloadedBlob, blob); + + await fileClient.upload(arrayBuf); + const downloadedBlob1 = await (await fileClient.read()).contentAsBlob; + assert.deepStrictEqual(downloadedBlob1, blob); + + const uint8ArrayPartial = new Uint8Array(arrayBuf, 1, 3); + await fileClient.upload(uint8ArrayPartial); + const downloadedBlob2 = await (await fileClient.read()).contentAsBlob!; + assert.deepStrictEqual(downloadedBlob2, new Blob([uint8ArrayPartial])); + + const uint16Array = new Uint16Array(arrayBuf, 4, 2); + await fileClient.upload(uint16Array); + const downloadedBlob3 = await (await fileClient.read()).contentAsBlob!; + assert.deepStrictEqual(downloadedBlob3, new Blob([uint16Array])); + }); }); diff --git a/sdk/storage/storage-file-share/recordings/browsers/fileclient/recording_uploaddata_should_work_with_arraybuffer_and_arraybufferview.json b/sdk/storage/storage-file-share/recordings/browsers/fileclient/recording_uploaddata_should_work_with_arraybuffer_and_arraybufferview.json new file mode 100644 index 000000000000..a365ea559089 --- /dev/null +++ b/sdk/storage/storage-file-share/recordings/browsers/fileclient/recording_uploaddata_should_work_with_arraybuffer_and_arraybufferview.json @@ -0,0 +1,316 @@ +{ + "recordings": [ + { + "method": "PUT", + "url": "https://fakestorageaccount.file.core.windows.net/share160430931805803268", + "query": { + "restype": "share" + }, + "requestBody": null, + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 09:28:39 GMT", + "etag": "\"0x8D87F11AEB3B7E3\"", + "last-modified": "Mon, 02 Nov 2020 09:28:39 GMT", + "server": "Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "29156df7-372f-4c41-948f-b966e355bf21", + "x-ms-request-id": "606fdef6-e01a-0014-4afa-b01d92000000", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PUT", + "url": "https://fakestorageaccount.file.core.windows.net/share160430931805803268/dir160430931964008935", + "query": { + "restype": "directory" + }, + "requestBody": null, + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 09:28:39 GMT", + "etag": "\"0x8D87F11AF10E830\"", + "last-modified": "Mon, 02 Nov 2020 09:28:40 GMT", + "server": "Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "0fb32f3b-42f2-4085-ab70-57c3b670cf51", + "x-ms-file-attributes": "Directory", + "x-ms-file-change-time": "2020-11-02T09:28:40.1217584Z", + "x-ms-file-creation-time": "2020-11-02T09:28:40.1217584Z", + "x-ms-file-id": "13835128424026341376", + "x-ms-file-last-write-time": "2020-11-02T09:28:40.1217584Z", + "x-ms-file-parent-id": "0", + "x-ms-file-permission-key": "18253506462963126402*10775527834424002315", + "x-ms-request-id": "606fdefc-e01a-0014-4cfa-b01d92000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PUT", + "url": "https://fakestorageaccount.file.core.windows.net/share160430931805803268/dir160430931964008935/file160430932025101492", + "query": {}, + "requestBody": null, + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 09:28:40 GMT", + "etag": "\"0x8D87F11AF6CD4AE\"", + "last-modified": "Mon, 02 Nov 2020 09:28:40 GMT", + "server": "Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "233e4852-ba9a-4956-b7f9-27c202531537", + "x-ms-file-attributes": "Archive", + "x-ms-file-change-time": "2020-11-02T09:28:40.7241902Z", + "x-ms-file-creation-time": "2020-11-02T09:28:40.7241902Z", + "x-ms-file-id": "11529285414812647424", + "x-ms-file-last-write-time": "2020-11-02T09:28:40.7241902Z", + "x-ms-file-parent-id": "13835128424026341376", + "x-ms-file-permission-key": "4407534441384161157*10775527834424002315", + "x-ms-request-id": "606fdf02-e01a-0014-50fa-b01d92000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PUT", + "url": "https://fakestorageaccount.file.core.windows.net/share160430931805803268/dir160430931964008935/file160430932025101492", + "query": { + "comp": "range" + }, + "requestBody": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t", + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "content-md5": "xWvVSA9uVBPLYqCtlmZhOg==", + "date": "Mon, 02 Nov 2020 09:28:41 GMT", + "etag": "\"0x8D87F11AFC64FBD\"", + "last-modified": "Mon, 02 Nov 2020 09:28:41 GMT", + "server": "Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "a4d30c5b-1daa-4ca9-8635-68b39b602b45", + "x-ms-request-id": "606fdf04-e01a-0014-52fa-b01d92000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "GET", + "url": "https://fakestorageaccount.file.core.windows.net/share160430931805803268/dir160430931964008935/file160430932025101492", + "query": {}, + "requestBody": null, + "status": 200, + "response": "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t", + "responseHeaders": { + "accept-ranges": "bytes", + "content-length": "10", + "content-type": "application/octet-stream", + "date": "Mon, 02 Nov 2020 09:28:41 GMT", + "etag": "\"0x8D87F11AFC64FBD\"", + "last-modified": "Mon, 02 Nov 2020 09:28:41 GMT", + "server": "Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "fcfed9f1-e4cc-421a-8b8d-d69976950df2", + "x-ms-file-attributes": "Archive", + "x-ms-file-change-time": "2020-11-02T09:28:40.7241902Z", + "x-ms-file-creation-time": "2020-11-02T09:28:40.7241902Z", + "x-ms-file-id": "11529285414812647424", + "x-ms-file-last-write-time": "2020-11-02T09:28:40.7241902Z", + "x-ms-file-parent-id": "13835128424026341376", + "x-ms-file-permission-key": "4407534441384161157*10775527834424002315", + "x-ms-lease-state": "available", + "x-ms-lease-status": "unlocked", + "x-ms-request-id": "606fdf08-e01a-0014-54fa-b01d92000000", + "x-ms-server-encrypted": "true", + "x-ms-type": "File", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PUT", + "url": "https://fakestorageaccount.file.core.windows.net/share160430931805803268/dir160430931964008935/file160430932025101492", + "query": {}, + "requestBody": null, + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 09:28:41 GMT", + "etag": "\"0x8D87F11B04E5D6D\"", + "last-modified": "Mon, 02 Nov 2020 09:28:42 GMT", + "server": "Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "3c045c0a-6443-48bc-8a47-65c95271ea45", + "x-ms-file-attributes": "Archive", + "x-ms-file-change-time": "2020-11-02T09:28:42.2022509Z", + "x-ms-file-creation-time": "2020-11-02T09:28:42.2022509Z", + "x-ms-file-id": "11529285414812647424", + "x-ms-file-last-write-time": "2020-11-02T09:28:42.2022509Z", + "x-ms-file-parent-id": "13835128424026341376", + "x-ms-file-permission-key": "4407534441384161157*10775527834424002315", + "x-ms-request-id": "606fdf09-e01a-0014-55fa-b01d92000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PUT", + "url": "https://fakestorageaccount.file.core.windows.net/share160430931805803268/dir160430931964008935/file160430932025101492", + "query": { + "comp": "range" + }, + "requestBody": "\u0001\u0002\u0003", + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "content-md5": "Uonfc331cyb83SJZevsfrA==", + "date": "Mon, 02 Nov 2020 09:28:42 GMT", + "etag": "\"0x8D87F11B07C2CA0\"", + "last-modified": "Mon, 02 Nov 2020 09:28:42 GMT", + "server": "Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "c9994e8c-2ebd-43f6-95b7-0f977ad76007", + "x-ms-request-id": "606fdf0a-e01a-0014-56fa-b01d92000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "GET", + "url": "https://fakestorageaccount.file.core.windows.net/share160430931805803268/dir160430931964008935/file160430932025101492", + "query": {}, + "requestBody": null, + "status": 200, + "response": "\u0001\u0002\u0003", + "responseHeaders": { + "accept-ranges": "bytes", + "content-length": "3", + "content-type": "application/octet-stream", + "date": "Mon, 02 Nov 2020 09:28:42 GMT", + "etag": "\"0x8D87F11B07C2CA0\"", + "last-modified": "Mon, 02 Nov 2020 09:28:42 GMT", + "server": "Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "ce7e8cf0-41e7-426a-9274-35e3e4efd81c", + "x-ms-file-attributes": "Archive", + "x-ms-file-change-time": "2020-11-02T09:28:42.2022509Z", + "x-ms-file-creation-time": "2020-11-02T09:28:42.2022509Z", + "x-ms-file-id": "11529285414812647424", + "x-ms-file-last-write-time": "2020-11-02T09:28:42.2022509Z", + "x-ms-file-parent-id": "13835128424026341376", + "x-ms-file-permission-key": "4407534441384161157*10775527834424002315", + "x-ms-lease-state": "available", + "x-ms-lease-status": "unlocked", + "x-ms-request-id": "606fdf0f-e01a-0014-58fa-b01d92000000", + "x-ms-server-encrypted": "true", + "x-ms-type": "File", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PUT", + "url": "https://fakestorageaccount.file.core.windows.net/share160430931805803268/dir160430931964008935/file160430932025101492", + "query": {}, + "requestBody": null, + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 09:28:43 GMT", + "etag": "\"0x8D87F11B1034FD2\"", + "last-modified": "Mon, 02 Nov 2020 09:28:43 GMT", + "server": "Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "7247675e-6c69-488f-8199-9b1ecad778fc", + "x-ms-file-attributes": "Archive", + "x-ms-file-change-time": "2020-11-02T09:28:43.3881042Z", + "x-ms-file-creation-time": "2020-11-02T09:28:43.3881042Z", + "x-ms-file-id": "11529285414812647424", + "x-ms-file-last-write-time": "2020-11-02T09:28:43.3881042Z", + "x-ms-file-parent-id": "13835128424026341376", + "x-ms-file-permission-key": "4407534441384161157*10775527834424002315", + "x-ms-request-id": "606fdf10-e01a-0014-59fa-b01d92000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "PUT", + "url": "https://fakestorageaccount.file.core.windows.net/share160430931805803268/dir160430931964008935/file160430932025101492", + "query": { + "comp": "range" + }, + "requestBody": "\u0004\u0005\u0006\u0007", + "status": 201, + "response": "", + "responseHeaders": { + "content-length": "0", + "content-md5": "prhTe5fVi0F9Pf3RAwsV0g==", + "date": "Mon, 02 Nov 2020 09:28:43 GMT", + "etag": "\"0x8D87F11B132A5C9\"", + "last-modified": "Mon, 02 Nov 2020 09:28:43 GMT", + "server": "Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "015875cc-3b19-4399-98fa-5f64713e7214", + "x-ms-request-id": "606fdf11-e01a-0014-5afa-b01d92000000", + "x-ms-request-server-encrypted": "true", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "GET", + "url": "https://fakestorageaccount.file.core.windows.net/share160430931805803268/dir160430931964008935/file160430932025101492", + "query": {}, + "requestBody": null, + "status": 200, + "response": "\u0004\u0005\u0006\u0007", + "responseHeaders": { + "accept-ranges": "bytes", + "content-length": "4", + "content-type": "application/octet-stream", + "date": "Mon, 02 Nov 2020 09:28:44 GMT", + "etag": "\"0x8D87F11B132A5C9\"", + "last-modified": "Mon, 02 Nov 2020 09:28:43 GMT", + "server": "Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "3465cae7-550d-46d0-858f-e1d8820b7402", + "x-ms-file-attributes": "Archive", + "x-ms-file-change-time": "2020-11-02T09:28:43.3881042Z", + "x-ms-file-creation-time": "2020-11-02T09:28:43.3881042Z", + "x-ms-file-id": "11529285414812647424", + "x-ms-file-last-write-time": "2020-11-02T09:28:43.3881042Z", + "x-ms-file-parent-id": "13835128424026341376", + "x-ms-file-permission-key": "4407534441384161157*10775527834424002315", + "x-ms-lease-state": "available", + "x-ms-lease-status": "unlocked", + "x-ms-request-id": "606fdf14-e01a-0014-5cfa-b01d92000000", + "x-ms-server-encrypted": "true", + "x-ms-type": "File", + "x-ms-version": "2020-02-10" + } + }, + { + "method": "DELETE", + "url": "https://fakestorageaccount.file.core.windows.net/share160430931805803268", + "query": { + "restype": "share" + }, + "requestBody": null, + "status": 202, + "response": "", + "responseHeaders": { + "content-length": "0", + "date": "Mon, 02 Nov 2020 09:28:44 GMT", + "server": "Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0", + "x-ms-client-request-id": "58ee462d-1fdf-49ca-abc6-15786d4109f1", + "x-ms-request-id": "606fdf16-e01a-0014-5efa-b01d92000000", + "x-ms-version": "2020-02-10" + } + } + ], + "uniqueTestInfo": { + "uniqueName": { + "share": "share160430931805803268", + "dir": "dir160430931964008935", + "file": "file160430932025101492" + }, + "newDate": {} + }, + "hash": "b7f75513ee95b559b02146634f914412" +} \ No newline at end of file diff --git a/sdk/storage/storage-file-share/recordings/node/fileclient/recording_uploaddata_should_work_with_arraybuffer_and_arraybufferview.js b/sdk/storage/storage-file-share/recordings/node/fileclient/recording_uploaddata_should_work_with_arraybuffer_and_arraybufferview.js new file mode 100644 index 000000000000..a6464eb505f1 --- /dev/null +++ b/sdk/storage/storage-file-share/recordings/node/fileclient/recording_uploaddata_should_work_with_arraybuffer_and_arraybufferview.js @@ -0,0 +1,425 @@ +let nock = require('nock'); + +module.exports.hash = "cb9aa871a97549a6960545d9f6ae2bb0"; + +module.exports.testInfo = {"uniqueName":{"share":"share160430925727102968","dir":"dir160430925869406903","file":"file160430925900606133"},"newDate":{}} + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160430925727102968') + .query(true) + .reply(201, "", [ + 'Content-Length', + '0', + 'Last-Modified', + 'Mon, 02 Nov 2020 09:27:38 GMT', + 'ETag', + '"0x8D87F118A5AFCEA"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'd7d552a0-c01a-0013-56fa-b071f1000000', + 'x-ms-client-request-id', + '172da17c-e950-46ef-9d00-23669f92cccc', + 'x-ms-version', + '2020-02-10', + 'Date', + 'Mon, 02 Nov 2020 09:27:38 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160430925727102968/dir160430925869406903') + .query(true) + .reply(201, "", [ + 'Content-Length', + '0', + 'Last-Modified', + 'Mon, 02 Nov 2020 09:27:38 GMT', + 'ETag', + '"0x8D87F118A8F38A7"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'd7d552a4-c01a-0013-57fa-b071f1000000', + 'x-ms-client-request-id', + 'b07ab62d-0ac3-43f7-bd49-2d4a6537b153', + 'x-ms-version', + '2020-02-10', + 'x-ms-file-change-time', + '2020-11-02T09:27:38.8738727Z', + 'x-ms-file-last-write-time', + '2020-11-02T09:27:38.8738727Z', + 'x-ms-file-creation-time', + '2020-11-02T09:27:38.8738727Z', + 'x-ms-file-permission-key', + '18253506462963126402*10775527834424002315', + 'x-ms-file-attributes', + 'Directory', + 'x-ms-file-id', + '13835128424026341376', + 'x-ms-file-parent-id', + '0', + 'x-ms-request-server-encrypted', + 'true', + 'Date', + 'Mon, 02 Nov 2020 09:27:38 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160430925727102968/dir160430925869406903/file160430925900606133') + .reply(201, "", [ + 'Content-Length', + '0', + 'Last-Modified', + 'Mon, 02 Nov 2020 09:27:39 GMT', + 'ETag', + '"0x8D87F118ABE679F"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'd7d552a7-c01a-0013-58fa-b071f1000000', + 'x-ms-client-request-id', + '634150e3-ae9e-446a-b090-fe9595a73185', + 'x-ms-version', + '2020-02-10', + 'x-ms-file-change-time', + '2020-11-02T09:27:39.1830943Z', + 'x-ms-file-last-write-time', + '2020-11-02T09:27:39.1830943Z', + 'x-ms-file-creation-time', + '2020-11-02T09:27:39.1830943Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'x-ms-request-server-encrypted', + 'true', + 'Date', + 'Mon, 02 Nov 2020 09:27:38 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160430925727102968/dir160430925869406903/file160430925900606133', "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t") + .query(true) + .reply(201, "", [ + 'Content-Length', + '0', + 'Content-MD5', + 'xWvVSA9uVBPLYqCtlmZhOg==', + 'Last-Modified', + 'Mon, 02 Nov 2020 09:27:39 GMT', + 'ETag', + '"0x8D87F118AEC0FB4"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'd7d552a8-c01a-0013-59fa-b071f1000000', + 'x-ms-client-request-id', + 'becedc24-1044-4482-baa1-f098fa76d285', + 'x-ms-version', + '2020-02-10', + 'x-ms-request-server-encrypted', + 'true', + 'Date', + 'Mon, 02 Nov 2020 09:27:39 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .get('/share160430925727102968/dir160430925869406903/file160430925900606133') + .reply(200, "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t", [ + 'Content-Length', + '10', + 'Content-Type', + 'application/octet-stream', + 'Last-Modified', + 'Mon, 02 Nov 2020 09:27:39 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87F118AEC0FB4"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'd7d552a9-c01a-0013-5afa-b071f1000000', + 'x-ms-client-request-id', + 'd5e095a4-02f7-47b3-ba8e-732f1da6c3b5', + 'x-ms-version', + '2020-02-10', + 'x-ms-type', + 'File', + 'x-ms-server-encrypted', + 'true', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-file-change-time', + '2020-11-02T09:27:39.1830943Z', + 'x-ms-file-last-write-time', + '2020-11-02T09:27:39.1830943Z', + 'x-ms-file-creation-time', + '2020-11-02T09:27:39.1830943Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-type,x-ms-server-encrypted,x-ms-lease-status,x-ms-lease-state,x-ms-file-change-time,x-ms-file-last-write-time,x-ms-file-creation-time,x-ms-file-permission-key,x-ms-file-attributes,x-ms-file-id,x-ms-file-parent-id,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Mon, 02 Nov 2020 09:27:39 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160430925727102968/dir160430925869406903/file160430925900606133') + .reply(201, "", [ + 'Content-Length', + '0', + 'Last-Modified', + 'Mon, 02 Nov 2020 09:27:40 GMT', + 'ETag', + '"0x8D87F118B490DDB"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'd7d552ab-c01a-0013-5cfa-b071f1000000', + 'x-ms-client-request-id', + '66755a53-73f2-4e08-a58d-e7ddd71a495d', + 'x-ms-version', + '2020-02-10', + 'x-ms-file-change-time', + '2020-11-02T09:27:40.0917467Z', + 'x-ms-file-last-write-time', + '2020-11-02T09:27:40.0917467Z', + 'x-ms-file-creation-time', + '2020-11-02T09:27:40.0917467Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'x-ms-request-server-encrypted', + 'true', + 'Date', + 'Mon, 02 Nov 2020 09:27:39 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160430925727102968/dir160430925869406903/file160430925900606133', "\u0001\u0002\u0003") + .query(true) + .reply(201, "", [ + 'Content-Length', + '0', + 'Content-MD5', + 'Uonfc331cyb83SJZevsfrA==', + 'Last-Modified', + 'Mon, 02 Nov 2020 09:27:40 GMT', + 'ETag', + '"0x8D87F118B777962"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'd7d552ac-c01a-0013-5dfa-b071f1000000', + 'x-ms-client-request-id', + 'cf668d54-a5f0-49b9-9780-1c1962fc0fc6', + 'x-ms-version', + '2020-02-10', + 'x-ms-request-server-encrypted', + 'true', + 'Date', + 'Mon, 02 Nov 2020 09:27:40 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .get('/share160430925727102968/dir160430925869406903/file160430925900606133') + .reply(200, "\u0001\u0002\u0003", [ + 'Content-Length', + '3', + 'Content-Type', + 'application/octet-stream', + 'Last-Modified', + 'Mon, 02 Nov 2020 09:27:40 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87F118B777962"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'd7d552af-c01a-0013-5ffa-b071f1000000', + 'x-ms-client-request-id', + '8f0e6091-3204-4544-806c-581c74ec0ea8', + 'x-ms-version', + '2020-02-10', + 'x-ms-type', + 'File', + 'x-ms-server-encrypted', + 'true', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-file-change-time', + '2020-11-02T09:27:40.0917467Z', + 'x-ms-file-last-write-time', + '2020-11-02T09:27:40.0917467Z', + 'x-ms-file-creation-time', + '2020-11-02T09:27:40.0917467Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-type,x-ms-server-encrypted,x-ms-lease-status,x-ms-lease-state,x-ms-file-change-time,x-ms-file-last-write-time,x-ms-file-creation-time,x-ms-file-permission-key,x-ms-file-attributes,x-ms-file-id,x-ms-file-parent-id,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Mon, 02 Nov 2020 09:27:40 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160430925727102968/dir160430925869406903/file160430925900606133') + .reply(201, "", [ + 'Content-Length', + '0', + 'Last-Modified', + 'Mon, 02 Nov 2020 09:27:40 GMT', + 'ETag', + '"0x8D87F118BCF4675"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'd7d552b0-c01a-0013-60fa-b071f1000000', + 'x-ms-client-request-id', + '2f6a97ae-36c2-4889-bb45-38c43ace9d29', + 'x-ms-version', + '2020-02-10', + 'x-ms-file-change-time', + '2020-11-02T09:27:40.9713781Z', + 'x-ms-file-last-write-time', + '2020-11-02T09:27:40.9713781Z', + 'x-ms-file-creation-time', + '2020-11-02T09:27:40.9713781Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'x-ms-request-server-encrypted', + 'true', + 'Date', + 'Mon, 02 Nov 2020 09:27:40 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .put('/share160430925727102968/dir160430925869406903/file160430925900606133', "\u0004\u0005\u0006\u0007") + .query(true) + .reply(201, "", [ + 'Content-Length', + '0', + 'Content-MD5', + 'prhTe5fVi0F9Pf3RAwsV0g==', + 'Last-Modified', + 'Mon, 02 Nov 2020 09:27:41 GMT', + 'ETag', + '"0x8D87F118BFC03FF"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'd7d552b1-c01a-0013-61fa-b071f1000000', + 'x-ms-client-request-id', + '151c5e58-05ce-4f64-ab53-0c9db191911b', + 'x-ms-version', + '2020-02-10', + 'x-ms-request-server-encrypted', + 'true', + 'Date', + 'Mon, 02 Nov 2020 09:27:40 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .get('/share160430925727102968/dir160430925869406903/file160430925900606133') + .reply(200, "\u0004\u0005\u0006\u0007", [ + 'Content-Length', + '4', + 'Content-Type', + 'application/octet-stream', + 'Last-Modified', + 'Mon, 02 Nov 2020 09:27:41 GMT', + 'Accept-Ranges', + 'bytes', + 'ETag', + '"0x8D87F118BFC03FF"', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'd7d552b2-c01a-0013-62fa-b071f1000000', + 'x-ms-client-request-id', + '4771026b-1934-450f-af49-80f73019b084', + 'x-ms-version', + '2020-02-10', + 'x-ms-type', + 'File', + 'x-ms-server-encrypted', + 'true', + 'x-ms-lease-status', + 'unlocked', + 'x-ms-lease-state', + 'available', + 'x-ms-file-change-time', + '2020-11-02T09:27:40.9713781Z', + 'x-ms-file-last-write-time', + '2020-11-02T09:27:40.9713781Z', + 'x-ms-file-creation-time', + '2020-11-02T09:27:40.9713781Z', + 'x-ms-file-permission-key', + '4407534441384161157*10775527834424002315', + 'x-ms-file-attributes', + 'Archive', + 'x-ms-file-id', + '11529285414812647424', + 'x-ms-file-parent-id', + '13835128424026341376', + 'Access-Control-Expose-Headers', + 'x-ms-request-id,x-ms-client-request-id,Server,x-ms-version,Content-Type,Last-Modified,ETag,x-ms-type,x-ms-server-encrypted,x-ms-lease-status,x-ms-lease-state,x-ms-file-change-time,x-ms-file-last-write-time,x-ms-file-creation-time,x-ms-file-permission-key,x-ms-file-attributes,x-ms-file-id,x-ms-file-parent-id,Accept-Ranges,Content-Length,Date,Transfer-Encoding', + 'Access-Control-Allow-Origin', + '*', + 'Date', + 'Mon, 02 Nov 2020 09:27:41 GMT' +]); + +nock('https://fakestorageaccount.file.core.windows.net:443', {"encodedQueryParams":true}) + .delete('/share160430925727102968') + .query(true) + .reply(202, "", [ + 'Content-Length', + '0', + 'Server', + 'Windows-Azure-File/1.0 Microsoft-HTTPAPI/2.0', + 'x-ms-request-id', + 'd7d552b3-c01a-0013-63fa-b071f1000000', + 'x-ms-client-request-id', + '7d70742e-cecc-4af6-8ac4-da814df4fd3d', + 'x-ms-version', + '2020-02-10', + 'Date', + 'Mon, 02 Nov 2020 09:27:41 GMT' +]); diff --git a/sdk/storage/storage-file-share/src/Clients.ts b/sdk/storage/storage-file-share/src/Clients.ts index d78db9e61406..a1310a01c86b 100644 --- a/sdk/storage/storage-file-share/src/Clients.ts +++ b/sdk/storage/storage-file-share/src/Clients.ts @@ -4841,9 +4841,7 @@ export class ShareFileClient extends StorageClient { } return this.uploadSeekableInternal( - (offset: number, size: number): Buffer => { - return buffer.slice(offset, offset + size); - }, + (offset: number, size: number): Buffer => buffer.slice(offset, offset + size), buffer.byteLength, { ...options, @@ -4853,9 +4851,7 @@ export class ShareFileClient extends StorageClient { } else { const browserBlob = new Blob([data]); return this.uploadSeekableInternal( - (offset: number, size: number): Blob => { - return browserBlob.slice(offset, offset + size); - }, + (offset: number, size: number): Blob => browserBlob.slice(offset, offset + size), browserBlob.size, { ...options, tracingOptions: { ...options!.tracingOptions, spanOptions } } ); diff --git a/sdk/storage/storage-file-share/test/fileclient.spec.ts b/sdk/storage/storage-file-share/test/fileclient.spec.ts index 9ca2867fa364..2be101db4909 100644 --- a/sdk/storage/storage-file-share/test/fileclient.spec.ts +++ b/sdk/storage/storage-file-share/test/fileclient.spec.ts @@ -11,7 +11,7 @@ import { FileSystemAttributes } from "../src/FileSystemAttributes"; import { DirectoryCreateResponse } from "../src/generated/src/models"; import { Pipeline } from "../src/Pipeline"; import { truncatedISO8061Date } from "../src/utils/utils.common"; -import { bodyToString, getBSU, recorderEnvSetup } from "./utils"; +import { bodyToString, compareBodyWithUint8Array, getBSU, recorderEnvSetup } from "./utils"; import { MockPolicyFactory } from "./utils/MockPolicyFactory"; import { FILE_MAX_SIZE_BYTES } from "../src/utils/constants"; import { isIE } from "./utils/index.browser"; @@ -477,6 +477,34 @@ describe("FileClient", () => { assert.deepStrictEqual(await bodyToString(response), content); }); + it("uploadData should work with ArrayBuffer and ArrayBufferView", async () => { + const byteLength = 10; + const arrayBuf = new ArrayBuffer(byteLength); + const uint8Array = new Uint8Array(arrayBuf); + for (let i = 0; i < byteLength; i++) { + uint8Array[i] = i; + } + + await fileClient.uploadData(arrayBuf); + const res = await fileClient.download(); + assert.ok(compareBodyWithUint8Array(res, uint8Array)); + + const uint8ArrayPartial = new Uint8Array(arrayBuf, 1, 3); + await fileClient.uploadData(uint8ArrayPartial); + const res1 = await fileClient.download(); + assert.ok(compareBodyWithUint8Array(res1, uint8ArrayPartial)); + + const uint16Array = new Uint16Array(arrayBuf, 4, 2); + await fileClient.uploadData(uint16Array); + const res2 = await fileClient.download(); + assert.ok( + compareBodyWithUint8Array( + res2, + new Uint8Array(arrayBuf, uint16Array.byteOffset, uint16Array.byteLength) + ) + ); + }); + it("uploadRange", async () => { await fileClient.create(10); await fileClient.uploadRange("Hello", 0, 5); diff --git a/sdk/storage/storage-file-share/test/utils/index.browser.ts b/sdk/storage/storage-file-share/test/utils/index.browser.ts index d8b65c4d33a8..e12075771ea5 100644 --- a/sdk/storage/storage-file-share/test/utils/index.browser.ts +++ b/sdk/storage/storage-file-share/test/utils/index.browser.ts @@ -139,3 +139,32 @@ export function getSASConnectionStringFromEnvironment(): string { const env = (window as any).__env__; return `BlobEndpoint=https://${env.ACCOUNT_NAME}.blob.core.windows.net/;QueueEndpoint=https://${env.ACCOUNT_NAME}.queue.core.windows.net/;FileEndpoint=https://${env.ACCOUNT_NAME}.file.core.windows.net/;TableEndpoint=https://${env.ACCOUNT_NAME}.table.core.windows.net/;SharedAccessSignature=${env.ACCOUNT_SAS}`; } + +export function arraysEqual(a: Uint8Array, b: Uint8Array): boolean { + if (a === b) return true; + if (a == null || b == null) return false; + if (a.length != b.length) return false; + + for (let i = 0; i < a.length; ++i) { + if (a[i] !== b[i]) return false; + } + return true; +} + +/** + * Compare the content of body from downloading operation methods with a Uint8Array. + * Work on both Node.js and browser environment. + * + * @param response Convenience layer methods response with downloaded body + * @param uint8arry + */ +export async function compareBodyWithUint8Array( + response: { + readableStreamBody?: NodeJS.ReadableStream; + blobBody?: Promise; + }, + uint8arry: Uint8Array +): Promise { + const blob = await response.blobBody!; + return arraysEqual(uint8arry, new Uint8Array(await blob.arrayBuffer())); +} diff --git a/sdk/storage/storage-file-share/test/utils/index.ts b/sdk/storage/storage-file-share/test/utils/index.ts index 1621b0eee117..4624b02811ae 100644 --- a/sdk/storage/storage-file-share/test/utils/index.ts +++ b/sdk/storage/storage-file-share/test/utils/index.ts @@ -173,3 +173,34 @@ export function getSASConnectionStringFromEnvironment(): string { ".table." )}/;SharedAccessSignature=${sas}`; } + +// A helper method used to read a Node.js readable stream into a Buffer +async function streamToBuffer(readableStream: NodeJS.ReadableStream): Promise { + return new Promise((resolve, reject) => { + const chunks: Buffer[] = []; + readableStream.on("data", (data: Buffer | string) => { + chunks.push(data instanceof Buffer ? data : Buffer.from(data)); + }); + readableStream.on("end", () => { + resolve(Buffer.concat(chunks)); + }); + readableStream.on("error", reject); + }); +} + +/** + * Compare the content of body from downloading operation methods with a Uint8Array. + * Work on both Node.js and browser environment. + * + * @param response Convenience layer methods response with downloaded body + */ +export async function compareBodyWithUint8Array( + response: { + readableStreamBody?: NodeJS.ReadableStream; + blobBody?: Promise; + }, + uint8arry: Uint8Array +): Promise { + const buf = await streamToBuffer(response.readableStreamBody!); + return buf.equals(Buffer.from(uint8arry.buffer, uint8arry.byteOffset, uint8arry.byteLength)); +} From 2f1c11850404722b7999812334e21280b784f004 Mon Sep 17 00:00:00 2001 From: Lin Jian Date: Mon, 2 Nov 2020 19:20:07 +0800 Subject: [PATCH 3/3] nit: comments --- .../storage-blob-changefeed/src/utils/utils.browser.ts | 2 +- sdk/storage/storage-blob-changefeed/src/utils/utils.node.ts | 2 +- sdk/storage/storage-blob/test/utils/index.browser.ts | 2 +- sdk/storage/storage-blob/test/utils/index.ts | 2 +- sdk/storage/storage-file-datalake/test/utils/index.browser.ts | 2 +- sdk/storage/storage-file-datalake/test/utils/index.ts | 2 +- sdk/storage/storage-file-share/test/utils/index.browser.ts | 4 ++-- sdk/storage/storage-file-share/test/utils/index.ts | 4 ++-- sdk/storage/storage-queue/test/utils/index.browser.ts | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/sdk/storage/storage-blob-changefeed/src/utils/utils.browser.ts b/sdk/storage/storage-blob-changefeed/src/utils/utils.browser.ts index 18ae9408302d..4a20fbc48faa 100644 --- a/sdk/storage/storage-blob-changefeed/src/utils/utils.browser.ts +++ b/sdk/storage/storage-blob-changefeed/src/utils/utils.browser.ts @@ -3,7 +3,7 @@ /** * Read body from downloading operation methods to string. - * Work on both Node.js and browser environment. + * Works in both Node.js and browsers. * * @param response Convenience layer methods response with downloaded body * @param length Length of Readable stream, needed for Node.js environment diff --git a/sdk/storage/storage-blob-changefeed/src/utils/utils.node.ts b/sdk/storage/storage-blob-changefeed/src/utils/utils.node.ts index b613eec3e91c..84d77700ee5b 100644 --- a/sdk/storage/storage-blob-changefeed/src/utils/utils.node.ts +++ b/sdk/storage/storage-blob-changefeed/src/utils/utils.node.ts @@ -5,7 +5,7 @@ import { AvroReadable, AvroReadableFromStream } from "../../../storage-internal- /** * Read body from downloading operation methods to string. - * Work on both Node.js and browser environment. + * Works in both Node.js and browsers. * * @param response Convenience layer methods response with downloaded body * @param length Length of Readable stream, needed for Node.js environment diff --git a/sdk/storage/storage-blob/test/utils/index.browser.ts b/sdk/storage/storage-blob/test/utils/index.browser.ts index 5c561accea42..c7a5eb068e73 100644 --- a/sdk/storage/storage-blob/test/utils/index.browser.ts +++ b/sdk/storage/storage-blob/test/utils/index.browser.ts @@ -84,7 +84,7 @@ export function getAlternateBSU(): BlobServiceClient { /** * Read body from downloading operation methods to string. - * Work on both Node.js and browser environment. + * Works in both Node.js and browsers. * * @param response Convenience layer methods response with downloaded body * @param length Length of Readable stream, needed for Node.js environment diff --git a/sdk/storage/storage-blob/test/utils/index.ts b/sdk/storage/storage-blob/test/utils/index.ts index 0a13368eb0bb..699ec67403ef 100644 --- a/sdk/storage/storage-blob/test/utils/index.ts +++ b/sdk/storage/storage-blob/test/utils/index.ts @@ -139,7 +139,7 @@ export function getConnectionStringFromEnvironment(): string { /** * Read body from downloading operation methods to string. - * Work on both Node.js and browser environment. + * Works in both Node.js and browsers. * * @param response Convenience layer methods response with downloaded body * @param length Length of Readable stream, needed for Node.js environment diff --git a/sdk/storage/storage-file-datalake/test/utils/index.browser.ts b/sdk/storage/storage-file-datalake/test/utils/index.browser.ts index 2e8984991dfe..02201657ee23 100644 --- a/sdk/storage/storage-file-datalake/test/utils/index.browser.ts +++ b/sdk/storage/storage-file-datalake/test/utils/index.browser.ts @@ -86,7 +86,7 @@ export function getAlternateDataLakeServiceClient(): DataLakeServiceClient { /** * Read body from downloading operation methods to string. - * Work on both Node.js and browser environment. + * Works in both Node.js and browsers. * * @param response Convenience layer methods response with downloaded body * @param length Length of Readable stream, needed for Node.js environment diff --git a/sdk/storage/storage-file-datalake/test/utils/index.ts b/sdk/storage/storage-file-datalake/test/utils/index.ts index 3914c8b2ea6f..3c9f241cf2c3 100644 --- a/sdk/storage/storage-file-datalake/test/utils/index.ts +++ b/sdk/storage/storage-file-datalake/test/utils/index.ts @@ -124,7 +124,7 @@ export function getAlternateDataLakeServiceClient(): DataLakeServiceClient { /** * Read body from downloading operation methods to string. - * Work on both Node.js and browser environment. + * Works in both Node.js and browsers. * * @param response Convenience layer methods response with downloaded body * @param length Length of Readable stream, needed for Node.js environment diff --git a/sdk/storage/storage-file-share/test/utils/index.browser.ts b/sdk/storage/storage-file-share/test/utils/index.browser.ts index e12075771ea5..d6adb2f7ffa6 100644 --- a/sdk/storage/storage-file-share/test/utils/index.browser.ts +++ b/sdk/storage/storage-file-share/test/utils/index.browser.ts @@ -49,7 +49,7 @@ export function getSoftDeleteBSU(): ShareServiceClient { /** * Read body from downloading operation methods to string. - * Work on both Node.js and browser environment. + * Works in both Node.js and browsers. * * @param response Convenience layer methods response with downloaded body * @param length Length of Readable stream, needed for Node.js environment @@ -153,7 +153,7 @@ export function arraysEqual(a: Uint8Array, b: Uint8Array): boolean { /** * Compare the content of body from downloading operation methods with a Uint8Array. - * Work on both Node.js and browser environment. + * Works in both Node.js and browsers. * * @param response Convenience layer methods response with downloaded body * @param uint8arry diff --git a/sdk/storage/storage-file-share/test/utils/index.ts b/sdk/storage/storage-file-share/test/utils/index.ts index 4624b02811ae..fc55765fe28b 100644 --- a/sdk/storage/storage-file-share/test/utils/index.ts +++ b/sdk/storage/storage-file-share/test/utils/index.ts @@ -70,7 +70,7 @@ export function getConnectionStringFromEnvironment(): string { /** * Read body from downloading operation methods to string. - * Work on both Node.js and browser environment. + * Works in both Node.js and browsers. * * @param response Convenience layer methods response with downloaded body * @param length Length of Readable stream, needed for Node.js environment @@ -190,7 +190,7 @@ async function streamToBuffer(readableStream: NodeJS.ReadableStream): Promise