зеркало из https://github.com/Azure/Azurite.git
Merge remote-tracking branch 'upstream/master' into table_merge_master
This commit is contained in:
Коммит
782b3474c0
|
@ -19,6 +19,4 @@ swagger
|
|||
.lintstagedrc
|
||||
.vscode
|
||||
.vscodeignore
|
||||
dist
|
||||
**/*.cert
|
||||
**/*.key
|
||||
dist
|
|
@ -0,0 +1,11 @@
|
|||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "daily"
|
16
ChangeLog.md
16
ChangeLog.md
|
@ -2,6 +2,22 @@
|
|||
|
||||
> Note. This file includes changes after 3.0.0-preview. For legacy Azurite changes, please goto GitHub [releases](https://github.com/Azure/Azurite/releases).
|
||||
|
||||
## Upcoming Release
|
||||
|
||||
## 2020.10 Version 3.9.0
|
||||
|
||||
- Bump up Azure Storage service API version to 2020-02-10.
|
||||
- Update Azurite and Azurite tests to reference Azure Storage SDK v12.
|
||||
- Add handling of SIGTERM to gracefully stop the docker container.
|
||||
|
||||
Blob:
|
||||
|
||||
- Add support for async copy blobs across storage accounts within the same Azurite instance.
|
||||
- Add support for async copy blobs on sql metadata store.
|
||||
- Add support for blob syncCopyFromURL within same Azurite instance on loki metadata store.
|
||||
- Allow mixed case characters for blob metadata prefix.
|
||||
- Fix SqlBlobMetadataStore.getBlockList, to make it fail for non-existent blobs.
|
||||
|
||||
## 2020.07 Version 3.8.0
|
||||
|
||||
- Bump up Azure Storage service API version to 2019-12-12.
|
||||
|
|
42
Dockerfile
42
Dockerfile
|
@ -1,20 +1,42 @@
|
|||
#
|
||||
# Builder
|
||||
#
|
||||
FROM node:lts-alpine AS builder
|
||||
|
||||
WORKDIR /opt/azurite
|
||||
|
||||
# Install dependencies first
|
||||
COPY *.json LICENSE NOTICE.txt ./
|
||||
RUN npm config set unsafe-perm=true && \
|
||||
npm ci
|
||||
|
||||
# Copy the source code and build the app
|
||||
COPY src ./src
|
||||
COPY tests ./tests
|
||||
RUN npm run build && \
|
||||
npm run test && \
|
||||
npm install -g --loglevel verbose
|
||||
|
||||
|
||||
#
|
||||
# Production image
|
||||
#
|
||||
FROM node:lts-alpine
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
WORKDIR /opt/azurite
|
||||
|
||||
# Default Workspace Volume
|
||||
VOLUME [ "/data" ]
|
||||
|
||||
COPY src ./src
|
||||
COPY tests ./tests
|
||||
COPY *.json ./
|
||||
COPY LICENSE .
|
||||
COPY NOTICE.txt .
|
||||
COPY package*.json LICENSE NOTICE.txt ./
|
||||
|
||||
RUN npm config set unsafe-perm=true && \
|
||||
npm ci
|
||||
|
||||
COPY --from=builder /opt/azurite/dist/ dist/
|
||||
|
||||
RUN npm config set unsafe-perm=true
|
||||
RUN npm ci
|
||||
RUN npm run build
|
||||
RUN ls -l
|
||||
RUN npm install -g --loglevel verbose
|
||||
|
||||
# Blob Storage Port
|
||||
|
@ -24,4 +46,4 @@ EXPOSE 10001
|
|||
# Table Storage Port
|
||||
EXPOSE 10002
|
||||
|
||||
CMD ["azurite", "-l", "/data", "--blobHost", "0.0.0.0","--queueHost", "0.0.0.0", "--tableHost", "0.0.0.0"]
|
||||
CMD ["azurite", "-l", "/data", "--blobHost", "0.0.0.0","--queueHost", "0.0.0.0", "--tableHost", "0.0.0.0"]
|
||||
|
|
|
@ -2,7 +2,7 @@ Thanks for contribution! Please go through following checklist before sending PR
|
|||
|
||||
### PR Branch Destination
|
||||
|
||||
- For Azurite V3, please send PR to `dev` branch.
|
||||
- For Azurite V3, please send PR to `master` branch.
|
||||
- For legacy Azurite V2, please send PR to `legacy-dev` branch.
|
||||
|
||||
### Always Add Test Cases
|
||||
|
|
27
README.md
27
README.md
|
@ -10,7 +10,7 @@
|
|||
|
||||
| Version | Azure Storage API Version | Service Support | Description | Reference Links |
|
||||
| ------------------------------------------------------------------ | ------------------------- | --------------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 3.8.0 | 2019-12-12 | Blob<br>Queue | Azurite V3 based on TypeScript & New Architecture | [NPM](https://www.npmjs.com/package/azurite) - [Docker](https://hub.docker.com/_/microsoft-azure-storage-azurite) - [Visual Studio Code Extension](https://marketplace.visualstudio.com/items?itemName=Azurite.azurite) |
|
||||
| 3.9.0 | 2020-02-10 | Blob<br>Queue | Azurite V3 based on TypeScript & New Architecture | [NPM](https://www.npmjs.com/package/azurite) - [Docker](https://hub.docker.com/_/microsoft-azure-storage-azurite) - [Visual Studio Code Extension](https://marketplace.visualstudio.com/items?itemName=Azurite.azurite) |
|
||||
| [Legacy (v2)](https://github.com/Azure/Azurite/tree/legacy-master) | 2016-05-31 | Blob, Queue and Table | Legacy Azurite V2 | [NPM](https://www.npmjs.com/package/azurite) |
|
||||
|
||||
## Introduction
|
||||
|
@ -19,19 +19,19 @@ Azurite is an open source Azure Storage API compatible server (emulator). Based
|
|||
|
||||
Azurite V2 is manually created with pure JavaScript, popular and active as an open source project. However, Azure Storage APIs are growing and keeping updating, manually keeping Azurite up to date is not efficient and prone to bugs. JavaScript also lacks strong type validation which prevents easy collaboration.
|
||||
|
||||
Compared to V2, Azurite V3 implements a new architecture leveraging code generated by a TypeScript Server Code Generator we created. The generator uses the same swagger (modified) used by the new Azure Storage SDKs. This reduces manual effort and more facilitates better code alignment with storage APIs.
|
||||
Compared to V2, Azurite V3 implements a new architecture leveraging code generated by a TypeScript Server Code Generator we created. The generator uses the same swagger (modified) used by the new Azure Storage SDKs. This reduces manual effort and facilitates better code alignment with storage APIs.
|
||||
|
||||
3.0.0-preview is the first release version using Azurite's new architecture.
|
||||
|
||||
## Features & Key Changes in Azurite V3
|
||||
|
||||
- Blob storage features align with Azure Storage API version 2019-12-12 (Refer to support matrix section below)
|
||||
- Blob storage features align with Azure Storage API version 2020-02-10 (Refer to support matrix section below)
|
||||
- SharedKey/Account SAS/Service SAS/Public Access Authentications
|
||||
- Get/Set Blob Service Properties
|
||||
- Create/List/Delete Containers
|
||||
- Create/Read/List/Update/Delete Block Blobs
|
||||
- Create/Read/List/Update/Delete Page Blobs
|
||||
- Queue storage features align with Azure Storage API version 2019-12-12 (Refer to support matrix section below)
|
||||
- Queue storage features align with Azure Storage API version 2020-02-10 (Refer to support matrix section below)
|
||||
- SharedKey/Account SAS/Service SAS
|
||||
- Get/Set Queue Service Properties
|
||||
- Preflight Request
|
||||
|
@ -778,7 +778,7 @@ Legacy Azurite V2 supports Azure Storage Blob, Queue and Table services.
|
|||
Azurite V3 currently only supports Azure Storage blob service. Queue service is supported after V3.2.0-preview.
|
||||
Table service support is currently under discussion.
|
||||
|
||||
Azurite V3 supports features from Azure Storage API version 2019-12-12, and will maintain parity with the latest API versions, in a more frequent update frequency than legacy Azurite V2.
|
||||
Azurite V3 supports features from Azure Storage API version 2020-02-10, and will maintain parity with the latest API versions, in a more frequent update frequency than legacy Azurite V2.
|
||||
|
||||
## TypeScript Server Code Generator
|
||||
|
||||
|
@ -789,7 +789,8 @@ All the generated code is kept in `generated` folder, including the generated mi
|
|||
|
||||
## Support Matrix
|
||||
|
||||
Latest release targets **2019-12-12** API version **blob** service.
|
||||
Latest release targets **2020-02-10** API version **blob** service.
|
||||
|
||||
Detailed support matrix:
|
||||
|
||||
- Supported Vertical Features
|
||||
|
@ -823,21 +824,26 @@ Detailed support matrix:
|
|||
- Create Append Blob, Append Block
|
||||
- Lease Blob
|
||||
- Snapshot Blob
|
||||
- Copy Blob (Only supports copy within same account in Azurite)
|
||||
- Abort Copy Blob (Only supports copy within same account in Azurite)
|
||||
- Copy Blob (Only supports copy within same Azurite instance)
|
||||
- Abort Copy Blob (Only supports copy within same Azurite instance)
|
||||
- Copy Blob From URL (Only supports copy within same Azurite instance, only on Loki)
|
||||
- Access control based on conditional headers
|
||||
- Following features or REST APIs are NOT supported or limited supported in this release (will support more features per customers feedback in future releases)
|
||||
|
||||
- SharedKey Lite
|
||||
- Delegation SAS
|
||||
- Static Website
|
||||
- Soft delete & Undelete Blob
|
||||
- Put Block from URL
|
||||
- Incremental Copy Blob
|
||||
- Blob Tags
|
||||
- Blob Query
|
||||
- Blob Versions
|
||||
- Blob Last Access Time
|
||||
- Concurrent Append
|
||||
- Blob Expiry
|
||||
- Object Replication Service
|
||||
|
||||
Latest version supports for **2019-12-12** API version **queue** service.
|
||||
Latest version supports for **2020-02-10** API version **queue** service.
|
||||
Detailed support matrix:
|
||||
|
||||
- Supported Vertical Features
|
||||
|
@ -865,6 +871,7 @@ Detailed support matrix:
|
|||
- Clear Message
|
||||
- Following features or REST APIs are NOT supported or limited supported in this release (will support more features per customers feedback in future releases)
|
||||
- SharedKey Lite
|
||||
- Delegation SAS
|
||||
|
||||
Latest version supports for **2019-12-12** API version **table** service.
|
||||
Detailed support matrix:
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
15
package.json
15
package.json
|
@ -3,7 +3,7 @@
|
|||
"displayName": "Azurite",
|
||||
"description": "An open source Azure Storage API compatible server",
|
||||
"icon": "icon.png",
|
||||
"version": "3.8.0",
|
||||
"version": "3.9.0",
|
||||
"publisher": "Azurite",
|
||||
"categories": [
|
||||
"Other"
|
||||
|
@ -31,9 +31,8 @@
|
|||
"multistream": "^2.1.1",
|
||||
"mysql2": "^2.1.0",
|
||||
"rimraf": "^2.6.3",
|
||||
"sequelize": "^5.18.4",
|
||||
"tedious": "^6.6.5",
|
||||
"tsc": "^1.20150623.0",
|
||||
"sequelize": "^6.3.0",
|
||||
"tedious": "^9.2.1",
|
||||
"tslib": "^1.9.3",
|
||||
"uri-templates": "^0.2.0",
|
||||
"uuid": "^3.3.2",
|
||||
|
@ -41,8 +40,8 @@
|
|||
"xml2js": "^0.4.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@azure/storage-blob": "^10.4.1",
|
||||
"@azure/storage-queue": "^10.2.0",
|
||||
"@azure/storage-blob": "^12.1.2",
|
||||
"@azure/storage-queue": "^12.0.5",
|
||||
"@types/args": "^3.0.0",
|
||||
"@types/async": "^3.0.1",
|
||||
"@types/bluebird": "^3.5.27",
|
||||
|
@ -64,12 +63,12 @@
|
|||
"cross-env": "^6.0.3",
|
||||
"cross-var": "^1.1.0",
|
||||
"husky": "^1.3.1",
|
||||
"lint-staged": "^8.1.5",
|
||||
"lint-staged": "^8.2.1",
|
||||
"mocha": "^5.2.0",
|
||||
"prettier": "^2.1.2",
|
||||
"prettier-tslint": "^0.4.2",
|
||||
"ts-node": "^9.0.0",
|
||||
"tslint": "^5.20.1",
|
||||
"tslint": "^6.1.3",
|
||||
"typescript": "^4.0.5",
|
||||
"vsce": "^1.64.0"
|
||||
},
|
||||
|
|
|
@ -17,18 +17,46 @@ import {
|
|||
DEFAULT_QUEUE_PERSISTENCE_ARRAY,
|
||||
DEFAULT_QUEUE_PERSISTENCE_PATH
|
||||
} from "./queue/utils/constants";
|
||||
import SqlBlobServer from "./blob/SqlBlobServer";
|
||||
import BlobServer from "./blob/BlobServer";
|
||||
|
||||
import TableConfiguration from "./table/TableConfiguration";
|
||||
import TableServer from "./table/TableServer";
|
||||
|
||||
import {
|
||||
DEFAULT_TABLE_LOKI_DB_PATH
|
||||
} from "./table/utils/constants";
|
||||
import { DEFAULT_TABLE_LOKI_DB_PATH } from "./table/utils/constants";
|
||||
|
||||
// tslint:disable:no-console
|
||||
|
||||
const accessAsync = promisify(access);
|
||||
|
||||
function shutdown(
|
||||
blobServer: BlobServer | SqlBlobServer,
|
||||
queueServer: QueueServer,
|
||||
tableServer: TableServer
|
||||
) {
|
||||
const blobBeforeCloseMessage = `Azurite Blob service is closing...`;
|
||||
const blobAfterCloseMessage = `Azurite Blob service successfully closed`;
|
||||
const queueBeforeCloseMessage = `Azurite Queue service is closing...`;
|
||||
const queueAfterCloseMessage = `Azurite Queue service successfully closed`;
|
||||
const tableBeforeCloseMessage = `Azurite Table service is closing...`;
|
||||
const tableAfterCloseMessage = `Azurite Table service successfully closed`;
|
||||
|
||||
console.log(blobBeforeCloseMessage);
|
||||
blobServer.close().then(() => {
|
||||
console.log(blobAfterCloseMessage);
|
||||
});
|
||||
|
||||
console.log(queueBeforeCloseMessage);
|
||||
queueServer.close().then(() => {
|
||||
console.log(queueAfterCloseMessage);
|
||||
});
|
||||
|
||||
console.log(tableBeforeCloseMessage);
|
||||
tableServer.close().then(() => {
|
||||
console.log(tableAfterCloseMessage);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry for Azurite services.
|
||||
*/
|
||||
|
@ -129,50 +157,17 @@ async function main() {
|
|||
);
|
||||
|
||||
// Handle close event
|
||||
const blobBeforeCloseMessage = `Azurite Blob service is closing...`;
|
||||
const blobAfterCloseMessage = `Azurite Blob service successfully closed`;
|
||||
const tableBeforeCloseMessage = `Azurite Table service is closing...`;
|
||||
const tableAfterCloseMessage = `Azurite Table service successfully closed`;
|
||||
const queueBeforeCloseMessage = `Azurite Queue service is closing...`;
|
||||
const queueAfterCloseMessage = `Azurite Queue service successfully closed`;
|
||||
process
|
||||
.once("message", msg => {
|
||||
.once("message", (msg) => {
|
||||
if (msg === "shutdown") {
|
||||
console.log(blobBeforeCloseMessage);
|
||||
blobServer.close().then(() => {
|
||||
console.log(blobAfterCloseMessage);
|
||||
});
|
||||
|
||||
console.log(tableBeforeCloseMessage);
|
||||
tableServer.close().then(() => {
|
||||
console.log(tableAfterCloseMessage);
|
||||
});
|
||||
|
||||
console.log(queueBeforeCloseMessage);
|
||||
queueServer.close().then(() => {
|
||||
console.log(queueAfterCloseMessage);
|
||||
});
|
||||
shutdown(blobServer, queueServer, tableServer);
|
||||
}
|
||||
})
|
||||
.once("SIGINT", () => {
|
||||
console.log(blobBeforeCloseMessage);
|
||||
blobServer.close().then(() => {
|
||||
console.log(blobAfterCloseMessage);
|
||||
});
|
||||
|
||||
console.log(tableBeforeCloseMessage);
|
||||
tableServer.close().then(() => {
|
||||
console.log(tableAfterCloseMessage);
|
||||
});
|
||||
|
||||
console.log(queueBeforeCloseMessage);
|
||||
queueServer.close().then(() => {
|
||||
console.log(queueAfterCloseMessage);
|
||||
});
|
||||
});
|
||||
.once("SIGINT", () => shutdown(blobServer, queueServer, tableServer))
|
||||
.once("SIGTERM", () => shutdown(blobServer, queueServer, tableServer));
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
main().catch((err) => {
|
||||
console.error(`Exit due to unhandled error: ${err.message}`);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
|
@ -243,7 +243,8 @@ export default class AccountSASAuthenticator implements IAuthenticator {
|
|||
operation === Operation.BlockBlob_Upload ||
|
||||
operation === Operation.PageBlob_Create ||
|
||||
operation === Operation.AppendBlob_Create ||
|
||||
operation === Operation.Blob_StartCopyFromURL
|
||||
operation === Operation.Blob_StartCopyFromURL ||
|
||||
operation === Operation.Blob_CopyFromURL
|
||||
) {
|
||||
this.logger.info(
|
||||
`AccountSASAuthenticator:validate() For ${Operation[operation]}, if blob exists, the permission must be Write.`,
|
||||
|
|
|
@ -316,7 +316,8 @@ export default class BlobSASAuthenticator implements IAuthenticator {
|
|||
operation === Operation.BlockBlob_Upload ||
|
||||
operation === Operation.PageBlob_Create ||
|
||||
operation === Operation.AppendBlob_Create ||
|
||||
operation === Operation.Blob_StartCopyFromURL
|
||||
operation === Operation.Blob_StartCopyFromURL ||
|
||||
operation === Operation.Blob_CopyFromURL
|
||||
) {
|
||||
this.logger.info(
|
||||
`BlobSASAuthenticator:validate() For ${Operation[operation]}, if blob exists, the permission must be Write.`,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { IIPRange } from "@azure/storage-blob";
|
||||
import { SasIPRange } from "@azure/storage-blob";
|
||||
|
||||
import {
|
||||
computeHMACSHA256,
|
||||
|
@ -84,10 +84,10 @@ export interface IAccountSASSignatureValues {
|
|||
/**
|
||||
* Optional. IP range allowed.
|
||||
*
|
||||
* @type {IIPRange | string}
|
||||
* @type {SasIPRange | string}
|
||||
* @memberof IAccountSASSignatureValues
|
||||
*/
|
||||
ipRange?: IIPRange | string;
|
||||
ipRange?: SasIPRange | string;
|
||||
|
||||
/**
|
||||
* The values that indicate the services accessible with this SAS. Please refer to {@link AccountSASServices} to
|
||||
|
|
|
@ -484,6 +484,16 @@ OPERATION_ACCOUNT_SAS_PERMISSIONS.set(
|
|||
)
|
||||
);
|
||||
|
||||
OPERATION_ACCOUNT_SAS_PERMISSIONS.set(
|
||||
Operation.Blob_CopyFromURL,
|
||||
new OperationAccountSASPermission(
|
||||
AccountSASService.Blob,
|
||||
AccountSASResourceType.Object,
|
||||
// If destination is an existing blob, create permission is not enough
|
||||
AccountSASPermission.Write + AccountSASPermission.Create
|
||||
)
|
||||
);
|
||||
|
||||
OPERATION_ACCOUNT_SAS_PERMISSIONS.set(
|
||||
Operation.PageBlob_CopyIncremental,
|
||||
new OperationAccountSASPermission(
|
||||
|
|
|
@ -177,6 +177,13 @@ OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set(
|
|||
Operation.Blob_AbortCopyFromURL,
|
||||
new OperationBlobSASPermission(BlobSASPermission.Write)
|
||||
);
|
||||
OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set(
|
||||
Operation.Blob_CopyFromURL,
|
||||
// TODO: When destination blob doesn't exist, needs create permission
|
||||
new OperationBlobSASPermission(
|
||||
BlobSASPermission.Write + BlobSASPermission.Create
|
||||
)
|
||||
);
|
||||
OPERATION_BLOB_SAS_BLOB_PERMISSIONS.set(
|
||||
Operation.Blob_SetTier,
|
||||
new OperationBlobSASPermission(BlobSASPermission.Write) // TODO: Not sure
|
||||
|
@ -411,7 +418,6 @@ OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set(
|
|||
);
|
||||
OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set(
|
||||
Operation.Blob_StartCopyFromURL,
|
||||
// TODO: If destination is an existing blob, create permission is not enough
|
||||
new OperationBlobSASPermission(
|
||||
BlobSASPermission.Write + BlobSASPermission.Create
|
||||
)
|
||||
|
@ -420,6 +426,12 @@ OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set(
|
|||
Operation.Blob_AbortCopyFromURL,
|
||||
new OperationBlobSASPermission(BlobSASPermission.Write)
|
||||
);
|
||||
OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set(
|
||||
Operation.Blob_CopyFromURL,
|
||||
new OperationBlobSASPermission(
|
||||
BlobSASPermission.Write + BlobSASPermission.Create
|
||||
)
|
||||
);
|
||||
OPERATION_BLOB_SAS_CONTAINER_PERMISSIONS.set(
|
||||
Operation.Blob_SetTier,
|
||||
new OperationBlobSASPermission(BlobSASPermission.Write)
|
||||
|
|
|
@ -695,4 +695,19 @@ export default class StorageErrorFactory {
|
|||
additionalMessages
|
||||
);
|
||||
}
|
||||
|
||||
public static getCannotVerifyCopySource(
|
||||
contextID: string,
|
||||
statusCode: number,
|
||||
message: string,
|
||||
additionalMessages?: { [key: string]: string }
|
||||
): StorageError {
|
||||
return new StorageError(
|
||||
statusCode,
|
||||
"CannotVerifyCopySource",
|
||||
message,
|
||||
contextID,
|
||||
additionalMessages
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import { URLBuilder } from "@azure/ms-rest-js";
|
||||
import axios, { AxiosResponse } from "axios";
|
||||
import { URL } from "url";
|
||||
|
||||
import IExtentStore from "../../common/persistence/IExtentStore";
|
||||
|
@ -12,6 +14,7 @@ import * as Models from "../generated/artifacts/models";
|
|||
import Context from "../generated/Context";
|
||||
import IBlobHandler from "../generated/handlers/IBlobHandler";
|
||||
import ILogger from "../generated/utils/ILogger";
|
||||
import { parseXML } from "../generated/utils/xml";
|
||||
import { extractStoragePartsFromPath } from "../middlewares/blobStorageContext.middleware";
|
||||
import IBlobMetadataStore, {
|
||||
BlobModel
|
||||
|
@ -69,14 +72,6 @@ export default class BlobHandler extends BaseHandler implements IBlobHandler {
|
|||
throw new NotImplementedError(context.contextId);
|
||||
}
|
||||
|
||||
public copyFromURL(
|
||||
copySource: string,
|
||||
options: Models.BlobCopyFromURLOptionalParams,
|
||||
context: Context
|
||||
): Promise<Models.BlobCopyFromURLResponse> {
|
||||
throw new NotImplementedError(context.contextId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download blob.
|
||||
*
|
||||
|
@ -634,7 +629,6 @@ export default class BlobHandler extends BaseHandler implements IBlobHandler {
|
|||
const snapshot = url.searchParams.get("snapshot") || "";
|
||||
|
||||
if (
|
||||
sourceAccount !== blobCtx.account ||
|
||||
sourceAccount === undefined ||
|
||||
sourceContainer === undefined ||
|
||||
sourceBlob === undefined
|
||||
|
@ -642,6 +636,80 @@ export default class BlobHandler extends BaseHandler implements IBlobHandler {
|
|||
throw StorageErrorFactory.getBlobNotFound(context.contextId!);
|
||||
}
|
||||
|
||||
if (sourceAccount !== blobCtx.account) {
|
||||
// Currently the only cross-account copy support is from/to the same Azurite instance. In either case access
|
||||
// is determined by performing a request to the copy source to see if the authentication is valid.
|
||||
const currentServer = blobCtx.request!.getHeader("Host") || "";
|
||||
if (currentServer !== url.host) {
|
||||
this.logger.error(
|
||||
`BlobHandler:startCopyFromURL() Source account ${url} is not on the same Azurite instance as target account ${account}`,
|
||||
context.contextId
|
||||
);
|
||||
|
||||
throw StorageErrorFactory.getCannotVerifyCopySource(
|
||||
context.contextId!,
|
||||
404,
|
||||
"The specified resource does not exist"
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.debug(
|
||||
`BlobHandler:startCopyFromURL() Validating access to the source account ${sourceAccount}`,
|
||||
context.contextId
|
||||
);
|
||||
|
||||
// In order to retrieve proper error details we make a metadata request to the copy source. If we instead issue
|
||||
// a HEAD request then the error details are not returned and reporting authentication failures to the caller
|
||||
// becomes a black box.
|
||||
const metadataUrl = URLBuilder.parse(copySource);
|
||||
metadataUrl.setQueryParameter("comp", "metadata");
|
||||
const validationResponse: AxiosResponse = await axios.get(
|
||||
metadataUrl.toString(),
|
||||
{
|
||||
// Instructs axios to not throw an error for non-2xx responses
|
||||
validateStatus: () => true
|
||||
}
|
||||
);
|
||||
if (validationResponse.status === 200) {
|
||||
this.logger.debug(
|
||||
`BlobHandler:startCopyFromURL() Successfully validated access to source account ${sourceAccount}`,
|
||||
context.contextId
|
||||
);
|
||||
} else {
|
||||
this.logger.debug(
|
||||
`BlobHandler:startCopyFromURL() Access denied to source account ${sourceAccount} StatusCode=${validationResponse.status}, AuthenticationErrorDetail=${validationResponse.data}`,
|
||||
context.contextId
|
||||
);
|
||||
|
||||
if (validationResponse.status === 404) {
|
||||
throw StorageErrorFactory.getCannotVerifyCopySource(
|
||||
context.contextId!,
|
||||
validationResponse.status,
|
||||
"The specified resource does not exist"
|
||||
);
|
||||
} else {
|
||||
// For non-successful responses attempt to unwrap the error message from the metadata call.
|
||||
let message: string =
|
||||
"Could not verify the copy source within the specified time.";
|
||||
if (
|
||||
validationResponse.headers[HeaderConstants.CONTENT_TYPE] ===
|
||||
"application/xml"
|
||||
) {
|
||||
const authenticationError = await parseXML(validationResponse.data);
|
||||
if (authenticationError.Message !== undefined) {
|
||||
message = authenticationError.Message.replace(/\n+/gm, "");
|
||||
}
|
||||
}
|
||||
|
||||
throw StorageErrorFactory.getCannotVerifyCopySource(
|
||||
context.contextId!,
|
||||
validationResponse.status,
|
||||
message
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Preserve metadata key case
|
||||
const metadata = convertRawHeadersToMetadata(
|
||||
blobCtx.request!.getRawHeaders()
|
||||
|
@ -723,6 +791,77 @@ export default class BlobHandler extends BaseHandler implements IBlobHandler {
|
|||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy from Url.
|
||||
*
|
||||
* @param {string} copySource
|
||||
* @param {Models.BlobStartCopyFromURLOptionalParams} options
|
||||
* @param {Context} context
|
||||
* @returns {Promise<Models.BlobStartCopyFromURLResponse>}
|
||||
* @memberof BlobHandler
|
||||
*/
|
||||
public async copyFromURL(
|
||||
copySource: string,
|
||||
options: Models.BlobCopyFromURLOptionalParams,
|
||||
context: Context
|
||||
): Promise<Models.BlobCopyFromURLResponse> {
|
||||
const blobCtx = new BlobStorageContext(context);
|
||||
const account = blobCtx.account!;
|
||||
const container = blobCtx.container!;
|
||||
const blob = blobCtx.blob!;
|
||||
|
||||
// TODO: Check dest Lease status, and set to available if it's expired, see sample in BlobHandler.setMetadata()
|
||||
const url = new URL(copySource);
|
||||
const [
|
||||
sourceAccount,
|
||||
sourceContainer,
|
||||
sourceBlob
|
||||
] = extractStoragePartsFromPath(url.hostname, url.pathname);
|
||||
const snapshot = url.searchParams.get("snapshot") || "";
|
||||
|
||||
if (
|
||||
sourceAccount !== blobCtx.account ||
|
||||
sourceAccount === undefined ||
|
||||
sourceContainer === undefined ||
|
||||
sourceBlob === undefined
|
||||
) {
|
||||
throw StorageErrorFactory.getBlobNotFound(context.contextId!);
|
||||
}
|
||||
|
||||
// Preserve metadata key case
|
||||
const metadata = convertRawHeadersToMetadata(
|
||||
blobCtx.request!.getRawHeaders()
|
||||
);
|
||||
|
||||
const res = await this.metadataStore.copyFromURL(
|
||||
context,
|
||||
{
|
||||
account: sourceAccount,
|
||||
container: sourceContainer,
|
||||
blob: sourceBlob,
|
||||
snapshot
|
||||
},
|
||||
{ account, container, blob },
|
||||
copySource,
|
||||
metadata,
|
||||
options.tier,
|
||||
options
|
||||
);
|
||||
|
||||
const response: Models.BlobCopyFromURLResponse = {
|
||||
statusCode: 202,
|
||||
eTag: res.etag,
|
||||
lastModified: res.lastModified,
|
||||
requestId: context.contextId,
|
||||
version: BLOB_API_VERSION,
|
||||
date: context.startTime,
|
||||
copyId: res.copyId,
|
||||
clientRequestId: options.requestId
|
||||
};
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set blob tier.
|
||||
*
|
||||
|
@ -855,7 +994,7 @@ export default class BlobHandler extends BaseHandler implements IBlobHandler {
|
|||
} else {
|
||||
bodyGetter = async () => {
|
||||
return this.extentStore.readExtents(
|
||||
blocks.map(block => block.persistency),
|
||||
blocks.map((block) => block.persistency),
|
||||
rangeStart,
|
||||
rangeEnd + 1 - rangeStart,
|
||||
context.contextId
|
||||
|
@ -975,7 +1114,7 @@ export default class BlobHandler extends BaseHandler implements IBlobHandler {
|
|||
|
||||
const bodyGetter = async () => {
|
||||
return this.extentStore.readExtents(
|
||||
ranges.map(value => value.persistency),
|
||||
ranges.map((value) => value.persistency),
|
||||
0,
|
||||
contentLength,
|
||||
context.contextId
|
||||
|
|
|
@ -1,9 +1,21 @@
|
|||
#!/usr/bin/env node
|
||||
import * as Logger from "../common/Logger";
|
||||
import { BlobServerFactory } from "./BlobServerFactory";
|
||||
import SqlBlobServer from "./SqlBlobServer";
|
||||
import BlobServer from "./BlobServer";
|
||||
|
||||
// tslint:disable:no-console
|
||||
|
||||
function shutdown(server: BlobServer | SqlBlobServer) {
|
||||
const beforeCloseMessage = `Azurite Blob service is closing...`;
|
||||
const afterCloseMessage = `Azurite Blob service successfully closed`;
|
||||
|
||||
console.log(beforeCloseMessage);
|
||||
server.close().then(() => {
|
||||
console.log(afterCloseMessage);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry for Azurite blob service.
|
||||
*/
|
||||
|
@ -28,26 +40,17 @@ async function main() {
|
|||
);
|
||||
|
||||
// Handle close event
|
||||
const beforeCloseMessage = `Azurite Blob service is closing...`;
|
||||
const afterCloseMessage = `Azurite Blob service successfully closed`;
|
||||
process
|
||||
.once("message", msg => {
|
||||
.once("message", (msg) => {
|
||||
if (msg === "shutdown") {
|
||||
console.log(beforeCloseMessage);
|
||||
server.close().then(() => {
|
||||
console.log(afterCloseMessage);
|
||||
});
|
||||
shutdown(server);
|
||||
}
|
||||
})
|
||||
.once("SIGINT", () => {
|
||||
console.log(beforeCloseMessage);
|
||||
server.close().then(() => {
|
||||
console.log(afterCloseMessage);
|
||||
});
|
||||
});
|
||||
.once("SIGINT", () => shutdown(server))
|
||||
.once("SIGTERM", () => shutdown(server));
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
main().catch((err) => {
|
||||
console.error(`Exit due to unhandled error: ${err.message}`);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
|
@ -821,6 +821,29 @@ export interface IBlobMetadataStore
|
|||
leaseAccessConditions?: Models.BlobStartCopyFromURLOptionalParams
|
||||
): Promise<Models.BlobProperties>;
|
||||
|
||||
/**
|
||||
* Sync copy from Url.
|
||||
*
|
||||
* @param {Context} context
|
||||
* @param {BlobId} source
|
||||
* @param {BlobId} destination
|
||||
* @param {string} copySource
|
||||
* @param {(Models.BlobMetadata | undefined)} metadata
|
||||
* @param {(Models.AccessTier | undefined)} tier
|
||||
* @param {Models.BlobCopyFromURLOptionalParams} [leaseAccessConditions]
|
||||
* @returns {Promise<Models.BlobProperties>}
|
||||
* @memberof IBlobMetadataStore
|
||||
*/
|
||||
copyFromURL(
|
||||
context: Context,
|
||||
source: BlobId,
|
||||
destination: BlobId,
|
||||
copySource: string,
|
||||
metadata: Models.BlobMetadata | undefined,
|
||||
tier: Models.AccessTier | undefined,
|
||||
leaseAccessConditions?: Models.BlobCopyFromURLOptionalParams
|
||||
): Promise<Models.BlobProperties>;
|
||||
|
||||
/**
|
||||
* Update Tier for a blob.
|
||||
*
|
||||
|
|
|
@ -1935,6 +1935,182 @@ export default class LokiBlobMetadataStore
|
|||
return copiedBlob.properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy from Url.
|
||||
*
|
||||
* @param {Context} context
|
||||
* @param {BlobId} source
|
||||
* @param {BlobId} destination
|
||||
* @param {string} copySource
|
||||
* @param {(Models.BlobMetadata | undefined)} metadata
|
||||
* @param {(Models.AccessTier | undefined)} tier
|
||||
* @param {Models.BlobCopyFromURLOptionalParams} [leaseAccessConditions]
|
||||
* @returns {Promise<Models.BlobProperties>}
|
||||
* @memberof LokiBlobMetadataStore
|
||||
*/
|
||||
public async copyFromURL(
|
||||
context: Context,
|
||||
source: BlobId,
|
||||
destination: BlobId,
|
||||
copySource: string,
|
||||
metadata: Models.BlobMetadata | undefined,
|
||||
tier: Models.AccessTier | undefined,
|
||||
options: Models.BlobCopyFromURLOptionalParams = {}
|
||||
): Promise<Models.BlobProperties> {
|
||||
const coll = this.db.getCollection(this.BLOBS_COLLECTION);
|
||||
const sourceBlob = await this.getBlobWithLeaseUpdated(
|
||||
source.account,
|
||||
source.container,
|
||||
source.blob,
|
||||
source.snapshot,
|
||||
context,
|
||||
true,
|
||||
true
|
||||
);
|
||||
|
||||
options.sourceModifiedAccessConditions =
|
||||
options.sourceModifiedAccessConditions || {};
|
||||
validateReadConditions(
|
||||
context,
|
||||
{
|
||||
ifModifiedSince:
|
||||
options.sourceModifiedAccessConditions.sourceIfModifiedSince,
|
||||
ifUnmodifiedSince:
|
||||
options.sourceModifiedAccessConditions.sourceIfUnmodifiedSince,
|
||||
ifMatch: options.sourceModifiedAccessConditions.sourceIfMatches,
|
||||
ifNoneMatch: options.sourceModifiedAccessConditions.sourceIfNoneMatch
|
||||
},
|
||||
sourceBlob
|
||||
);
|
||||
|
||||
const destBlob = await this.getBlobWithLeaseUpdated(
|
||||
destination.account,
|
||||
destination.container,
|
||||
destination.blob,
|
||||
undefined,
|
||||
context,
|
||||
false
|
||||
);
|
||||
|
||||
validateWriteConditions(
|
||||
context,
|
||||
options.modifiedAccessConditions,
|
||||
destBlob
|
||||
);
|
||||
|
||||
if (destBlob) {
|
||||
const lease = new BlobLeaseAdapter(destBlob);
|
||||
new BlobWriteLeaseSyncer(destBlob).sync(lease);
|
||||
new BlobWriteLeaseValidator(options.leaseAccessConditions).validate(
|
||||
lease,
|
||||
context
|
||||
);
|
||||
}
|
||||
|
||||
// If source is uncommitted or deleted
|
||||
if (
|
||||
sourceBlob === undefined ||
|
||||
sourceBlob.deleted ||
|
||||
!sourceBlob.isCommitted
|
||||
) {
|
||||
throw StorageErrorFactory.getBlobNotFound(context.contextId!);
|
||||
}
|
||||
|
||||
if (sourceBlob.properties.accessTier === Models.AccessTier.Archive) {
|
||||
throw StorageErrorFactory.getBlobArchived(context.contextId!);
|
||||
}
|
||||
|
||||
await this.checkContainerExist(
|
||||
context,
|
||||
destination.account,
|
||||
destination.container
|
||||
);
|
||||
|
||||
// Deep clone a copied blob
|
||||
const copiedBlob: BlobModel = {
|
||||
name: destination.blob,
|
||||
deleted: false,
|
||||
snapshot: "",
|
||||
properties: {
|
||||
...sourceBlob.properties,
|
||||
creationTime: context.startTime!,
|
||||
lastModified: context.startTime!,
|
||||
etag: newEtag(),
|
||||
leaseStatus:
|
||||
destBlob !== undefined
|
||||
? destBlob.properties.leaseStatus
|
||||
: Models.LeaseStatusType.Unlocked,
|
||||
leaseState:
|
||||
destBlob !== undefined
|
||||
? destBlob.properties.leaseState
|
||||
: Models.LeaseStateType.Available,
|
||||
leaseDuration:
|
||||
destBlob !== undefined
|
||||
? destBlob.properties.leaseDuration
|
||||
: undefined,
|
||||
copyId: uuid(),
|
||||
copySource,
|
||||
copyProgress: sourceBlob.properties.contentLength
|
||||
? `${sourceBlob.properties.contentLength}/${sourceBlob.properties.contentLength}`
|
||||
: undefined,
|
||||
copyCompletionTime: context.startTime,
|
||||
copyStatusDescription: undefined,
|
||||
incrementalCopy: false,
|
||||
destinationSnapshot: undefined,
|
||||
deletedTime: undefined,
|
||||
remainingRetentionDays: undefined,
|
||||
archiveStatus: undefined,
|
||||
accessTierChangeTime: undefined
|
||||
},
|
||||
metadata:
|
||||
metadata === undefined || Object.keys(metadata).length === 0
|
||||
? { ...sourceBlob.metadata }
|
||||
: metadata,
|
||||
accountName: destination.account,
|
||||
containerName: destination.container,
|
||||
pageRangesInOrder: sourceBlob.pageRangesInOrder,
|
||||
isCommitted: sourceBlob.isCommitted,
|
||||
leaseDurationSeconds:
|
||||
destBlob !== undefined ? destBlob.leaseDurationSeconds : undefined,
|
||||
leaseId: destBlob !== undefined ? destBlob.leaseId : undefined,
|
||||
leaseExpireTime:
|
||||
destBlob !== undefined ? destBlob.leaseExpireTime : undefined,
|
||||
leaseBreakTime:
|
||||
destBlob !== undefined ? destBlob.leaseBreakTime : undefined,
|
||||
committedBlocksInOrder: sourceBlob.committedBlocksInOrder,
|
||||
persistency: sourceBlob.persistency
|
||||
};
|
||||
|
||||
if (
|
||||
copiedBlob.properties.blobType === Models.BlobType.BlockBlob &&
|
||||
tier !== undefined
|
||||
) {
|
||||
copiedBlob.properties.accessTier = this.parseTier(tier);
|
||||
if (copiedBlob.properties.accessTier === undefined) {
|
||||
throw StorageErrorFactory.getInvalidHeaderValue(context.contextId, {
|
||||
HeaderName: "x-ms-access-tier",
|
||||
HeaderValue: `${tier}`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
copiedBlob.properties.blobType === Models.BlobType.PageBlob &&
|
||||
tier !== undefined
|
||||
) {
|
||||
throw StorageErrorFactory.getInvalidHeaderValue(context.contextId, {
|
||||
HeaderName: "x-ms-access-tier",
|
||||
HeaderValue: `${tier}`
|
||||
});
|
||||
}
|
||||
|
||||
if (destBlob) {
|
||||
coll.remove(destBlob);
|
||||
}
|
||||
coll.insert(copiedBlob);
|
||||
return copiedBlob.properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Tier for a blob.
|
||||
*
|
||||
|
|
|
@ -7,9 +7,12 @@ import {
|
|||
Op,
|
||||
Options as SequelizeOptions,
|
||||
Sequelize,
|
||||
TEXT
|
||||
TEXT,
|
||||
Transaction
|
||||
} from "sequelize";
|
||||
|
||||
import uuid from "uuid/v4";
|
||||
|
||||
import {
|
||||
DEFAULT_SQL_CHARSET,
|
||||
DEFAULT_SQL_COLLATE
|
||||
|
@ -383,7 +386,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
context: Context,
|
||||
serviceProperties: ServicePropertiesModel
|
||||
): Promise<ServicePropertiesModel> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
const findResult = await ServicesModel.findByPk(
|
||||
serviceProperties.accountName,
|
||||
{
|
||||
|
@ -568,17 +571,13 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
container: string,
|
||||
leaseAccessConditions?: Models.LeaseAccessConditions
|
||||
): Promise<GetContainerPropertiesResponse> {
|
||||
const findResult = await ContainersModel.findOne({
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
}
|
||||
});
|
||||
|
||||
if (findResult === null || findResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
|
||||
const findResult = await this.assertContainerExists(
|
||||
context,
|
||||
account,
|
||||
container,
|
||||
undefined,
|
||||
true
|
||||
);
|
||||
const containerModel = this.convertDbModelToContainerModel(findResult);
|
||||
|
||||
return LeaseFactory.createLeaseState(
|
||||
|
@ -595,7 +594,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
container: string,
|
||||
options: Models.ContainerDeleteMethodOptionalParams = {}
|
||||
): Promise<void> {
|
||||
await this.sequelize.transaction(async t => {
|
||||
await this.sequelize.transaction(async (t) => {
|
||||
/* Transaction starts */
|
||||
const findResult = await ContainersModel.findOne({
|
||||
attributes: [
|
||||
|
@ -678,7 +677,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
leaseAccessConditions?: Models.LeaseAccessConditions,
|
||||
modifiedAccessConditions?: Models.ModifiedAccessConditions
|
||||
): Promise<void> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
/* Transaction starts */
|
||||
const findResult = await ContainersModel.findOne({
|
||||
attributes: [
|
||||
|
@ -766,7 +765,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
container: string,
|
||||
setAclModel: SetContainerAccessPolicyOptions
|
||||
): Promise<void> {
|
||||
await this.sequelize.transaction(async t => {
|
||||
await this.sequelize.transaction(async (t) => {
|
||||
const findResult = await ContainersModel.findOne({
|
||||
attributes: [
|
||||
"accountName",
|
||||
|
@ -827,7 +826,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
container: string,
|
||||
options: Models.ContainerAcquireLeaseOptionalParams
|
||||
): Promise<AcquireContainerLeaseResponse> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
/* Transaction starts */
|
||||
const findResult = await ContainersModel.findOne({
|
||||
where: {
|
||||
|
@ -881,7 +880,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
leaseId: string,
|
||||
options: Models.ContainerReleaseLeaseOptionalParams = {}
|
||||
): Promise<Models.ContainerProperties> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
/* Transaction starts */
|
||||
const findResult = await ContainersModel.findOne({
|
||||
where: {
|
||||
|
@ -933,7 +932,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
leaseId: string,
|
||||
options: Models.ContainerRenewLeaseOptionalParams = {}
|
||||
): Promise<RenewContainerLeaseResponse> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
/* Transaction starts */
|
||||
// TODO: Filter out unnecessary fields in select query
|
||||
const findResult = await ContainersModel.findOne({
|
||||
|
@ -989,7 +988,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
breakPeriod: number | undefined,
|
||||
options: Models.ContainerBreakLeaseOptionalParams = {}
|
||||
): Promise<BreakContainerLeaseResponse> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
const findResult = await ContainersModel.findOne({
|
||||
where: {
|
||||
accountName: account,
|
||||
|
@ -1053,7 +1052,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
proposedLeaseId: string,
|
||||
options: Models.ContainerChangeLeaseOptionalParams = {}
|
||||
): Promise<ChangeContainerLeaseResponse> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
const findResult = await ContainersModel.findOne({
|
||||
where: {
|
||||
accountName: account,
|
||||
|
@ -1104,15 +1103,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
account: string,
|
||||
container: string
|
||||
): Promise<void> {
|
||||
const res = await ContainersModel.findOne({
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
}
|
||||
});
|
||||
if (res === undefined || res === null) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
await this.assertContainerExists(context, account, container, undefined);
|
||||
}
|
||||
|
||||
public async createBlob(
|
||||
|
@ -1121,18 +1112,13 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
leaseAccessConditions?: Models.LeaseAccessConditions,
|
||||
modifiedAccessConditions?: Models.ModifiedAccessConditions
|
||||
): Promise<void> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
const containerFindResult = await ContainersModel.findOne({
|
||||
where: {
|
||||
accountName: blob.accountName,
|
||||
containerName: blob.containerName
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (containerFindResult === null || containerFindResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(
|
||||
context,
|
||||
blob.accountName,
|
||||
blob.containerName,
|
||||
t
|
||||
);
|
||||
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
|
@ -1196,18 +1182,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
leaseAccessConditions?: Models.LeaseAccessConditions,
|
||||
modifiedAccessConditions?: Models.ModifiedAccessConditions
|
||||
): Promise<BlobModel> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
const containerFindResult = await ContainersModel.findOne({
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (containerFindResult === null || containerFindResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(context, account, container, t);
|
||||
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
|
@ -1257,18 +1233,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
includeSnapshots?: boolean,
|
||||
includeUncommittedBlobs?: boolean
|
||||
): Promise<[BlobModel[], any | undefined]> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
const containerFindResult = await ContainersModel.findOne({
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (containerFindResult === null || containerFindResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(context, account, container, t);
|
||||
|
||||
const whereQuery: any = {
|
||||
accountName: account,
|
||||
|
@ -1375,19 +1341,13 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
block: BlockModel,
|
||||
leaseAccessConditions?: Models.LeaseAccessConditions
|
||||
): Promise<void> {
|
||||
await this.sequelize.transaction(async t => {
|
||||
const containerFindResult = await ContainersModel.findOne({
|
||||
attributes: ["containerName"],
|
||||
where: {
|
||||
accountName: block.accountName,
|
||||
containerName: block.containerName
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (containerFindResult === null || containerFindResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
await this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(
|
||||
context,
|
||||
block.accountName,
|
||||
block.containerName,
|
||||
t
|
||||
);
|
||||
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
|
@ -1468,7 +1428,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
});
|
||||
}
|
||||
|
||||
public async getBlockList(
|
||||
public getBlockList(
|
||||
context: Context,
|
||||
account: string,
|
||||
container: string,
|
||||
|
@ -1476,38 +1436,40 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
isCommitted?: boolean,
|
||||
leaseAccessConditions?: Models.LeaseAccessConditions
|
||||
): Promise<any> {
|
||||
const res: {
|
||||
uncommittedBlocks: Models.Block[];
|
||||
committedBlocks: Models.Block[];
|
||||
} = {
|
||||
uncommittedBlocks: [],
|
||||
committedBlocks: []
|
||||
};
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(context, account, container, t);
|
||||
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container,
|
||||
blobName: blob,
|
||||
snapshot: "",
|
||||
deleting: 0
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (blobFindResult === null || blobFindResult === undefined) {
|
||||
throw StorageErrorFactory.getBlobNotFound(context.contextId);
|
||||
}
|
||||
|
||||
const blobModel = this.convertDbModelToBlobModel(blobFindResult);
|
||||
LeaseFactory.createLeaseState(
|
||||
new BlobLeaseAdapter(blobModel),
|
||||
context
|
||||
).validate(new BlobReadLeaseValidator(leaseAccessConditions));
|
||||
|
||||
const res: {
|
||||
uncommittedBlocks: Models.Block[];
|
||||
committedBlocks: Models.Block[];
|
||||
} = {
|
||||
uncommittedBlocks: [],
|
||||
committedBlocks: []
|
||||
};
|
||||
|
||||
await this.sequelize.transaction(async t => {
|
||||
if (isCommitted !== false) {
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container,
|
||||
blobName: blob,
|
||||
snapshot: "",
|
||||
deleting: 0,
|
||||
isCommitted: true
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (blobFindResult !== null && blobFindResult !== undefined) {
|
||||
const blobModel = this.convertDbModelToBlobModel(blobFindResult);
|
||||
|
||||
LeaseFactory.createLeaseState(
|
||||
new BlobLeaseAdapter(blobModel),
|
||||
context
|
||||
).validate(new BlobReadLeaseValidator(leaseAccessConditions));
|
||||
|
||||
res.committedBlocks = blobModel.committedBlocksInOrder || [];
|
||||
}
|
||||
res.committedBlocks = blobModel.committedBlocksInOrder || [];
|
||||
}
|
||||
|
||||
if (isCommitted !== true) {
|
||||
|
@ -1530,9 +1492,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
res.uncommittedBlocks.push(block);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
});
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public async commitBlockList(
|
||||
|
@ -1542,18 +1503,13 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
leaseAccessConditions?: Models.LeaseAccessConditions,
|
||||
modifiedAccessConditions?: Models.ModifiedAccessConditions
|
||||
): Promise<void> {
|
||||
await this.sequelize.transaction(async t => {
|
||||
const containerFindResult = await ContainersModel.findOne({
|
||||
where: {
|
||||
accountName: blob.accountName,
|
||||
containerName: blob.containerName
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (containerFindResult === null || containerFindResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
await this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(
|
||||
context,
|
||||
blob.accountName,
|
||||
blob.containerName,
|
||||
t
|
||||
);
|
||||
|
||||
const pCommittedBlocksMap: Map<string, PersistencyBlockModel> = new Map(); // persistencyCommittedBlocksMap
|
||||
const pUncommittedBlocksMap: Map<
|
||||
|
@ -1677,7 +1633,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
creationTime,
|
||||
lastModified: blob.properties.lastModified || context.startTime,
|
||||
contentLength: selectedBlockList
|
||||
.map(block => block.size)
|
||||
.map((block) => block.size)
|
||||
.reduce((total, val) => {
|
||||
return total + val;
|
||||
}, 0),
|
||||
|
@ -1724,18 +1680,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
leaseAccessConditions?: Models.LeaseAccessConditions,
|
||||
modifiedAccessConditions?: Models.ModifiedAccessConditions
|
||||
): Promise<GetBlobPropertiesRes> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
const containerFindResult = await ContainersModel.findOne({
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (containerFindResult === null || containerFindResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(context, account, container, t);
|
||||
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
|
@ -1793,19 +1739,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
metadata?: Models.BlobMetadata,
|
||||
modifiedAccessConditions?: Models.ModifiedAccessConditions
|
||||
): Promise<CreateSnapshotResponse> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
const containerFindResult = await ContainersModel.findOne({
|
||||
attributes: ["accountName"], // TODO: Optimize select attributes for all queries
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (containerFindResult === null || containerFindResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(context, account, container, t);
|
||||
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
|
@ -1873,19 +1808,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
blob: string,
|
||||
options: Models.BlobDeleteMethodOptionalParams
|
||||
): Promise<void> {
|
||||
await this.sequelize.transaction(async t => {
|
||||
const containerFindResult = await ContainersModel.findOne({
|
||||
attributes: ["accountName"],
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (containerFindResult === null || containerFindResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
await this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(context, account, container, t);
|
||||
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
|
@ -2059,19 +1983,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
blobHTTPHeaders: Models.BlobHTTPHeaders | undefined,
|
||||
modifiedAccessConditions?: Models.ModifiedAccessConditions
|
||||
): Promise<Models.BlobProperties> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
const containerFindResult = await ContainersModel.findOne({
|
||||
attributes: ["accountName"],
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (containerFindResult === null || containerFindResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(context, account, container, t);
|
||||
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
|
@ -2146,19 +2059,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
metadata: Models.BlobMetadata | undefined,
|
||||
modifiedAccessConditions?: Models.ModifiedAccessConditions
|
||||
): Promise<Models.BlobProperties> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
const containerFindResult = await ContainersModel.findOne({
|
||||
attributes: ["accountName"],
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (containerFindResult === null || containerFindResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(context, account, container, t);
|
||||
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
|
@ -2233,19 +2135,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
proposedLeaseId?: string,
|
||||
options: Models.BlobAcquireLeaseOptionalParams = {}
|
||||
): Promise<AcquireBlobLeaseResponse> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
const containerFindResult = await ContainersModel.findOne({
|
||||
attributes: ["accountName"],
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (containerFindResult === null || containerFindResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(context, account, container, t);
|
||||
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
|
@ -2300,19 +2191,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
leaseId: string,
|
||||
options: Models.BlobReleaseLeaseOptionalParams = {}
|
||||
): Promise<ReleaseBlobLeaseResponse> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
const containerFindResult = await ContainersModel.findOne({
|
||||
attributes: ["accountName"],
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (containerFindResult === null || containerFindResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(context, account, container, t);
|
||||
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
|
@ -2367,19 +2247,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
leaseId: string,
|
||||
options: Models.BlobRenewLeaseOptionalParams = {}
|
||||
): Promise<RenewBlobLeaseResponse> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
const containerFindResult = await ContainersModel.findOne({
|
||||
attributes: ["accountName"],
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (containerFindResult === null || containerFindResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(context, account, container, t);
|
||||
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
|
@ -2435,19 +2304,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
proposedLeaseId: string,
|
||||
options: Models.BlobChangeLeaseOptionalParams = {}
|
||||
): Promise<ChangeBlobLeaseResponse> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
const containerFindResult = await ContainersModel.findOne({
|
||||
attributes: ["accountName"],
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (containerFindResult === null || containerFindResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(context, account, container, t);
|
||||
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
|
@ -2502,19 +2360,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
breakPeriod: number | undefined,
|
||||
options: Models.BlobBreakLeaseOptionalParams = {}
|
||||
): Promise<BreakBlobLeaseResponse> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
const containerFindResult = await ContainersModel.findOne({
|
||||
attributes: ["accountName"],
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (containerFindResult === null || containerFindResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(context, account, container, t);
|
||||
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
|
@ -2577,20 +2424,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
blob: string,
|
||||
snapshot?: string | undefined
|
||||
): Promise<void> {
|
||||
await this.sequelize.transaction(async t => {
|
||||
const containerRes = await ContainersModel.findOne({
|
||||
attributes: ["accountName"],
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
const requestId = context ? context.contextId : undefined;
|
||||
if (containerRes === null || containerRes === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(requestId);
|
||||
}
|
||||
await this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(context, account, container, t);
|
||||
|
||||
const res = await BlobsModel.findOne({
|
||||
where: {
|
||||
|
@ -2604,7 +2439,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
});
|
||||
|
||||
if (res === null || res === undefined) {
|
||||
throw StorageErrorFactory.getBlobNotFound(requestId);
|
||||
throw StorageErrorFactory.getBlobNotFound(context.contextId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -2632,7 +2467,7 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
}
|
||||
|
||||
const blobType = this.getModelValue<Models.BlobType>(res, "blobType", true);
|
||||
const isCommitted = this.getModelValue<boolean>(res, "iscommitted", true);
|
||||
const isCommitted = this.getModelValue<boolean>(res, "isCommitted", true);
|
||||
|
||||
return { blobType, isCommitted };
|
||||
}
|
||||
|
@ -2643,7 +2478,172 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
destination: BlobId,
|
||||
copySource: string,
|
||||
metadata: Models.BlobMetadata | undefined,
|
||||
tier: Models.AccessTier | undefined
|
||||
tier: Models.AccessTier | undefined,
|
||||
options: Models.BlobStartCopyFromURLOptionalParams = {}
|
||||
): Promise<Models.BlobProperties> {
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
const sourceBlob = await this.getBlobWithLeaseUpdated(
|
||||
source.account,
|
||||
source.container,
|
||||
source.blob,
|
||||
source.snapshot,
|
||||
context,
|
||||
true,
|
||||
true,
|
||||
t
|
||||
);
|
||||
|
||||
options.sourceModifiedAccessConditions =
|
||||
options.sourceModifiedAccessConditions || {};
|
||||
validateReadConditions(
|
||||
context,
|
||||
{
|
||||
ifModifiedSince:
|
||||
options.sourceModifiedAccessConditions.sourceIfModifiedSince,
|
||||
ifUnmodifiedSince:
|
||||
options.sourceModifiedAccessConditions.sourceIfUnmodifiedSince,
|
||||
ifMatch: options.sourceModifiedAccessConditions.sourceIfMatches,
|
||||
ifNoneMatch: options.sourceModifiedAccessConditions.sourceIfNoneMatch
|
||||
},
|
||||
sourceBlob
|
||||
);
|
||||
|
||||
const destBlob = await this.getBlobWithLeaseUpdated(
|
||||
destination.account,
|
||||
destination.container,
|
||||
destination.blob,
|
||||
undefined,
|
||||
context,
|
||||
false,
|
||||
undefined,
|
||||
t
|
||||
);
|
||||
|
||||
validateWriteConditions(
|
||||
context,
|
||||
options.modifiedAccessConditions,
|
||||
destBlob
|
||||
);
|
||||
|
||||
if (destBlob) {
|
||||
new BlobWriteLeaseValidator(options.leaseAccessConditions).validate(
|
||||
new BlobLeaseAdapter(destBlob),
|
||||
context
|
||||
);
|
||||
}
|
||||
|
||||
// If source is uncommitted or deleted
|
||||
if (
|
||||
sourceBlob === undefined ||
|
||||
sourceBlob.deleted ||
|
||||
!sourceBlob.isCommitted
|
||||
) {
|
||||
throw StorageErrorFactory.getBlobNotFound(context.contextId!);
|
||||
}
|
||||
|
||||
if (sourceBlob.properties.accessTier === Models.AccessTier.Archive) {
|
||||
throw StorageErrorFactory.getBlobArchived(context.contextId!);
|
||||
}
|
||||
|
||||
await this.assertContainerExists(
|
||||
context,
|
||||
destination.account,
|
||||
destination.container,
|
||||
t
|
||||
);
|
||||
|
||||
// Deep clone a copied blob
|
||||
const copiedBlob: BlobModel = {
|
||||
name: destination.blob,
|
||||
deleted: false,
|
||||
snapshot: "",
|
||||
properties: {
|
||||
...sourceBlob.properties,
|
||||
creationTime: context.startTime!,
|
||||
lastModified: context.startTime!,
|
||||
etag: newEtag(),
|
||||
leaseStatus:
|
||||
destBlob !== undefined
|
||||
? destBlob.properties.leaseStatus
|
||||
: Models.LeaseStatusType.Unlocked,
|
||||
leaseState:
|
||||
destBlob !== undefined
|
||||
? destBlob.properties.leaseState
|
||||
: Models.LeaseStateType.Available,
|
||||
leaseDuration:
|
||||
destBlob !== undefined
|
||||
? destBlob.properties.leaseDuration
|
||||
: undefined,
|
||||
copyId: uuid(),
|
||||
copyStatus: Models.CopyStatusType.Success,
|
||||
copySource,
|
||||
copyProgress: sourceBlob.properties.contentLength
|
||||
? `${sourceBlob.properties.contentLength}/${sourceBlob.properties.contentLength}`
|
||||
: undefined,
|
||||
copyCompletionTime: context.startTime,
|
||||
copyStatusDescription: undefined,
|
||||
incrementalCopy: false,
|
||||
destinationSnapshot: undefined,
|
||||
deletedTime: undefined,
|
||||
remainingRetentionDays: undefined,
|
||||
archiveStatus: undefined,
|
||||
accessTierChangeTime: undefined
|
||||
},
|
||||
metadata:
|
||||
metadata === undefined || Object.keys(metadata).length === 0
|
||||
? { ...sourceBlob.metadata }
|
||||
: metadata,
|
||||
accountName: destination.account,
|
||||
containerName: destination.container,
|
||||
pageRangesInOrder: sourceBlob.pageRangesInOrder,
|
||||
isCommitted: sourceBlob.isCommitted,
|
||||
leaseDurationSeconds:
|
||||
destBlob !== undefined ? destBlob.leaseDurationSeconds : undefined,
|
||||
leaseId: destBlob !== undefined ? destBlob.leaseId : undefined,
|
||||
leaseExpireTime:
|
||||
destBlob !== undefined ? destBlob.leaseExpireTime : undefined,
|
||||
leaseBreakTime:
|
||||
destBlob !== undefined ? destBlob.leaseBreakTime : undefined,
|
||||
committedBlocksInOrder: sourceBlob.committedBlocksInOrder,
|
||||
persistency: sourceBlob.persistency
|
||||
};
|
||||
|
||||
if (
|
||||
copiedBlob.properties.blobType === Models.BlobType.BlockBlob &&
|
||||
tier !== undefined
|
||||
) {
|
||||
copiedBlob.properties.accessTier = this.parseTier(tier);
|
||||
if (copiedBlob.properties.accessTier === undefined) {
|
||||
throw StorageErrorFactory.getInvalidHeaderValue(context.contextId, {
|
||||
HeaderName: "x-ms-access-tier",
|
||||
HeaderValue: `${tier}`
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
copiedBlob.properties.blobType === Models.BlobType.PageBlob &&
|
||||
tier !== undefined
|
||||
) {
|
||||
throw StorageErrorFactory.getInvalidHeaderValue(context.contextId, {
|
||||
HeaderName: "x-ms-access-tier",
|
||||
HeaderValue: `${tier}`
|
||||
});
|
||||
}
|
||||
|
||||
await BlobsModel.upsert(this.convertBlobModelToDbModel(copiedBlob), {
|
||||
transaction: t
|
||||
});
|
||||
return copiedBlob.properties;
|
||||
});
|
||||
}
|
||||
|
||||
public copyFromURL(
|
||||
context: Context,
|
||||
source: BlobId,
|
||||
destination: BlobId,
|
||||
copySource: string,
|
||||
metadata: Models.BlobMetadata | undefined
|
||||
): Promise<Models.BlobProperties> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
@ -2656,19 +2656,8 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
tier: Models.AccessTier,
|
||||
leaseAccessConditions?: Models.LeaseAccessConditions
|
||||
): Promise<200 | 202> {
|
||||
return this.sequelize.transaction(async t => {
|
||||
const containerFindResult = await ContainersModel.findOne({
|
||||
attributes: ["accountName"],
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
},
|
||||
transaction: t
|
||||
});
|
||||
|
||||
if (containerFindResult === null || containerFindResult === undefined) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
return this.sequelize.transaction(async (t) => {
|
||||
await this.assertContainerExists(context, account, container, t);
|
||||
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
|
@ -2840,10 +2829,10 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
},
|
||||
limit: maxResults + 1,
|
||||
order: [["id", "ASC"]]
|
||||
}).then(res => {
|
||||
}).then((res) => {
|
||||
if (res.length < maxResults) {
|
||||
return [
|
||||
res.map(obj => {
|
||||
res.map((obj) => {
|
||||
return this.deserializeModelValue(obj, "persistency", true);
|
||||
}),
|
||||
undefined
|
||||
|
@ -2856,7 +2845,9 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
true
|
||||
);
|
||||
return [
|
||||
res.map(obj => this.deserializeModelValue(obj, "persistency", true)),
|
||||
res.map((obj) =>
|
||||
this.deserializeModelValue(obj, "persistency", true)
|
||||
),
|
||||
nextMarker
|
||||
];
|
||||
}
|
||||
|
@ -2867,6 +2858,27 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
return new BlobReferredExtentsAsyncIterator(this);
|
||||
}
|
||||
|
||||
private async assertContainerExists(
|
||||
context: Context,
|
||||
account: string,
|
||||
container: string,
|
||||
transaction?: Transaction,
|
||||
fullResult: boolean = false
|
||||
): Promise<ContainersModel> {
|
||||
const findResult = await ContainersModel.findOne({
|
||||
attributes: fullResult ? undefined : ["accountName"],
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container
|
||||
},
|
||||
transaction
|
||||
});
|
||||
if (findResult === undefined || findResult === null) {
|
||||
throw StorageErrorFactory.getContainerNotFound(context.contextId);
|
||||
}
|
||||
return findResult;
|
||||
}
|
||||
|
||||
private getModelValue<T>(model: Model, key: string): T | undefined;
|
||||
private getModelValue<T>(model: Model, key: string, isRequired: true): T;
|
||||
private getModelValue<T>(
|
||||
|
@ -3199,4 +3211,106 @@ export default class SqlBlobMetadataStore implements IBlobMetadataStore {
|
|||
}
|
||||
return { lease: leaseString };
|
||||
}
|
||||
|
||||
private async getBlobWithLeaseUpdated(
|
||||
account: string,
|
||||
container: string,
|
||||
blob: string,
|
||||
snapshot: string = "",
|
||||
context: Context,
|
||||
forceExist?: boolean,
|
||||
forceCommitted?: boolean,
|
||||
transaction?: Transaction
|
||||
): Promise<BlobModel | undefined> {
|
||||
await this.checkContainerExist(context, account, container);
|
||||
|
||||
const blobFindResult = await BlobsModel.findOne({
|
||||
where: {
|
||||
accountName: account,
|
||||
containerName: container,
|
||||
blobName: blob,
|
||||
snapshot
|
||||
},
|
||||
transaction
|
||||
});
|
||||
|
||||
if (blobFindResult === null || blobFindResult === undefined) {
|
||||
if (forceExist === false) {
|
||||
return undefined;
|
||||
} else {
|
||||
throw StorageErrorFactory.getBlobNotFound(context.contextId);
|
||||
}
|
||||
}
|
||||
|
||||
// Force exist if parameter forceExist is undefined or true
|
||||
const doc = this.convertDbModelToBlobModel(blobFindResult);
|
||||
if (forceExist === undefined || forceExist === true) {
|
||||
if (forceCommitted) {
|
||||
if (!doc || !(doc as BlobModel).isCommitted) {
|
||||
throw StorageErrorFactory.getBlobNotFound(context.contextId);
|
||||
}
|
||||
} else {
|
||||
if (!doc) {
|
||||
throw StorageErrorFactory.getBlobNotFound(context.contextId);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (forceCommitted) {
|
||||
if (!doc || !(doc as BlobModel).isCommitted) {
|
||||
return undefined;
|
||||
}
|
||||
} else {
|
||||
if (!doc) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (doc.properties) {
|
||||
doc.properties.contentMD5 = this.restoreUint8Array(
|
||||
doc.properties.contentMD5
|
||||
);
|
||||
}
|
||||
|
||||
// Snapshot doesn't have lease
|
||||
if (snapshot !== undefined && snapshot !== "") {
|
||||
new BlobLeaseSyncer(doc).sync({
|
||||
leaseId: undefined,
|
||||
leaseExpireTime: undefined,
|
||||
leaseDurationSeconds: undefined,
|
||||
leaseBreakTime: undefined,
|
||||
leaseDurationType: undefined,
|
||||
leaseState: Models.LeaseStateType.Available, // TODO: Lease state & status should be undefined for snapshots
|
||||
leaseStatus: Models.LeaseStatusType.Unlocked // TODO: Lease state & status should be undefined for snapshots
|
||||
});
|
||||
} else {
|
||||
LeaseFactory.createLeaseState(new BlobLeaseAdapter(doc), context).sync(
|
||||
new BlobLeaseSyncer(doc)
|
||||
);
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the tier setting from request headers.
|
||||
*
|
||||
* @private
|
||||
* @param {string} tier
|
||||
* @returns {(Models.AccessTier | undefined)}
|
||||
* @memberof BlobHandler
|
||||
*/
|
||||
private parseTier(tier: string): Models.AccessTier | undefined {
|
||||
tier = tier.toLowerCase();
|
||||
if (tier === Models.AccessTier.Hot.toLowerCase()) {
|
||||
return Models.AccessTier.Hot;
|
||||
}
|
||||
if (tier === Models.AccessTier.Cool.toLowerCase()) {
|
||||
return Models.AccessTier.Cool;
|
||||
}
|
||||
if (tier === Models.AccessTier.Archive.toLowerCase()) {
|
||||
return Models.AccessTier.Archive;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { StoreDestinationArray } from "../../common/persistence/IExtentStore";
|
||||
import * as Models from "../generated/artifacts/models";
|
||||
|
||||
export const VERSION = "3.8.0";
|
||||
export const BLOB_API_VERSION = "2019-12-12";
|
||||
export const VERSION = "3.9.0";
|
||||
export const BLOB_API_VERSION = "2020-02-10";
|
||||
export const DEFAULT_BLOB_SERVER_HOST_NAME = "127.0.0.1"; // Change to 0.0.0.0 when needs external access
|
||||
export const DEFAULT_LIST_BLOBS_MAX_RESULTS = 5000;
|
||||
export const DEFAULT_LIST_CONTAINERS_MAX_RESULTS = 5000;
|
||||
|
@ -20,6 +20,13 @@ export const DEFAULT_CONTEXT_PATH = "azurite_blob_context";
|
|||
export const LOGGER_CONFIGS = {};
|
||||
export const DEFAULT_GC_INTERVAL_MS = 10 * 60 * 1000;
|
||||
export const DEFAULT_WRITE_CONCURRENCY_PER_LOCATION = 50;
|
||||
export const EMULATOR_ACCOUNT_NAME = "devstoreaccount1";
|
||||
export const EMULATOR_ACCOUNT_KEY_STR =
|
||||
"Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
|
||||
export const EMULATOR_ACCOUNT_KEY = Buffer.from(
|
||||
EMULATOR_ACCOUNT_KEY_STR,
|
||||
"base64"
|
||||
);
|
||||
|
||||
export const EMULATOR_ACCOUNT_SKUNAME = Models.SkuName.StandardRAGRS;
|
||||
export const EMULATOR_ACCOUNT_KIND = Models.AccountKind.StorageV2;
|
||||
|
@ -89,6 +96,7 @@ export const DEFAULT_BLOB_PERSISTENCE_ARRAY: StoreDestinationArray = [
|
|||
];
|
||||
|
||||
export const ValidAPIVersions = [
|
||||
"2020-02-10",
|
||||
"2019-12-12",
|
||||
"2019-07-07",
|
||||
"2019-02-02",
|
||||
|
|
|
@ -30,7 +30,7 @@ export function convertRawHeadersToMetadata(
|
|||
for (let i = 0; i < rawHeaders.length; i = i + 2) {
|
||||
const header = rawHeaders[i];
|
||||
if (
|
||||
header.startsWith(metadataPrefix) &&
|
||||
header.toLowerCase().startsWith(metadataPrefix) &&
|
||||
header.length > metadataPrefix.length
|
||||
) {
|
||||
const key = header.substr(metadataPrefix.length);
|
||||
|
@ -131,9 +131,7 @@ export function getURLQueries(url: string): { [key: string]: string } {
|
|||
}
|
||||
|
||||
export async function getMD5FromString(text: string): Promise<Uint8Array> {
|
||||
return createHash("md5")
|
||||
.update(text)
|
||||
.digest();
|
||||
return createHash("md5").update(text).digest();
|
||||
}
|
||||
|
||||
export async function getMD5FromStream(
|
||||
|
@ -142,13 +140,13 @@ export async function getMD5FromStream(
|
|||
const hash = createHash("md5");
|
||||
return new Promise<Uint8Array>((resolve, reject) => {
|
||||
stream
|
||||
.on("data", data => {
|
||||
.on("data", (data) => {
|
||||
hash.update(data);
|
||||
})
|
||||
.on("end", () => {
|
||||
resolve(hash.digest());
|
||||
})
|
||||
.on("error", err => {
|
||||
.on("error", (err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { IIPRange } from "@azure/storage-blob";
|
||||
import { SasIPRange } from "@azure/storage-blob";
|
||||
|
||||
import {
|
||||
computeHMACSHA256,
|
||||
|
@ -84,10 +84,10 @@ export interface IAccountSASSignatureValues {
|
|||
/**
|
||||
* Optional. IP range allowed.
|
||||
*
|
||||
* @type {IIPRange | string}
|
||||
* @type {SasIPRange | string}
|
||||
* @memberof IAccountSASSignatureValues
|
||||
*/
|
||||
ipRange?: IIPRange | string;
|
||||
ipRange?: SasIPRange | string;
|
||||
|
||||
/**
|
||||
* The values that indicate the services accessible with this SAS. Please refer to {@link AccountSASServices} to
|
||||
|
|
|
@ -18,6 +18,16 @@ import {
|
|||
|
||||
const accessAsync = promisify(access);
|
||||
|
||||
function shutdown(server: QueueServer) {
|
||||
const beforeCloseMessage = `Azurite Queue service is closing...`;
|
||||
const afterCloseMessage = `Azurite Queue service successfully closed`;
|
||||
|
||||
console.log(beforeCloseMessage);
|
||||
server.close().then(() => {
|
||||
console.log(afterCloseMessage);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Entry for Azurite queue service.
|
||||
*/
|
||||
|
@ -76,26 +86,17 @@ async function main() {
|
|||
);
|
||||
|
||||
// Handle close event
|
||||
const beforeCloseMessage = `Azurite Queue service is closing...`;
|
||||
const afterCloseMessage = `Azurite Queue service successfully closed`;
|
||||
process
|
||||
.once("message", msg => {
|
||||
.once("message", (msg: string) => {
|
||||
if (msg === "shutdown") {
|
||||
console.log(beforeCloseMessage);
|
||||
server.close().then(() => {
|
||||
console.log(afterCloseMessage);
|
||||
});
|
||||
shutdown(server);
|
||||
}
|
||||
})
|
||||
.once("SIGINT", () => {
|
||||
console.log(beforeCloseMessage);
|
||||
server.close().then(() => {
|
||||
console.log(afterCloseMessage);
|
||||
});
|
||||
});
|
||||
.once("SIGINT", () => shutdown(server))
|
||||
.once("SIGTERM", () => shutdown(server));
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
main().catch((err) => {
|
||||
console.error(`Exit due to unhandled error: ${err.message}`);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { StoreDestinationArray } from "../../common/persistence/IExtentStore";
|
||||
|
||||
export const VERSION = "3.8.0";
|
||||
export const QUEUE_API_VERSION = "2019-12-12";
|
||||
export const VERSION = "3.9.0";
|
||||
export const QUEUE_API_VERSION = "2020-02-10";
|
||||
export const DEFAULT_QUEUE_SERVER_HOST_NAME = "127.0.0.1"; // Change to 0.0.0.0 when needs external access
|
||||
export const DEFAULT_QUEUE_LISTENING_PORT = 10001;
|
||||
export const IS_PRODUCTION = process.env.NODE_ENV === "production";
|
||||
|
@ -90,6 +90,7 @@ export const DEFAULT_QUEUE_PERSISTENCE_ARRAY: StoreDestinationArray = [
|
|||
];
|
||||
|
||||
export const ValidAPIVersions = [
|
||||
"2020-02-10",
|
||||
"2019-12-12",
|
||||
"2019-07-07",
|
||||
"2019-02-02",
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
import {
|
||||
Aborter,
|
||||
AppendBlobURL,
|
||||
BlobURL,
|
||||
ContainerURL,
|
||||
PageBlobURL,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL
|
||||
StorageSharedKeyCredential,
|
||||
BlobServiceClient,
|
||||
newPipeline
|
||||
} from "@azure/storage-blob";
|
||||
import assert = require("assert");
|
||||
|
||||
|
@ -30,21 +25,26 @@ describe("AppendBlobAPIs", () => {
|
|||
const server = factory.createServer();
|
||||
|
||||
const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`;
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
let containerName: string = getUniqueName("container");
|
||||
let containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
let containerClient = serviceClient.getContainerClient(containerName);
|
||||
let blobName: string = getUniqueName("blob");
|
||||
let blobURL = BlobURL.fromContainerURL(containerURL, blobName);
|
||||
let appendBlobURL = AppendBlobURL.fromBlobURL(blobURL);
|
||||
let blobClient = containerClient.getBlobClient(blobName);
|
||||
let appendBlobClient = blobClient.getAppendBlobClient();
|
||||
|
||||
before(async () => {
|
||||
await server.start();
|
||||
|
@ -57,20 +57,20 @@ describe("AppendBlobAPIs", () => {
|
|||
|
||||
beforeEach(async () => {
|
||||
containerName = getUniqueName("container");
|
||||
containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
await containerURL.create(Aborter.none);
|
||||
containerClient = serviceClient.getContainerClient(containerName);
|
||||
await containerClient.create();
|
||||
blobName = getUniqueName("blob");
|
||||
blobURL = BlobURL.fromContainerURL(containerURL, blobName);
|
||||
appendBlobURL = AppendBlobURL.fromBlobURL(blobURL);
|
||||
blobClient = containerClient.getBlobClient(blobName);
|
||||
appendBlobClient = blobClient.getAppendBlobClient();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.delete();
|
||||
});
|
||||
|
||||
it("Create append blob should work @loki", async () => {
|
||||
await appendBlobURL.create(Aborter.none);
|
||||
const properties = await appendBlobURL.getProperties(Aborter.none);
|
||||
await appendBlobClient.create();
|
||||
const properties = await appendBlobClient.getProperties();
|
||||
assert.deepStrictEqual(properties.blobType, "AppendBlob");
|
||||
assert.deepStrictEqual(properties.leaseState, "available");
|
||||
assert.deepStrictEqual(properties.leaseStatus, "unlocked");
|
||||
|
@ -86,8 +86,8 @@ describe("AppendBlobAPIs", () => {
|
|||
});
|
||||
|
||||
it("Create append blob override existing pageblob @loki", async () => {
|
||||
const pageBlobUrl = PageBlobURL.fromBlobURL(blobURL);
|
||||
await pageBlobUrl.create(Aborter.none, 512);
|
||||
const pageBlobClient = blobClient.getPageBlobClient();
|
||||
await pageBlobClient.create(512);
|
||||
|
||||
const md5 = new Uint8Array([1, 2, 3, 4, 5]);
|
||||
const headers = {
|
||||
|
@ -104,11 +104,11 @@ describe("AppendBlobAPIs", () => {
|
|||
key2: "val2"
|
||||
};
|
||||
|
||||
await appendBlobURL.create(Aborter.none, {
|
||||
await appendBlobClient.create({
|
||||
blobHTTPHeaders: headers,
|
||||
metadata
|
||||
});
|
||||
const properties = await appendBlobURL.getProperties(Aborter.none);
|
||||
const properties = await appendBlobClient.getProperties();
|
||||
assert.deepStrictEqual(properties.blobType, "AppendBlob");
|
||||
assert.deepStrictEqual(properties.leaseState, "available");
|
||||
assert.deepStrictEqual(properties.leaseStatus, "unlocked");
|
||||
|
@ -134,20 +134,20 @@ describe("AppendBlobAPIs", () => {
|
|||
});
|
||||
|
||||
it("Delete append blob should work @loki", async () => {
|
||||
await appendBlobURL.create(Aborter.none);
|
||||
await appendBlobURL.delete(Aborter.none);
|
||||
await appendBlobClient.create();
|
||||
await appendBlobClient.delete();
|
||||
});
|
||||
|
||||
it("Create append blob snapshot should work @loki", async () => {
|
||||
await appendBlobURL.create(Aborter.none);
|
||||
const response = await appendBlobURL.createSnapshot(Aborter.none);
|
||||
const appendBlobSnapshotURL = appendBlobURL.withSnapshot(
|
||||
await appendBlobClient.create();
|
||||
const response = await appendBlobClient.createSnapshot();
|
||||
const appendBlobSnapshotClient = appendBlobClient.withSnapshot(
|
||||
response.snapshot!
|
||||
);
|
||||
|
||||
await appendBlobURL.appendBlock(Aborter.none, "hello", 5);
|
||||
await appendBlobClient.appendBlock("hello", 5);
|
||||
|
||||
let properties = await appendBlobURL.getProperties(Aborter.none);
|
||||
let properties = await appendBlobClient.getProperties();
|
||||
assert.deepStrictEqual(properties.blobType, "AppendBlob");
|
||||
assert.deepStrictEqual(properties.leaseState, "available");
|
||||
assert.deepStrictEqual(properties.leaseStatus, "unlocked");
|
||||
|
@ -161,7 +161,7 @@ describe("AppendBlobAPIs", () => {
|
|||
assert.deepStrictEqual(properties.blobSequenceNumber, undefined);
|
||||
assert.deepStrictEqual(properties.blobCommittedBlockCount, 1);
|
||||
|
||||
properties = await appendBlobSnapshotURL.getProperties(Aborter.none);
|
||||
properties = await appendBlobSnapshotClient.getProperties();
|
||||
assert.deepStrictEqual(properties.blobType, "AppendBlob");
|
||||
assert.deepStrictEqual(properties.leaseState, "available");
|
||||
assert.deepStrictEqual(properties.leaseStatus, "unlocked");
|
||||
|
@ -177,60 +177,91 @@ describe("AppendBlobAPIs", () => {
|
|||
});
|
||||
|
||||
it("Copy append blob snapshot should work @loki", async () => {
|
||||
await appendBlobURL.create(Aborter.none);
|
||||
await appendBlobURL.appendBlock(Aborter.none, "hello", 5);
|
||||
await appendBlobClient.create();
|
||||
await appendBlobClient.appendBlock("hello", 5);
|
||||
|
||||
const response = await appendBlobURL.createSnapshot(Aborter.none);
|
||||
const appendBlobSnapshotURL = appendBlobURL.withSnapshot(
|
||||
const response = await appendBlobClient.createSnapshot();
|
||||
const appendBlobSnapshotClient = appendBlobClient.withSnapshot(
|
||||
response.snapshot!
|
||||
);
|
||||
|
||||
await appendBlobURL.appendBlock(Aborter.none, "world", 5);
|
||||
await appendBlobClient.appendBlock("world", 5);
|
||||
|
||||
const destAppendBlobURL = AppendBlobURL.fromContainerURL(
|
||||
containerURL,
|
||||
const destAppendBlobClient = containerClient.getAppendBlobClient(
|
||||
"copiedAppendBlob"
|
||||
);
|
||||
await destAppendBlobURL.startCopyFromURL(
|
||||
Aborter.none,
|
||||
appendBlobSnapshotURL.url
|
||||
);
|
||||
await destAppendBlobClient.beginCopyFromURL(appendBlobSnapshotClient.url);
|
||||
|
||||
let properties = await appendBlobURL.getProperties(Aborter.none);
|
||||
let properties = await appendBlobClient.getProperties();
|
||||
assert.deepStrictEqual(properties.contentLength, 10);
|
||||
assert.deepStrictEqual(properties.blobCommittedBlockCount, 2);
|
||||
|
||||
properties = await appendBlobSnapshotURL.getProperties(Aborter.none);
|
||||
properties = await appendBlobSnapshotClient.getProperties();
|
||||
assert.deepStrictEqual(properties.contentLength, 5);
|
||||
assert.deepStrictEqual(properties.blobCommittedBlockCount, 1);
|
||||
|
||||
await appendBlobURL.delete(Aborter.none, { deleteSnapshots: "include" });
|
||||
await appendBlobClient.delete({ deleteSnapshots: "include" });
|
||||
|
||||
properties = await destAppendBlobURL.getProperties(Aborter.none);
|
||||
properties = await destAppendBlobClient.getProperties();
|
||||
assert.deepStrictEqual(properties.contentLength, 5);
|
||||
assert.deepStrictEqual(properties.blobCommittedBlockCount, 1);
|
||||
assert.ok(properties.copyId);
|
||||
assert.ok(properties.copyCompletionTime);
|
||||
assert.ok(properties.copyCompletedOn);
|
||||
assert.deepStrictEqual(properties.copyProgress, "5/5");
|
||||
assert.deepStrictEqual(properties.copySource, appendBlobSnapshotURL.url);
|
||||
assert.deepStrictEqual(properties.copySource, appendBlobSnapshotClient.url);
|
||||
assert.deepStrictEqual(properties.copyStatus, "success");
|
||||
});
|
||||
|
||||
it("Synchronized copy append blob snapshot should work @loki", async () => {
|
||||
await appendBlobClient.create();
|
||||
await appendBlobClient.appendBlock("hello", 5);
|
||||
|
||||
const response = await appendBlobClient.createSnapshot();
|
||||
const appendBlobSnapshotClient = appendBlobClient.withSnapshot(
|
||||
response.snapshot!
|
||||
);
|
||||
|
||||
await appendBlobClient.appendBlock("world", 5);
|
||||
|
||||
const destAppendBlobClient = containerClient.getAppendBlobClient(
|
||||
"copiedAppendBlob"
|
||||
);
|
||||
await destAppendBlobClient.syncCopyFromURL(appendBlobSnapshotClient.url);
|
||||
|
||||
let properties = await appendBlobClient.getProperties();
|
||||
assert.deepStrictEqual(properties.contentLength, 10);
|
||||
assert.deepStrictEqual(properties.blobCommittedBlockCount, 2);
|
||||
|
||||
properties = await appendBlobSnapshotClient.getProperties();
|
||||
assert.deepStrictEqual(properties.contentLength, 5);
|
||||
assert.deepStrictEqual(properties.blobCommittedBlockCount, 1);
|
||||
|
||||
await appendBlobClient.delete({ deleteSnapshots: "include" });
|
||||
|
||||
properties = await destAppendBlobClient.getProperties();
|
||||
assert.deepStrictEqual(properties.contentLength, 5);
|
||||
assert.deepStrictEqual(properties.blobCommittedBlockCount, 1);
|
||||
assert.ok(properties.copyId);
|
||||
assert.ok(properties.copyCompletedOn);
|
||||
assert.deepStrictEqual(properties.copyProgress, "5/5");
|
||||
assert.deepStrictEqual(properties.copySource, appendBlobSnapshotClient.url);
|
||||
});
|
||||
|
||||
it("Set append blob metadata should work @loki", async () => {
|
||||
await appendBlobURL.create(Aborter.none);
|
||||
await appendBlobClient.create();
|
||||
|
||||
const metadata = {
|
||||
key1: "value1",
|
||||
key2: "val2"
|
||||
};
|
||||
await appendBlobURL.setMetadata(Aborter.none, metadata);
|
||||
await appendBlobClient.setMetadata(metadata);
|
||||
|
||||
const properties = await appendBlobURL.getProperties(Aborter.none);
|
||||
const properties = await appendBlobClient.getProperties();
|
||||
assert.deepStrictEqual(properties.metadata, metadata);
|
||||
});
|
||||
|
||||
it("Set append blob HTTP headers should work @loki", async () => {
|
||||
await appendBlobURL.create(Aborter.none);
|
||||
await appendBlobClient.create();
|
||||
|
||||
const md5 = new Uint8Array([1, 2, 3, 4, 5]);
|
||||
const headers = {
|
||||
|
@ -241,9 +272,9 @@ describe("AppendBlobAPIs", () => {
|
|||
blobContentLanguage: "blobContentLanguage_",
|
||||
blobContentDisposition: "blobContentDisposition_"
|
||||
};
|
||||
await appendBlobURL.setHTTPHeaders(Aborter.none, headers);
|
||||
await appendBlobClient.setHTTPHeaders(headers);
|
||||
|
||||
const properties = await appendBlobURL.getProperties(Aborter.none);
|
||||
const properties = await appendBlobClient.getProperties();
|
||||
assert.deepStrictEqual(properties.cacheControl, headers.blobCacheControl);
|
||||
assert.deepStrictEqual(properties.contentType, headers.blobContentType);
|
||||
assert.deepEqual(properties.contentMD5, headers.blobContentMD5);
|
||||
|
@ -261,10 +292,10 @@ describe("AppendBlobAPIs", () => {
|
|||
);
|
||||
});
|
||||
|
||||
it("Set tier should not work for append blob @loki", async function() {
|
||||
await appendBlobURL.create(Aborter.none);
|
||||
it("Set tier should not work for append blob @loki", async function () {
|
||||
await appendBlobClient.create();
|
||||
try {
|
||||
await blobURL.setTier(Aborter.none, "hot");
|
||||
await blobClient.setAccessTier("hot");
|
||||
} catch (err) {
|
||||
return;
|
||||
}
|
||||
|
@ -272,15 +303,11 @@ describe("AppendBlobAPIs", () => {
|
|||
});
|
||||
|
||||
it("Append block should work @loki", async () => {
|
||||
await appendBlobURL.create(Aborter.none);
|
||||
let appendBlockResponse = await appendBlobURL.appendBlock(
|
||||
Aborter.none,
|
||||
"abcdef",
|
||||
6
|
||||
);
|
||||
await appendBlobClient.create();
|
||||
let appendBlockResponse = await appendBlobClient.appendBlock("abcdef", 6);
|
||||
assert.deepStrictEqual(appendBlockResponse.blobAppendOffset, "0");
|
||||
|
||||
const properties1 = await appendBlobURL.getProperties(Aborter.none);
|
||||
const properties1 = await appendBlobClient.getProperties();
|
||||
assert.deepStrictEqual(properties1.blobType, "AppendBlob");
|
||||
assert.deepStrictEqual(properties1.leaseState, "available");
|
||||
assert.deepStrictEqual(properties1.leaseStatus, "unlocked");
|
||||
|
@ -293,22 +320,18 @@ describe("AppendBlobAPIs", () => {
|
|||
assert.deepStrictEqual(properties1.cacheControl, undefined);
|
||||
assert.deepStrictEqual(properties1.blobSequenceNumber, undefined);
|
||||
assert.deepStrictEqual(properties1.blobCommittedBlockCount, 1);
|
||||
assert.deepStrictEqual(properties1.eTag, appendBlockResponse.eTag);
|
||||
assert.deepStrictEqual(properties1.etag, appendBlockResponse.etag);
|
||||
|
||||
await sleep(1000); // Sleep 1 second to make sure last modified time changed
|
||||
appendBlockResponse = await appendBlobURL.appendBlock(
|
||||
Aborter.none,
|
||||
"123456",
|
||||
6
|
||||
);
|
||||
appendBlockResponse = await appendBlobClient.appendBlock("123456", 6);
|
||||
assert.deepStrictEqual(appendBlockResponse.blobAppendOffset, "6");
|
||||
assert.notDeepStrictEqual(appendBlockResponse.eTag, properties1.eTag);
|
||||
appendBlockResponse = await appendBlobURL.appendBlock(Aborter.none, "T", 1);
|
||||
assert.notDeepStrictEqual(appendBlockResponse.etag, properties1.etag);
|
||||
appendBlockResponse = await appendBlobClient.appendBlock("T", 1);
|
||||
assert.deepStrictEqual(appendBlockResponse.blobAppendOffset, "12");
|
||||
appendBlockResponse = await appendBlobURL.appendBlock(Aborter.none, "@", 2);
|
||||
appendBlockResponse = await appendBlobClient.appendBlock("@", 2);
|
||||
assert.deepStrictEqual(appendBlockResponse.blobAppendOffset, "13");
|
||||
|
||||
const properties2 = await appendBlobURL.getProperties(Aborter.none);
|
||||
const properties2 = await appendBlobClient.getProperties();
|
||||
assert.deepStrictEqual(properties2.blobType, "AppendBlob");
|
||||
assert.deepStrictEqual(properties2.leaseState, "available");
|
||||
assert.deepStrictEqual(properties2.leaseStatus, "unlocked");
|
||||
|
@ -321,28 +344,28 @@ describe("AppendBlobAPIs", () => {
|
|||
assert.deepStrictEqual(properties2.cacheControl, undefined);
|
||||
assert.deepStrictEqual(properties2.blobSequenceNumber, undefined);
|
||||
assert.deepStrictEqual(properties2.blobCommittedBlockCount, 4);
|
||||
assert.deepStrictEqual(properties1.creationTime, properties2.creationTime);
|
||||
assert.deepStrictEqual(properties1.createdOn, properties2.createdOn);
|
||||
assert.notDeepStrictEqual(
|
||||
properties1.lastModified,
|
||||
properties2.lastModified
|
||||
);
|
||||
assert.notDeepStrictEqual(properties1.eTag, properties2.eTag);
|
||||
assert.notDeepStrictEqual(properties1.etag, properties2.etag);
|
||||
|
||||
const response = await appendBlobURL.download(Aborter.none, 0);
|
||||
const string = await bodyToString(response);
|
||||
const response = await appendBlobClient.download(0);
|
||||
const string = await bodyToString(response, response.contentLength);
|
||||
|
||||
assert.deepStrictEqual(string, "abcdef123456T@");
|
||||
});
|
||||
|
||||
it("Download append blob should work @loki", async () => {
|
||||
await appendBlobURL.create(Aborter.none);
|
||||
await appendBlobURL.appendBlock(Aborter.none, "abcdef", 6);
|
||||
await appendBlobURL.appendBlock(Aborter.none, "123456", 6);
|
||||
await appendBlobURL.appendBlock(Aborter.none, "T", 1);
|
||||
await appendBlobURL.appendBlock(Aborter.none, "@", 2);
|
||||
await appendBlobClient.create();
|
||||
await appendBlobClient.appendBlock("abcdef", 6);
|
||||
await appendBlobClient.appendBlock("123456", 6);
|
||||
await appendBlobClient.appendBlock("T", 1);
|
||||
await appendBlobClient.appendBlock("@", 2);
|
||||
|
||||
const response = await appendBlobURL.download(Aborter.none, 5, 8);
|
||||
const string = await bodyToString(response);
|
||||
const response = await appendBlobClient.download(5, 8);
|
||||
const string = await bodyToString(response, response.contentLength);
|
||||
assert.deepStrictEqual(string, "f123456T");
|
||||
assert.deepStrictEqual(response.blobCommittedBlockCount, 4);
|
||||
assert.deepStrictEqual(response.blobType, BlobType.AppendBlob);
|
||||
|
@ -352,48 +375,47 @@ describe("AppendBlobAPIs", () => {
|
|||
});
|
||||
|
||||
it("Download append blob should work for snapshot @loki", async () => {
|
||||
await appendBlobURL.create(Aborter.none);
|
||||
await appendBlobURL.appendBlock(Aborter.none, "abcdef", 6);
|
||||
await appendBlobClient.create();
|
||||
await appendBlobClient.appendBlock("abcdef", 6);
|
||||
|
||||
const snapshotResponse = await appendBlobURL.createSnapshot(Aborter.none);
|
||||
const snapshotAppendBlobURL = appendBlobURL.withSnapshot(
|
||||
const snapshotResponse = await appendBlobClient.createSnapshot();
|
||||
const snapshotAppendBlobURL = appendBlobClient.withSnapshot(
|
||||
snapshotResponse.snapshot!
|
||||
);
|
||||
|
||||
await appendBlobURL.appendBlock(Aborter.none, "123456", 6);
|
||||
await appendBlobURL.appendBlock(Aborter.none, "T", 1);
|
||||
await appendBlobURL.appendBlock(Aborter.none, "@", 2);
|
||||
await appendBlobClient.appendBlock("123456", 6);
|
||||
await appendBlobClient.appendBlock("T", 1);
|
||||
await appendBlobClient.appendBlock("@", 2);
|
||||
|
||||
const response = await snapshotAppendBlobURL.download(Aborter.none, 3);
|
||||
const response = await snapshotAppendBlobURL.download(3);
|
||||
const string = await bodyToString(response);
|
||||
assert.deepStrictEqual(string, "def");
|
||||
assert.deepEqual(response.contentMD5, await getMD5FromString("def"));
|
||||
});
|
||||
|
||||
it("Download append blob should work for copied blob @loki", async () => {
|
||||
await appendBlobURL.create(Aborter.none);
|
||||
await appendBlobURL.appendBlock(Aborter.none, "abcdef", 6);
|
||||
await appendBlobClient.create();
|
||||
await appendBlobClient.appendBlock("abcdef", 6);
|
||||
|
||||
const copiedAppendBlobURL = AppendBlobURL.fromContainerURL(
|
||||
containerURL,
|
||||
const copiedAppendBlobClient = containerClient.getAppendBlobClient(
|
||||
"copiedAppendBlob"
|
||||
);
|
||||
await copiedAppendBlobURL.startCopyFromURL(Aborter.none, appendBlobURL.url);
|
||||
await copiedAppendBlobClient.beginCopyFromURL(appendBlobClient.url);
|
||||
|
||||
await appendBlobURL.delete(Aborter.none);
|
||||
await appendBlobClient.delete();
|
||||
|
||||
const response = await copiedAppendBlobURL.download(Aborter.none, 3);
|
||||
const response = await copiedAppendBlobClient.download(3);
|
||||
const string = await bodyToString(response);
|
||||
assert.deepStrictEqual(string, "def");
|
||||
assert.deepEqual(response.contentMD5, await getMD5FromString("def"));
|
||||
});
|
||||
|
||||
it("Append block with invalid blob type should not work @loki", async () => {
|
||||
const pageBlobUrl = PageBlobURL.fromBlobURL(appendBlobURL);
|
||||
await pageBlobUrl.create(Aborter.none, 512);
|
||||
const pageBlobClient = appendBlobClient.getPageBlobClient();
|
||||
await pageBlobClient.create(512);
|
||||
|
||||
try {
|
||||
await appendBlobURL.appendBlock(Aborter.none, "a", 1);
|
||||
await appendBlobClient.appendBlock("a", 1);
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(err.message.includes("InvalidBlobType"), true);
|
||||
return;
|
||||
|
@ -402,10 +424,10 @@ describe("AppendBlobAPIs", () => {
|
|||
});
|
||||
|
||||
it("Append block with content length 0 should not work @loki", async () => {
|
||||
await appendBlobURL.create(Aborter.none);
|
||||
await appendBlobClient.create();
|
||||
|
||||
try {
|
||||
await appendBlobURL.appendBlock(Aborter.none, "", 0);
|
||||
await appendBlobClient.appendBlock("", 0);
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(err.message.includes("InvalidHeaderValue"), true);
|
||||
return;
|
||||
|
@ -414,22 +436,18 @@ describe("AppendBlobAPIs", () => {
|
|||
});
|
||||
|
||||
it("Append block append position access condition should work @loki", async () => {
|
||||
await appendBlobURL.create(Aborter.none);
|
||||
await appendBlobURL.appendBlock(Aborter.none, "a", 1, {
|
||||
accessConditions: {
|
||||
appendPositionAccessConditions: {
|
||||
maxSize: 1,
|
||||
appendPosition: 0
|
||||
}
|
||||
await appendBlobClient.create();
|
||||
await appendBlobClient.appendBlock("a", 1, {
|
||||
conditions: {
|
||||
maxSize: 1,
|
||||
appendPosition: 0
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
await appendBlobURL.appendBlock(Aborter.none, "a", 1, {
|
||||
accessConditions: {
|
||||
appendPositionAccessConditions: {
|
||||
maxSize: 1
|
||||
}
|
||||
await appendBlobClient.appendBlock("a", 1, {
|
||||
conditions: {
|
||||
maxSize: 1
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
|
@ -439,20 +457,16 @@ describe("AppendBlobAPIs", () => {
|
|||
);
|
||||
assert.deepStrictEqual(err.statusCode, 412);
|
||||
|
||||
await appendBlobURL.appendBlock(Aborter.none, "a", 1, {
|
||||
accessConditions: {
|
||||
appendPositionAccessConditions: {
|
||||
appendPosition: 1
|
||||
}
|
||||
await appendBlobClient.appendBlock("a", 1, {
|
||||
conditions: {
|
||||
appendPosition: 1
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
await appendBlobURL.appendBlock(Aborter.none, "a", 1, {
|
||||
accessConditions: {
|
||||
appendPositionAccessConditions: {
|
||||
appendPosition: 0
|
||||
}
|
||||
await appendBlobClient.appendBlock("a", 1, {
|
||||
conditions: {
|
||||
appendPosition: 0
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
|
@ -469,13 +483,13 @@ describe("AppendBlobAPIs", () => {
|
|||
});
|
||||
|
||||
it("Append block md5 validation should work @loki", async () => {
|
||||
await appendBlobURL.create(Aborter.none);
|
||||
await appendBlobURL.appendBlock(Aborter.none, "aEf", 1, {
|
||||
await appendBlobClient.create();
|
||||
await appendBlobClient.appendBlock("aEf", 1, {
|
||||
transactionalContentMD5: await getMD5FromString("aEf")
|
||||
});
|
||||
|
||||
try {
|
||||
await appendBlobURL.appendBlock(Aborter.none, "aEf", 1, {
|
||||
await appendBlobClient.appendBlock("aEf", 1, {
|
||||
transactionalContentMD5: await getMD5FromString("invalid")
|
||||
});
|
||||
} catch (err) {
|
||||
|
@ -487,45 +501,35 @@ describe("AppendBlobAPIs", () => {
|
|||
});
|
||||
|
||||
it("Append block access condition should work @loki", async () => {
|
||||
let response = await appendBlobURL.create(Aborter.none);
|
||||
response = await appendBlobURL.appendBlock(Aborter.none, "a", 1, {
|
||||
accessConditions: {
|
||||
modifiedAccessConditions: {
|
||||
ifMatch: response.eTag
|
||||
}
|
||||
let response = await appendBlobClient.create();
|
||||
response = await appendBlobClient.appendBlock("a", 1, {
|
||||
conditions: {
|
||||
ifMatch: response.etag
|
||||
}
|
||||
});
|
||||
|
||||
response = await appendBlobURL.appendBlock(Aborter.none, "a", 1, {
|
||||
accessConditions: {
|
||||
modifiedAccessConditions: {
|
||||
ifNoneMatch: "xxxx"
|
||||
}
|
||||
response = await appendBlobClient.appendBlock("a", 1, {
|
||||
conditions: {
|
||||
ifNoneMatch: "xxxx"
|
||||
}
|
||||
});
|
||||
|
||||
response = await appendBlobURL.appendBlock(Aborter.none, "a", 1, {
|
||||
accessConditions: {
|
||||
modifiedAccessConditions: {
|
||||
ifModifiedSince: new Date("2000/01/01")
|
||||
}
|
||||
response = await appendBlobClient.appendBlock("a", 1, {
|
||||
conditions: {
|
||||
ifModifiedSince: new Date("2000/01/01")
|
||||
}
|
||||
});
|
||||
|
||||
response = await appendBlobURL.appendBlock(Aborter.none, "a", 1, {
|
||||
accessConditions: {
|
||||
modifiedAccessConditions: {
|
||||
ifUnmodifiedSince: response.lastModified
|
||||
}
|
||||
response = await appendBlobClient.appendBlock("a", 1, {
|
||||
conditions: {
|
||||
ifUnmodifiedSince: response.lastModified
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
await appendBlobURL.appendBlock(Aborter.none, "a", 1, {
|
||||
accessConditions: {
|
||||
modifiedAccessConditions: {
|
||||
ifMatch: response.eTag + "2"
|
||||
}
|
||||
await appendBlobClient.appendBlock("a", 1, {
|
||||
conditions: {
|
||||
ifMatch: response.etag + "2"
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
|
@ -537,26 +541,25 @@ describe("AppendBlobAPIs", () => {
|
|||
});
|
||||
|
||||
it("Append block lease condition should work @loki", async () => {
|
||||
await appendBlobURL.create(Aborter.none);
|
||||
await appendBlobClient.create();
|
||||
|
||||
const leaseId = "abcdefg";
|
||||
await appendBlobURL.acquireLease(Aborter.none, leaseId, 20);
|
||||
const blobLeaseClient = await appendBlobClient.getBlobLeaseClient(leaseId);
|
||||
await blobLeaseClient.acquireLease(20);
|
||||
|
||||
const properties = await appendBlobURL.getProperties(Aborter.none);
|
||||
const properties = await appendBlobClient.getProperties();
|
||||
assert.deepStrictEqual(properties.leaseDuration, "fixed");
|
||||
assert.deepStrictEqual(properties.leaseState, "leased");
|
||||
assert.deepStrictEqual(properties.leaseStatus, "locked");
|
||||
|
||||
await appendBlobURL.appendBlock(Aborter.none, "a", 1, {
|
||||
accessConditions: {
|
||||
leaseAccessConditions: {
|
||||
leaseId
|
||||
}
|
||||
await appendBlobClient.appendBlock("a", 1, {
|
||||
conditions: {
|
||||
leaseId
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
await appendBlobURL.appendBlock(Aborter.none, "c", 1);
|
||||
await appendBlobClient.appendBlock("c", 1);
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(err.message.includes("LeaseIdMissing"), true);
|
||||
assert.deepStrictEqual(err.statusCode, 412);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,11 +1,7 @@
|
|||
import {
|
||||
Aborter,
|
||||
BlobURL,
|
||||
BlockBlobURL,
|
||||
ContainerURL,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL
|
||||
StorageSharedKeyCredential,
|
||||
BlobServiceClient,
|
||||
newPipeline
|
||||
} from "@azure/storage-blob";
|
||||
import assert = require("assert");
|
||||
|
||||
|
@ -27,21 +23,26 @@ describe("BlockBlobAPIs", () => {
|
|||
const server = factory.createServer();
|
||||
|
||||
const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`;
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
let containerName: string = getUniqueName("container");
|
||||
let containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
let containerClient = serviceClient.getContainerClient(containerName);
|
||||
let blobName: string = getUniqueName("blob");
|
||||
let blobURL = BlobURL.fromContainerURL(containerURL, blobName);
|
||||
let blockBlobURL = BlockBlobURL.fromBlobURL(blobURL);
|
||||
let blobClient = containerClient.getBlobClient(blobName);
|
||||
let blockBlobClient = blobClient.getBlockBlobClient();
|
||||
|
||||
before(async () => {
|
||||
await server.start();
|
||||
|
@ -54,29 +55,25 @@ describe("BlockBlobAPIs", () => {
|
|||
|
||||
beforeEach(async () => {
|
||||
containerName = getUniqueName("container");
|
||||
containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
await containerURL.create(Aborter.none);
|
||||
containerClient = serviceClient.getContainerClient(containerName);
|
||||
await containerClient.create();
|
||||
blobName = getUniqueName("blob");
|
||||
blobURL = BlobURL.fromContainerURL(containerURL, blobName);
|
||||
blockBlobURL = BlockBlobURL.fromBlobURL(blobURL);
|
||||
blobClient = containerClient.getBlobClient(blobName);
|
||||
blockBlobClient = blobClient.getBlockBlobClient();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.delete();
|
||||
});
|
||||
|
||||
it("upload with string body and default parameters @loki @sql", async () => {
|
||||
const body: string = getUniqueName("randomstring");
|
||||
const result_upload = await blockBlobURL.upload(
|
||||
Aborter.none,
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
const result_upload = await blockBlobClient.upload(body, body.length);
|
||||
assert.equal(
|
||||
result_upload._response.request.headers.get("x-ms-client-request-id"),
|
||||
result_upload.clientRequestId
|
||||
);
|
||||
const result = await blobURL.download(Aborter.none, 0);
|
||||
const result = await blobClient.download(0);
|
||||
assert.deepStrictEqual(await bodyToString(result, body.length), body);
|
||||
assert.equal(
|
||||
result._response.request.headers.get("x-ms-client-request-id"),
|
||||
|
@ -85,8 +82,8 @@ describe("BlockBlobAPIs", () => {
|
|||
});
|
||||
|
||||
it("upload empty blob @loki @sql", async () => {
|
||||
await blockBlobURL.upload(Aborter.none, "", 0);
|
||||
const result = await blobURL.download(Aborter.none, 0);
|
||||
await blockBlobClient.upload("", 0);
|
||||
const result = await blobClient.download(0);
|
||||
assert.deepStrictEqual(await bodyToString(result, 0), "");
|
||||
});
|
||||
|
||||
|
@ -103,20 +100,15 @@ describe("BlockBlobAPIs", () => {
|
|||
keyb: "valb"
|
||||
}
|
||||
};
|
||||
const result_upload = await blockBlobURL.upload(
|
||||
Aborter.none,
|
||||
body,
|
||||
body.length,
|
||||
{
|
||||
blobHTTPHeaders: options,
|
||||
metadata: options.metadata
|
||||
}
|
||||
);
|
||||
const result_upload = await blockBlobClient.upload(body, body.length, {
|
||||
blobHTTPHeaders: options,
|
||||
metadata: options.metadata
|
||||
});
|
||||
assert.equal(
|
||||
result_upload._response.request.headers.get("x-ms-client-request-id"),
|
||||
result_upload.clientRequestId
|
||||
);
|
||||
const result = await blobURL.download(Aborter.none, 0);
|
||||
const result = await blobClient.download(0);
|
||||
assert.deepStrictEqual(await bodyToString(result, body.length), body);
|
||||
assert.deepStrictEqual(result.cacheControl, options.blobCacheControl);
|
||||
assert.deepStrictEqual(
|
||||
|
@ -135,8 +127,7 @@ describe("BlockBlobAPIs", () => {
|
|||
|
||||
it("stageBlock @loki @sql", async () => {
|
||||
const body = "HelloWorld";
|
||||
const result_stage = await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
const result_stage = await blockBlobClient.stageBlock(
|
||||
base64encode("1"),
|
||||
body,
|
||||
body.length
|
||||
|
@ -145,28 +136,21 @@ describe("BlockBlobAPIs", () => {
|
|||
result_stage._response.request.headers.get("x-ms-client-request-id"),
|
||||
result_stage.clientRequestId
|
||||
);
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("2"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
await blockBlobClient.stageBlock(base64encode("2"), body, body.length);
|
||||
|
||||
const listBlobResponse = await containerURL.listBlobFlatSegment(
|
||||
Aborter.none,
|
||||
undefined,
|
||||
{ include: ["uncommittedblobs"] }
|
||||
);
|
||||
const listBlobResponse = await (
|
||||
await containerClient
|
||||
.listBlobsFlat({ includeUncommitedBlobs: true })
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.equal(listBlobResponse.segment.blobItems.length, 1);
|
||||
assert.deepStrictEqual(
|
||||
listBlobResponse.segment.blobItems[0].properties.contentLength,
|
||||
0
|
||||
);
|
||||
|
||||
const listResponse = await blockBlobURL.getBlockList(
|
||||
Aborter.none,
|
||||
"uncommitted"
|
||||
);
|
||||
const listResponse = await blockBlobClient.getBlockList("uncommitted");
|
||||
assert.equal(listResponse.uncommittedBlocks!.length, 2);
|
||||
assert.equal(listResponse.uncommittedBlocks![0].name, base64encode("1"));
|
||||
assert.equal(listResponse.uncommittedBlocks![0].size, body.length);
|
||||
|
@ -181,35 +165,23 @@ describe("BlockBlobAPIs", () => {
|
|||
it("stageBlock with double commit block should work @loki @sql", async () => {
|
||||
const body = "HelloWorld";
|
||||
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("1"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
await blockBlobClient.stageBlock(base64encode("1"), body, body.length);
|
||||
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("1"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
await blockBlobClient.stageBlock(base64encode("1"), body, body.length);
|
||||
|
||||
const listBlobResponse = await containerURL.listBlobFlatSegment(
|
||||
Aborter.none,
|
||||
undefined,
|
||||
{ include: ["uncommittedblobs"] }
|
||||
);
|
||||
const listBlobResponse = (
|
||||
await containerClient
|
||||
.listBlobsFlat({ includeUncommitedBlobs: true })
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.equal(listBlobResponse.segment.blobItems.length, 1);
|
||||
assert.deepStrictEqual(
|
||||
listBlobResponse.segment.blobItems[0].properties.contentLength,
|
||||
0
|
||||
);
|
||||
|
||||
const listResponse = await blockBlobURL.getBlockList(
|
||||
Aborter.none,
|
||||
"uncommitted"
|
||||
);
|
||||
const listResponse = await blockBlobClient.getBlockList("uncommitted");
|
||||
assert.equal(listResponse.uncommittedBlocks!.length, 1);
|
||||
assert.equal(listResponse.uncommittedBlocks![0].name, base64encode("1"));
|
||||
assert.equal(listResponse.uncommittedBlocks![0].size, body.length);
|
||||
|
@ -221,19 +193,9 @@ describe("BlockBlobAPIs", () => {
|
|||
|
||||
it("commitBlockList @loki @sql", async () => {
|
||||
const body = "HelloWorld";
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("1"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("2"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
const result_commit = await blockBlobURL.commitBlockList(Aborter.none, [
|
||||
await blockBlobClient.stageBlock(base64encode("1"), body, body.length);
|
||||
await blockBlobClient.stageBlock(base64encode("2"), body, body.length);
|
||||
const result_commit = await blockBlobClient.commitBlockList([
|
||||
base64encode("1"),
|
||||
base64encode("2")
|
||||
]);
|
||||
|
@ -241,10 +203,7 @@ describe("BlockBlobAPIs", () => {
|
|||
result_commit._response.request.headers.get("x-ms-client-request-id"),
|
||||
result_commit.clientRequestId
|
||||
);
|
||||
const listResponse = await blockBlobURL.getBlockList(
|
||||
Aborter.none,
|
||||
"committed"
|
||||
);
|
||||
const listResponse = await blockBlobClient.getBlockList("committed");
|
||||
assert.equal(listResponse.committedBlocks!.length, 2);
|
||||
assert.equal(listResponse.committedBlocks![0].name, base64encode("1"));
|
||||
assert.equal(listResponse.committedBlocks![0].size, body.length);
|
||||
|
@ -258,19 +217,9 @@ describe("BlockBlobAPIs", () => {
|
|||
|
||||
it("commitBlockList with previous committed blocks @loki @sql", async () => {
|
||||
const body = "HelloWorld";
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("1"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("2"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
const result_commit = await blockBlobURL.commitBlockList(Aborter.none, [
|
||||
await blockBlobClient.stageBlock(base64encode("1"), body, body.length);
|
||||
await blockBlobClient.stageBlock(base64encode("2"), body, body.length);
|
||||
const result_commit = await blockBlobClient.commitBlockList([
|
||||
base64encode("1"),
|
||||
base64encode("2")
|
||||
]);
|
||||
|
@ -279,13 +228,10 @@ describe("BlockBlobAPIs", () => {
|
|||
result_commit.clientRequestId
|
||||
);
|
||||
|
||||
const properties1 = await blockBlobURL.getProperties(Aborter.none);
|
||||
assert.notDeepStrictEqual(properties1.creationTime, undefined);
|
||||
const properties1 = await blockBlobClient.getProperties();
|
||||
assert.notDeepStrictEqual(properties1.createdOn, undefined);
|
||||
|
||||
const listResponse = await blockBlobURL.getBlockList(
|
||||
Aborter.none,
|
||||
"committed"
|
||||
);
|
||||
const listResponse = await blockBlobClient.getBlockList("committed");
|
||||
assert.equal(listResponse.committedBlocks!.length, 2);
|
||||
assert.equal(listResponse.committedBlocks![0].name, base64encode("1"));
|
||||
assert.equal(listResponse.committedBlocks![0].size, body.length);
|
||||
|
@ -296,42 +242,34 @@ describe("BlockBlobAPIs", () => {
|
|||
listResponse.clientRequestId
|
||||
);
|
||||
|
||||
await blockBlobURL.commitBlockList(Aborter.none, [base64encode("2")]);
|
||||
const listResponse2 = await blockBlobURL.getBlockList(
|
||||
Aborter.none,
|
||||
"committed"
|
||||
);
|
||||
await blockBlobClient.commitBlockList([base64encode("2")]);
|
||||
const listResponse2 = await blockBlobClient.getBlockList("committed");
|
||||
assert.equal(listResponse2.committedBlocks!.length, 1);
|
||||
assert.equal(listResponse2.committedBlocks![0].name, base64encode("2"));
|
||||
assert.equal(listResponse2.committedBlocks![0].size, body.length);
|
||||
|
||||
const properties2 = await blockBlobURL.getProperties(Aborter.none);
|
||||
assert.notDeepStrictEqual(properties2.creationTime, undefined);
|
||||
assert.deepStrictEqual(properties1.creationTime, properties2.creationTime);
|
||||
const properties2 = await blockBlobClient.getProperties();
|
||||
assert.notDeepStrictEqual(properties2.createdOn, undefined);
|
||||
assert.deepStrictEqual(properties1.createdOn, properties2.createdOn);
|
||||
});
|
||||
|
||||
it("commitBlockList with empty list should create an empty block blob @loki @sql", async () => {
|
||||
await blockBlobURL.commitBlockList(Aborter.none, []);
|
||||
await blockBlobClient.commitBlockList([]);
|
||||
|
||||
const listResponse = await blockBlobURL.getBlockList(
|
||||
Aborter.none,
|
||||
"committed"
|
||||
);
|
||||
const listResponse = await blockBlobClient.getBlockList("committed");
|
||||
assert.equal(listResponse.committedBlocks!.length, 0);
|
||||
|
||||
const result = await blobURL.download(Aborter.none, 0);
|
||||
const result = await blobClient.download(0);
|
||||
assert.deepStrictEqual(await bodyToString(result, 0), "");
|
||||
});
|
||||
|
||||
it("commitBlockList with empty list should not work with ifNoneMatch=* for existing blob @loki @sql", async () => {
|
||||
await blockBlobURL.commitBlockList(Aborter.none, []);
|
||||
await blockBlobClient.commitBlockList([]);
|
||||
|
||||
try {
|
||||
await blockBlobURL.commitBlockList(Aborter.none, [], {
|
||||
accessConditions: {
|
||||
modifiedAccessConditions: {
|
||||
ifNoneMatch: "*"
|
||||
}
|
||||
await blockBlobClient.commitBlockList([], {
|
||||
conditions: {
|
||||
ifNoneMatch: "*"
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
|
@ -343,14 +281,12 @@ describe("BlockBlobAPIs", () => {
|
|||
});
|
||||
|
||||
it("upload should not work with ifNoneMatch=* for existing blob @loki @sql", async () => {
|
||||
await blockBlobURL.commitBlockList(Aborter.none, []);
|
||||
await blockBlobClient.commitBlockList([]);
|
||||
|
||||
try {
|
||||
await blockBlobURL.upload(Aborter.none, "hello", 5, {
|
||||
accessConditions: {
|
||||
modifiedAccessConditions: {
|
||||
ifNoneMatch: "*"
|
||||
}
|
||||
await blockBlobClient.upload("hello", 5, {
|
||||
conditions: {
|
||||
ifNoneMatch: "*"
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
|
@ -363,18 +299,8 @@ describe("BlockBlobAPIs", () => {
|
|||
|
||||
it("commitBlockList with all parameters set @loki @sql", async () => {
|
||||
const body = "HelloWorld";
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("1"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("2"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
await blockBlobClient.stageBlock(base64encode("1"), body, body.length);
|
||||
await blockBlobClient.stageBlock(base64encode("2"), body, body.length);
|
||||
|
||||
const options = {
|
||||
blobCacheControl: "blobCacheControl",
|
||||
|
@ -387,8 +313,7 @@ describe("BlockBlobAPIs", () => {
|
|||
keyb: "valb"
|
||||
}
|
||||
};
|
||||
await blockBlobURL.commitBlockList(
|
||||
Aborter.none,
|
||||
await blockBlobClient.commitBlockList(
|
||||
[base64encode("1"), base64encode("2")],
|
||||
{
|
||||
blobHTTPHeaders: options,
|
||||
|
@ -396,17 +321,14 @@ describe("BlockBlobAPIs", () => {
|
|||
}
|
||||
);
|
||||
|
||||
const listResponse = await blockBlobURL.getBlockList(
|
||||
Aborter.none,
|
||||
"committed"
|
||||
);
|
||||
const listResponse = await blockBlobClient.getBlockList("committed");
|
||||
assert.equal(listResponse.committedBlocks!.length, 2);
|
||||
assert.equal(listResponse.committedBlocks![0].name, base64encode("1"));
|
||||
assert.equal(listResponse.committedBlocks![0].size, body.length);
|
||||
assert.equal(listResponse.committedBlocks![1].name, base64encode("2"));
|
||||
assert.equal(listResponse.committedBlocks![1].size, body.length);
|
||||
|
||||
const result = await blobURL.download(Aborter.none, 0);
|
||||
const result = await blobClient.download(0);
|
||||
assert.deepStrictEqual(
|
||||
await bodyToString(result, body.repeat(2).length),
|
||||
body.repeat(2)
|
||||
|
@ -428,20 +350,10 @@ describe("BlockBlobAPIs", () => {
|
|||
|
||||
it("getBlockList @loki @sql", async () => {
|
||||
const body = "HelloWorld";
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("1"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("2"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
await blockBlobURL.commitBlockList(Aborter.none, [base64encode("2")]);
|
||||
const listResponse = await blockBlobURL.getBlockList(Aborter.none, "all");
|
||||
await blockBlobClient.stageBlock(base64encode("1"), body, body.length);
|
||||
await blockBlobClient.stageBlock(base64encode("2"), body, body.length);
|
||||
await blockBlobClient.commitBlockList([base64encode("2")]);
|
||||
const listResponse = await blockBlobClient.getBlockList("all");
|
||||
assert.equal(listResponse.committedBlocks!.length, 1);
|
||||
assert.equal(listResponse.uncommittedBlocks!.length, 0);
|
||||
assert.equal(listResponse.committedBlocks![0].name, base64encode("2"));
|
||||
|
@ -450,23 +362,13 @@ describe("BlockBlobAPIs", () => {
|
|||
|
||||
it("getBlockList_BlockListingFilter @loki @sql", async () => {
|
||||
const body = "HelloWorld";
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("1"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("2"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
await blockBlobClient.stageBlock(base64encode("1"), body, body.length);
|
||||
await blockBlobClient.stageBlock(base64encode("2"), body, body.length);
|
||||
|
||||
// Getproperties on a block blob without commited block will return 404
|
||||
let err;
|
||||
try {
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
await blockBlobClient.getProperties();
|
||||
} catch (error) {
|
||||
err = error;
|
||||
}
|
||||
|
@ -474,33 +376,20 @@ describe("BlockBlobAPIs", () => {
|
|||
|
||||
// Stage block with block Id length different than the exist uncommited blocks will fail with 400
|
||||
try {
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("123"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
await blockBlobClient.stageBlock(base64encode("123"), body, body.length);
|
||||
} catch (error) {
|
||||
err = error;
|
||||
}
|
||||
assert.deepStrictEqual(err.statusCode, 400);
|
||||
|
||||
await blockBlobURL.commitBlockList(Aborter.none, [
|
||||
await blockBlobClient.commitBlockList([
|
||||
base64encode("1"),
|
||||
base64encode("2")
|
||||
]);
|
||||
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("123"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
await blockBlobClient.stageBlock(base64encode("123"), body, body.length);
|
||||
|
||||
let listResponse = await blockBlobURL.getBlockList(
|
||||
Aborter.none,
|
||||
"committed"
|
||||
);
|
||||
let listResponse = await blockBlobClient.getBlockList("committed");
|
||||
assert.equal(listResponse.committedBlocks!.length, 2);
|
||||
assert.equal(listResponse.committedBlocks![0].name, base64encode("1"));
|
||||
assert.equal(listResponse.committedBlocks![0].size, body.length);
|
||||
|
@ -508,13 +397,13 @@ describe("BlockBlobAPIs", () => {
|
|||
assert.equal(listResponse.committedBlocks![1].size, body.length);
|
||||
assert.equal(listResponse.uncommittedBlocks!.length, 0);
|
||||
|
||||
listResponse = await blockBlobURL.getBlockList(Aborter.none, "uncommitted");
|
||||
listResponse = await blockBlobClient.getBlockList("uncommitted");
|
||||
assert.equal(listResponse.uncommittedBlocks!.length, 1);
|
||||
assert.equal(listResponse.uncommittedBlocks![0].name, base64encode("123"));
|
||||
assert.equal(listResponse.uncommittedBlocks![0].size, body.length);
|
||||
assert.equal(listResponse.committedBlocks!.length, 0);
|
||||
|
||||
listResponse = await blockBlobURL.getBlockList(Aborter.none, "all");
|
||||
listResponse = await blockBlobClient.getBlockList("all");
|
||||
assert.equal(listResponse.committedBlocks!.length, 2);
|
||||
assert.equal(listResponse.committedBlocks![0].name, base64encode("1"));
|
||||
assert.equal(listResponse.committedBlocks![0].size, body.length);
|
||||
|
@ -525,12 +414,37 @@ describe("BlockBlobAPIs", () => {
|
|||
assert.equal(listResponse.uncommittedBlocks![0].size, body.length);
|
||||
});
|
||||
|
||||
it("getBlockList for non-existent blob @loki @sql", async () => {
|
||||
try {
|
||||
await blockBlobClient.getBlockList("committed");
|
||||
} catch (error) {
|
||||
assert.deepEqual(404, error.statusCode);
|
||||
return;
|
||||
}
|
||||
assert.fail();
|
||||
});
|
||||
|
||||
it("getBlockList for non-existent container @loki @sql", async () => {
|
||||
const fakeContainer = getUniqueName("container");
|
||||
const fakeContainerClient = serviceClient.getContainerClient(fakeContainer);
|
||||
const fakeBlobClient = fakeContainerClient.getBlobClient(blobName);
|
||||
const fakeBlockBlobClient = fakeBlobClient.getBlockBlobClient();
|
||||
|
||||
try {
|
||||
await fakeBlockBlobClient.getBlockList("committed");
|
||||
} catch (error) {
|
||||
assert.deepEqual(404, error.statusCode);
|
||||
return;
|
||||
}
|
||||
assert.fail();
|
||||
});
|
||||
|
||||
it("upload with Readable stream body and default parameters @loki @sql", async () => {
|
||||
const body: string = getUniqueName("randomstring");
|
||||
const bodyBuffer = Buffer.from(body);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, bodyBuffer, body.length);
|
||||
const result = await blobURL.download(Aborter.none, 0);
|
||||
await blockBlobClient.upload(bodyBuffer, body.length);
|
||||
const result = await blobClient.download(0);
|
||||
assert.equal(
|
||||
result._response.request.headers.get("x-ms-client-request-id"),
|
||||
result.clientRequestId
|
||||
|
@ -552,8 +466,8 @@ describe("BlockBlobAPIs", () => {
|
|||
|
||||
it("upload with Chinese string body and default parameters @loki @sql", async () => {
|
||||
const body: string = getUniqueName("randomstring你好");
|
||||
await blockBlobURL.upload(Aborter.none, body, Buffer.byteLength(body));
|
||||
const result = await blobURL.download(Aborter.none, 0);
|
||||
await blockBlobClient.upload(body, Buffer.byteLength(body));
|
||||
const result = await blobClient.download(0);
|
||||
assert.deepStrictEqual(
|
||||
await bodyToString(result, Buffer.byteLength(body)),
|
||||
body
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
import {
|
||||
Aborter,
|
||||
BlobURL,
|
||||
BlockBlobURL,
|
||||
ContainerURL,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL
|
||||
BlobServiceClient,
|
||||
newPipeline,
|
||||
StorageSharedKeyCredential
|
||||
} from "@azure/storage-blob";
|
||||
import assert = require("assert");
|
||||
|
||||
|
@ -27,18 +23,24 @@ describe("ContainerAPIs", () => {
|
|||
const server = factory.createServer();
|
||||
|
||||
const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`;
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
let containerName: string = getUniqueName("container");
|
||||
let containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
let containerClient = serviceClient.getContainerClient(containerName);
|
||||
let blobLeaseClient = containerClient.getBlobLeaseClient();
|
||||
|
||||
before(async () => {
|
||||
await server.start();
|
||||
|
@ -51,12 +53,13 @@ describe("ContainerAPIs", () => {
|
|||
|
||||
beforeEach(async () => {
|
||||
containerName = getUniqueName("container");
|
||||
containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
await containerURL.create(Aborter.none);
|
||||
containerClient = serviceClient.getContainerClient(containerName);
|
||||
await containerClient.create();
|
||||
blobLeaseClient = containerClient.getBlobLeaseClient();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.delete();
|
||||
});
|
||||
|
||||
it("setMetadata @loki @sql", async () => {
|
||||
|
@ -65,22 +68,19 @@ describe("ContainerAPIs", () => {
|
|||
keya: "vala",
|
||||
keyb: "valb"
|
||||
};
|
||||
await containerURL.setMetadata(Aborter.none, metadata);
|
||||
await containerClient.setMetadata(metadata);
|
||||
|
||||
const result = await containerURL.getProperties(Aborter.none);
|
||||
const result = await containerClient.getProperties();
|
||||
assert.deepEqual(result.metadata, metadata);
|
||||
});
|
||||
|
||||
it("setMetadata should work with conditional headers @loki @sql", async () => {
|
||||
// const properties = await containerURL.getProperties(Aborter.none);
|
||||
await containerURL.setMetadata(
|
||||
Aborter.none,
|
||||
// const properties = await containerClient.getProperties();
|
||||
await containerClient.setMetadata(
|
||||
{},
|
||||
{
|
||||
containerAccessConditions: {
|
||||
modifiedAccessConditions: {
|
||||
ifModifiedSince: new Date("2018/01/01")
|
||||
}
|
||||
conditions: {
|
||||
ifModifiedSince: new Date("2018/01/01")
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -88,14 +88,11 @@ describe("ContainerAPIs", () => {
|
|||
|
||||
it("setMetadata should not work with invalid conditional headers @loki @sql", async () => {
|
||||
try {
|
||||
await containerURL.setMetadata(
|
||||
Aborter.none,
|
||||
await containerClient.setMetadata(
|
||||
{},
|
||||
{
|
||||
containerAccessConditions: {
|
||||
modifiedAccessConditions: {
|
||||
ifModifiedSince: new Date("2118/01/01")
|
||||
}
|
||||
conditions: {
|
||||
ifModifiedSince: new Date("2118/01/01")
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -108,8 +105,8 @@ describe("ContainerAPIs", () => {
|
|||
});
|
||||
|
||||
it("getProperties @loki @sql", async () => {
|
||||
const result = await containerURL.getProperties(Aborter.none);
|
||||
assert.ok(result.eTag!.length > 0);
|
||||
const result = await containerClient.getProperties();
|
||||
assert.ok(result.etag!.length > 0);
|
||||
assert.ok(result.lastModified);
|
||||
assert.ok(!result.leaseDuration);
|
||||
assert.equal(result.leaseState, "available");
|
||||
|
@ -125,13 +122,12 @@ describe("ContainerAPIs", () => {
|
|||
});
|
||||
|
||||
it("getProperties should return 404 for non existed container @loki @sql", async () => {
|
||||
const nonExistedContainerURL = ContainerURL.fromServiceURL(
|
||||
serviceURL,
|
||||
const nonExistedContainerURL = serviceClient.getContainerClient(
|
||||
"404container_"
|
||||
);
|
||||
let expectedError = false;
|
||||
try {
|
||||
await nonExistedContainerURL.getProperties(Aborter.none);
|
||||
await nonExistedContainerURL.getProperties();
|
||||
} catch (err) {
|
||||
if (err.response.status === 404) {
|
||||
expectedError = true;
|
||||
|
@ -140,75 +136,70 @@ describe("ContainerAPIs", () => {
|
|||
assert.ok(expectedError);
|
||||
});
|
||||
|
||||
it("create with default parameters @loki @sql", done => {
|
||||
it("create with default parameters @loki @sql", (done) => {
|
||||
// create() with default parameters has been tested in beforeEach
|
||||
done();
|
||||
});
|
||||
|
||||
it("create with all parameters configured @loki @sql", async () => {
|
||||
const cURL = ContainerURL.fromServiceURL(
|
||||
serviceURL,
|
||||
getUniqueName(containerName)
|
||||
);
|
||||
const cURL = serviceClient.getContainerClient(getUniqueName(containerName));
|
||||
const metadata = { key: "value" };
|
||||
const access = "container";
|
||||
const result_create = await cURL.create(Aborter.none, { metadata, access });
|
||||
const result_create = await cURL.create({ metadata, access });
|
||||
assert.equal(
|
||||
result_create._response.request.headers.get("x-ms-client-request-id"),
|
||||
result_create.clientRequestId
|
||||
);
|
||||
const result = await cURL.getProperties(Aborter.none);
|
||||
const result = await cURL.getProperties();
|
||||
assert.deepEqual(result.blobPublicAccess, access);
|
||||
assert.deepEqual(result.metadata, metadata);
|
||||
});
|
||||
|
||||
it("delete @loki @sql", done => {
|
||||
it("delete @loki @sql", (done) => {
|
||||
// delete() with default parameters has been tested in afterEach
|
||||
done();
|
||||
});
|
||||
|
||||
it("listBlobHierarchySegment with default parameters @loki @sql", async () => {
|
||||
const blobURLs = [];
|
||||
const blobClients = [];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const blobURL = BlobURL.fromContainerURL(
|
||||
containerURL,
|
||||
const blobClient = containerClient.getBlobClient(
|
||||
getUniqueName(`blockblob${i}/${i}`)
|
||||
);
|
||||
const blockBlobURL = BlockBlobURL.fromBlobURL(blobURL);
|
||||
await blockBlobURL.upload(Aborter.none, "", 0);
|
||||
blobURLs.push(blobURL);
|
||||
const blockBlobClient = blobClient.getBlockBlobClient();
|
||||
await blockBlobClient.upload("", 0);
|
||||
blobClients.push(blobClient);
|
||||
}
|
||||
|
||||
const delimiter = "/";
|
||||
const result = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
delimiter
|
||||
);
|
||||
const result = (
|
||||
await containerClient.listBlobsByHierarchy(delimiter).byPage().next()
|
||||
).value;
|
||||
assert.ok(result.serviceEndpoint.length > 0);
|
||||
assert.ok(containerURL.url.indexOf(result.containerName));
|
||||
assert.ok(containerClient.url.indexOf(result.containerName));
|
||||
assert.equal(
|
||||
result._response.request.headers.get("x-ms-client-request-id"),
|
||||
result.clientRequestId
|
||||
);
|
||||
assert.deepStrictEqual(result.nextMarker, "");
|
||||
assert.deepStrictEqual(result.continuationToken, "");
|
||||
assert.deepStrictEqual(result.delimiter, delimiter);
|
||||
assert.deepStrictEqual(
|
||||
result.segment.blobPrefixes!.length,
|
||||
blobURLs.length
|
||||
blobClients.length
|
||||
);
|
||||
|
||||
for (const blob of blobURLs) {
|
||||
for (const blob of blobClients) {
|
||||
let i = 0;
|
||||
assert.ok(blob.url.indexOf(result.segment.blobPrefixes![i++].name));
|
||||
}
|
||||
|
||||
for (const blob of blobURLs) {
|
||||
await blob.delete(Aborter.none);
|
||||
for (const blob of blobClients) {
|
||||
await blob.delete();
|
||||
}
|
||||
});
|
||||
|
||||
it("listBlobHierarchySegment with all parameters configured @loki @sql", async () => {
|
||||
const blobURLs = [];
|
||||
const blobClients = [];
|
||||
const prefix = "blockblob";
|
||||
const metadata = {
|
||||
keya: "a",
|
||||
|
@ -216,116 +207,107 @@ describe("ContainerAPIs", () => {
|
|||
};
|
||||
const delimiter = "/";
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const blobURL = BlobURL.fromContainerURL(
|
||||
containerURL,
|
||||
const blobClient = containerClient.getBlobClient(
|
||||
getUniqueName(`${prefix}${i}${delimiter}${i}`)
|
||||
);
|
||||
const blockBlobURL = BlockBlobURL.fromBlobURL(blobURL);
|
||||
await blockBlobURL.upload(Aborter.none, "", 0, {
|
||||
const blockBlobClient = blobClient.getBlockBlobClient();
|
||||
await blockBlobClient.upload("", 0, {
|
||||
metadata
|
||||
});
|
||||
blobURLs.push(blobURL);
|
||||
blobClients.push(blobClient);
|
||||
}
|
||||
|
||||
const result = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
delimiter,
|
||||
undefined,
|
||||
{
|
||||
include: [
|
||||
"metadata",
|
||||
"uncommittedblobs",
|
||||
"copy",
|
||||
"deleted",
|
||||
"snapshots"
|
||||
],
|
||||
maxresults: 1,
|
||||
prefix
|
||||
}
|
||||
);
|
||||
const result = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy(delimiter, {
|
||||
includeCopy: true,
|
||||
includeDeleted: true,
|
||||
includeMetadata: true,
|
||||
includeSnapshots: true,
|
||||
includeUncommitedBlobs: true,
|
||||
prefix
|
||||
})
|
||||
.byPage({ maxPageSize: 1 })
|
||||
.next()
|
||||
).value;
|
||||
assert.ok(result.serviceEndpoint.length > 0);
|
||||
assert.ok(containerURL.url.indexOf(result.containerName));
|
||||
assert.ok(containerClient.url.indexOf(result.containerName));
|
||||
assert.deepStrictEqual(result.segment.blobPrefixes!.length, 1);
|
||||
assert.deepStrictEqual(result.segment.blobItems!.length, 0);
|
||||
assert.ok(blobURLs[0].url.indexOf(result.segment.blobPrefixes![0].name));
|
||||
assert.ok(blobClients[0].url.indexOf(result.segment.blobPrefixes![0].name));
|
||||
assert.equal(
|
||||
result._response.request.headers.get("x-ms-client-request-id"),
|
||||
result.clientRequestId
|
||||
);
|
||||
|
||||
const result2 = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
delimiter,
|
||||
result.nextMarker,
|
||||
{
|
||||
include: [
|
||||
"metadata",
|
||||
"uncommittedblobs",
|
||||
"copy",
|
||||
"deleted",
|
||||
"snapshots"
|
||||
],
|
||||
maxresults: 2,
|
||||
prefix
|
||||
}
|
||||
);
|
||||
const result2 = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy(delimiter, {
|
||||
includeCopy: true,
|
||||
includeDeleted: true,
|
||||
includeMetadata: true,
|
||||
includeSnapshots: true,
|
||||
includeUncommitedBlobs: true,
|
||||
prefix
|
||||
})
|
||||
.byPage({
|
||||
continuationToken: result.continuationToken,
|
||||
maxPageSize: 2
|
||||
})
|
||||
.next()
|
||||
).value;
|
||||
assert.ok(result2.serviceEndpoint.length > 0);
|
||||
assert.ok(containerURL.url.indexOf(result2.containerName));
|
||||
assert.ok(containerClient.url.indexOf(result2.containerName));
|
||||
assert.deepStrictEqual(result2.segment.blobPrefixes!.length, 1);
|
||||
assert.deepStrictEqual(result2.segment.blobItems!.length, 0);
|
||||
assert.ok(blobURLs[0].url.indexOf(result2.segment.blobPrefixes![0].name));
|
||||
|
||||
const result3 = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
delimiter,
|
||||
undefined,
|
||||
{
|
||||
include: [
|
||||
"metadata",
|
||||
"uncommittedblobs",
|
||||
"copy",
|
||||
"deleted",
|
||||
"snapshots"
|
||||
],
|
||||
maxresults: 2,
|
||||
prefix: `${prefix}0${delimiter}`
|
||||
}
|
||||
assert.ok(
|
||||
blobClients[0].url.indexOf(result2.segment.blobPrefixes![0].name)
|
||||
);
|
||||
|
||||
const result3 = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy(delimiter, {
|
||||
includeCopy: true,
|
||||
includeDeleted: true,
|
||||
includeMetadata: true,
|
||||
includeSnapshots: true,
|
||||
includeUncommitedBlobs: true,
|
||||
prefix: `${prefix}0${delimiter}`
|
||||
})
|
||||
.byPage({ maxPageSize: 2 })
|
||||
.next()
|
||||
).value;
|
||||
assert.ok(result3.serviceEndpoint.length > 0);
|
||||
assert.ok(containerURL.url.indexOf(result3.containerName));
|
||||
assert.deepStrictEqual(result3.nextMarker, "");
|
||||
assert.ok(containerClient.url.indexOf(result3.containerName));
|
||||
assert.deepStrictEqual(result3.continuationToken, "");
|
||||
assert.deepStrictEqual(result3.delimiter, delimiter);
|
||||
assert.deepStrictEqual(result3.segment.blobItems!.length, 1);
|
||||
assert.deepStrictEqual(result3.segment.blobItems![0].metadata, {
|
||||
encrypted: undefined,
|
||||
...metadata
|
||||
});
|
||||
assert.ok(blobURLs[0].url.indexOf(result3.segment.blobItems![0].name));
|
||||
const getResult = await blobURLs[0].getProperties(Aborter.none);
|
||||
assert.ok(blobClients[0].url.indexOf(result3.segment.blobItems![0].name));
|
||||
const getResult = await blobClients[0].getProperties();
|
||||
assert.equal(
|
||||
getResult.eTag,
|
||||
getResult.etag,
|
||||
'"' + result3.segment.blobItems![0].properties.etag + '"'
|
||||
);
|
||||
|
||||
for (const blob of blobURLs) {
|
||||
await blob.delete(Aborter.none);
|
||||
for (const blob of blobClients) {
|
||||
await blob.delete();
|
||||
}
|
||||
});
|
||||
|
||||
it("acquireLease_available_proposedLeaseId_fixed @loki @sql", async () => {
|
||||
const guid = "ca761232-ed42-11ce-bacd-00aa0057b223";
|
||||
const duration = 30;
|
||||
const result_acquire = await containerURL.acquireLease(
|
||||
Aborter.none,
|
||||
guid,
|
||||
duration
|
||||
);
|
||||
blobLeaseClient = containerClient.getBlobLeaseClient(guid);
|
||||
const result_acquire = await blobLeaseClient.acquireLease(duration);
|
||||
assert.equal(
|
||||
result_acquire._response.request.headers.get("x-ms-client-request-id"),
|
||||
result_acquire.clientRequestId
|
||||
result_acquire._response.request.requestId
|
||||
);
|
||||
|
||||
const result = await containerURL.getProperties(Aborter.none);
|
||||
const result = await containerClient.getProperties();
|
||||
assert.equal(result.leaseDuration, "fixed");
|
||||
assert.equal(result.leaseState, "leased");
|
||||
assert.equal(result.leaseStatus, "locked");
|
||||
|
@ -334,19 +316,19 @@ describe("ContainerAPIs", () => {
|
|||
result.clientRequestId
|
||||
);
|
||||
|
||||
const result_release = await containerURL.releaseLease(Aborter.none, guid);
|
||||
const result_release = await blobLeaseClient.releaseLease();
|
||||
assert.equal(
|
||||
result_release._response.request.headers.get("x-ms-client-request-id"),
|
||||
result_release.clientRequestId
|
||||
result_release._response.request.requestId
|
||||
);
|
||||
});
|
||||
|
||||
it("acquireLease_available_NoproposedLeaseId_infinite @loki @sql", async () => {
|
||||
const leaseResult = await containerURL.acquireLease(Aborter.none, "", -1);
|
||||
const leaseResult = await blobLeaseClient.acquireLease(-1);
|
||||
const leaseId = leaseResult.leaseId;
|
||||
assert.ok(leaseId);
|
||||
|
||||
const result = await containerURL.getProperties(Aborter.none);
|
||||
const result = await containerClient.getProperties();
|
||||
assert.equal(result.leaseDuration, "infinite");
|
||||
assert.equal(result.leaseState, "leased");
|
||||
assert.equal(result.leaseStatus, "locked");
|
||||
|
@ -355,82 +337,78 @@ describe("ContainerAPIs", () => {
|
|||
result.clientRequestId
|
||||
);
|
||||
|
||||
await containerURL.releaseLease(Aborter.none, leaseId!);
|
||||
await blobLeaseClient.releaseLease();
|
||||
});
|
||||
|
||||
it("releaseLease @loki @sql", async () => {
|
||||
const guid = "ca761232ed4211cebacd00aa0057b223";
|
||||
const duration = -1;
|
||||
await containerURL.acquireLease(Aborter.none, guid, duration);
|
||||
blobLeaseClient = containerClient.getBlobLeaseClient(guid);
|
||||
await blobLeaseClient.acquireLease(duration);
|
||||
|
||||
const result = await containerURL.getProperties(Aborter.none);
|
||||
const result = await containerClient.getProperties();
|
||||
assert.equal(result.leaseDuration, "infinite");
|
||||
assert.equal(result.leaseState, "leased");
|
||||
assert.equal(result.leaseStatus, "locked");
|
||||
|
||||
await containerURL.releaseLease(Aborter.none, guid);
|
||||
await blobLeaseClient.releaseLease();
|
||||
});
|
||||
|
||||
it("renewLease @loki @sql", async () => {
|
||||
const guid = "ca761232ed4211cebacd00aa0057b223";
|
||||
const duration = 15;
|
||||
await containerURL.acquireLease(Aborter.none, guid, duration);
|
||||
blobLeaseClient = containerClient.getBlobLeaseClient(guid);
|
||||
await blobLeaseClient.acquireLease(duration);
|
||||
|
||||
const result = await containerURL.getProperties(Aborter.none);
|
||||
const result = await containerClient.getProperties();
|
||||
assert.equal(result.leaseDuration, "fixed");
|
||||
assert.equal(result.leaseState, "leased");
|
||||
assert.equal(result.leaseStatus, "locked");
|
||||
|
||||
await sleep(16 * 1000);
|
||||
const result2 = await containerURL.getProperties(Aborter.none);
|
||||
const result2 = await containerClient.getProperties();
|
||||
assert.ok(!result2.leaseDuration);
|
||||
assert.equal(result2.leaseState, "expired");
|
||||
assert.equal(result2.leaseStatus, "unlocked");
|
||||
|
||||
const result_renew = await containerURL.renewLease(Aborter.none, guid);
|
||||
const result3 = await containerURL.getProperties(Aborter.none);
|
||||
await blobLeaseClient.renewLease();
|
||||
const result3 = await containerClient.getProperties();
|
||||
assert.equal(result3.leaseDuration, "fixed");
|
||||
assert.equal(result3.leaseState, "leased");
|
||||
assert.equal(result3.leaseStatus, "locked");
|
||||
assert.equal(
|
||||
result_renew._response.request.headers.get("x-ms-client-request-id"),
|
||||
result_renew.clientRequestId
|
||||
);
|
||||
|
||||
await containerURL.releaseLease(Aborter.none, guid);
|
||||
await blobLeaseClient.releaseLease();
|
||||
});
|
||||
|
||||
it("changeLease @loki @sql", async () => {
|
||||
const guid = "ca761232ed4211cebacd00aa0057b223";
|
||||
const duration = 15;
|
||||
await containerURL.acquireLease(Aborter.none, guid, duration);
|
||||
blobLeaseClient = containerClient.getBlobLeaseClient(guid);
|
||||
await blobLeaseClient.acquireLease(duration);
|
||||
|
||||
const result = await containerURL.getProperties(Aborter.none);
|
||||
const result = await containerClient.getProperties();
|
||||
assert.equal(result.leaseDuration, "fixed");
|
||||
assert.equal(result.leaseState, "leased");
|
||||
assert.equal(result.leaseStatus, "locked");
|
||||
|
||||
const newGuid = "3c7e72ebb4304526bc53d8ecef03798f";
|
||||
const result_change = await containerURL.changeLease(
|
||||
Aborter.none,
|
||||
guid,
|
||||
newGuid
|
||||
);
|
||||
const result_change = await blobLeaseClient.changeLease(newGuid);
|
||||
assert.equal(
|
||||
result_change._response.request.headers.get("x-ms-client-request-id"),
|
||||
result_change.clientRequestId
|
||||
result_change._response.request.requestId
|
||||
);
|
||||
|
||||
await containerURL.getProperties(Aborter.none);
|
||||
await containerURL.releaseLease(Aborter.none, newGuid);
|
||||
await containerClient.getProperties();
|
||||
await blobLeaseClient.releaseLease();
|
||||
});
|
||||
|
||||
it("breakLease @loki @sql", async () => {
|
||||
const guid = "ca761232ed4211cebacd00aa0057b223";
|
||||
const duration = 15;
|
||||
await containerURL.acquireLease(Aborter.none, guid, duration);
|
||||
blobLeaseClient = containerClient.getBlobLeaseClient(guid);
|
||||
await blobLeaseClient.acquireLease(duration);
|
||||
|
||||
const result = await containerURL.getProperties(Aborter.none);
|
||||
const result = await containerClient.getProperties();
|
||||
assert.equal(result.leaseDuration, "fixed");
|
||||
assert.equal(result.leaseState, "leased");
|
||||
assert.equal(result.leaseStatus, "locked");
|
||||
|
@ -438,19 +416,16 @@ describe("ContainerAPIs", () => {
|
|||
const breakDuration = 30;
|
||||
let breaklefttime = breakDuration;
|
||||
while (breaklefttime > 0) {
|
||||
const breakResult = await containerURL.breakLease(
|
||||
Aborter.none,
|
||||
breakDuration
|
||||
);
|
||||
const breakResult = await blobLeaseClient.breakLease(breakDuration);
|
||||
|
||||
assert.equal(breakResult.leaseTime! <= breaklefttime, true);
|
||||
assert.equal(
|
||||
breakResult._response.request.headers.get("x-ms-client-request-id"),
|
||||
breakResult.clientRequestId
|
||||
breakResult._response.request.requestId
|
||||
);
|
||||
breaklefttime = breakResult.leaseTime!;
|
||||
|
||||
const result2 = await containerURL.getProperties(Aborter.none);
|
||||
const result2 = await containerClient.getProperties();
|
||||
assert.ok(!result2.leaseDuration);
|
||||
if (breaklefttime !== 0) {
|
||||
assert.equal(result2.leaseState, "breaking");
|
||||
|
@ -460,138 +435,128 @@ describe("ContainerAPIs", () => {
|
|||
await sleep(500);
|
||||
}
|
||||
|
||||
const result3 = await containerURL.getProperties(Aborter.none);
|
||||
const result3 = await containerClient.getProperties();
|
||||
assert.ok(!result3.leaseDuration);
|
||||
assert.equal(result3.leaseState, "broken");
|
||||
assert.equal(result3.leaseStatus, "unlocked");
|
||||
});
|
||||
|
||||
it("should correctly list all blobs in the container using listBlobFlatSegment with default parameters @loki @sql", async () => {
|
||||
const blobURLs = [];
|
||||
const blobClients = [];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const blobURL = BlobURL.fromContainerURL(
|
||||
containerURL,
|
||||
const blobClient = containerClient.getBlobClient(
|
||||
getUniqueName(`blockblob${i}/${i}`)
|
||||
);
|
||||
const blockBlobURL = BlockBlobURL.fromBlobURL(blobURL);
|
||||
await blockBlobURL.upload(Aborter.none, "", 0);
|
||||
blobURLs.push(blobURL);
|
||||
const blockBlobClient = blobClient.getBlockBlobClient();
|
||||
await blockBlobClient.upload("", 0);
|
||||
blobClients.push(blobClient);
|
||||
}
|
||||
|
||||
const inputmarker = undefined;
|
||||
const result = await containerURL.listBlobFlatSegment(
|
||||
Aborter.none,
|
||||
inputmarker
|
||||
);
|
||||
const result = (
|
||||
await containerClient
|
||||
.listBlobsFlat()
|
||||
.byPage({ continuationToken: inputmarker })
|
||||
.next()
|
||||
).value;
|
||||
assert.ok(result.serviceEndpoint.length > 0);
|
||||
assert.ok(containerURL.url.indexOf(result.containerName));
|
||||
assert.deepStrictEqual(result.nextMarker, "");
|
||||
assert.deepStrictEqual(result.segment.blobItems!.length, blobURLs.length);
|
||||
assert.ok(containerClient.url.indexOf(result.containerName));
|
||||
assert.deepStrictEqual(result.continuationToken, "");
|
||||
assert.deepStrictEqual(
|
||||
result.segment.blobItems!.length,
|
||||
blobClients.length
|
||||
);
|
||||
|
||||
let i = 0;
|
||||
for (const blob of blobURLs) {
|
||||
for (const blob of blobClients) {
|
||||
assert.ok(blob.url.indexOf(result.segment.blobItems![i].name));
|
||||
const getResult = await blob.getProperties(Aborter.none);
|
||||
const getResult = await blob.getProperties();
|
||||
assert.equal(
|
||||
getResult.eTag,
|
||||
getResult.etag,
|
||||
'"' + result.segment.blobItems![i].properties.etag + '"'
|
||||
);
|
||||
i++;
|
||||
}
|
||||
|
||||
for (const blob of blobURLs) {
|
||||
await blob.delete(Aborter.none);
|
||||
for (const blob of blobClients) {
|
||||
await blob.delete();
|
||||
}
|
||||
});
|
||||
|
||||
it("should only show uncommitted blobs in listBlobFlatSegment with uncommittedblobs option @loki @sql", async () => {
|
||||
const blobURL = BlobURL.fromContainerURL(
|
||||
containerURL,
|
||||
const blobClient = containerClient.getBlobClient(
|
||||
getUniqueName("uncommittedblob")
|
||||
);
|
||||
const blockBlobURL = BlockBlobURL.fromBlobURL(blobURL);
|
||||
const blockBlobClient = blobClient.getBlockBlobClient();
|
||||
|
||||
const body = "HelloWorld";
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("1"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
await blockBlobClient.stageBlock(base64encode("1"), body, body.length);
|
||||
|
||||
const result1 = await containerURL.listBlobFlatSegment(
|
||||
Aborter.none,
|
||||
undefined,
|
||||
{
|
||||
include: ["uncommittedblobs"]
|
||||
}
|
||||
);
|
||||
const result1 = (
|
||||
await containerClient
|
||||
.listBlobsFlat({
|
||||
includeUncommitedBlobs: true
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.equal(result1.segment.blobItems.length, 1);
|
||||
|
||||
const result2 = await containerURL.listBlobFlatSegment(
|
||||
Aborter.none,
|
||||
undefined
|
||||
);
|
||||
const result2 = (await containerClient.listBlobsFlat().byPage().next())
|
||||
.value;
|
||||
assert.equal(result2.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
it("should only show uncommitted blobs in listBlobHierarchySegment with uncommittedblobs option @loki @sql", async () => {
|
||||
const delimiter = "/";
|
||||
const blobURL = BlobURL.fromContainerURL(
|
||||
containerURL,
|
||||
const blobClient = containerClient.getBlobClient(
|
||||
getUniqueName("path/uncommittedblob")
|
||||
);
|
||||
const blockBlobURL = BlockBlobURL.fromBlobURL(blobURL);
|
||||
const blockBlobClient = blobClient.getBlockBlobClient();
|
||||
|
||||
const body = "HelloWorld";
|
||||
await blockBlobURL.stageBlock(
|
||||
Aborter.none,
|
||||
base64encode("1"),
|
||||
body,
|
||||
body.length
|
||||
);
|
||||
await blockBlobClient.stageBlock(base64encode("1"), body, body.length);
|
||||
|
||||
const result1 = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
delimiter,
|
||||
undefined,
|
||||
{
|
||||
include: ["uncommittedblobs"]
|
||||
}
|
||||
);
|
||||
const result1 = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy(delimiter, {
|
||||
includeUncommitedBlobs: true
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.equal(result1.segment.blobPrefixes!.length, 1);
|
||||
|
||||
const result2 = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
delimiter,
|
||||
undefined
|
||||
);
|
||||
const result2 = (
|
||||
await containerClient.listBlobsByHierarchy(delimiter).byPage().next()
|
||||
).value;
|
||||
assert.equal(result2.segment.blobPrefixes!.length, 0);
|
||||
});
|
||||
|
||||
it("should correctly order all blobs in the container @loki @sql", async () => {
|
||||
const blobURLs = [];
|
||||
const blobClients = [];
|
||||
const blobNames: Array<string> = [];
|
||||
|
||||
for (let i = 1; i < 4; i++) {
|
||||
const name = `blockblob${i}/abc-00${i}`;
|
||||
const blobURL = BlobURL.fromContainerURL(containerURL, name);
|
||||
const blockBlobURL = BlockBlobURL.fromBlobURL(blobURL);
|
||||
await blockBlobURL.upload(Aborter.none, "", 0);
|
||||
blobURLs.push(blobURL);
|
||||
const blobClient = containerClient.getBlobClient(name);
|
||||
const blockBlobClient = blobClient.getBlockBlobClient();
|
||||
await blockBlobClient.upload("", 0);
|
||||
blobClients.push(blobClient);
|
||||
blobNames.push(name);
|
||||
}
|
||||
|
||||
const inputmarker = undefined;
|
||||
const result = await containerURL.listBlobFlatSegment(
|
||||
Aborter.none,
|
||||
inputmarker,
|
||||
{
|
||||
prefix: "blockblob"
|
||||
}
|
||||
);
|
||||
const result = (
|
||||
await containerClient
|
||||
.listBlobsFlat({
|
||||
prefix: "blockblob"
|
||||
})
|
||||
.byPage({ continuationToken: inputmarker })
|
||||
.next()
|
||||
).value;
|
||||
assert.ok(result.serviceEndpoint.length > 0);
|
||||
assert.ok(containerURL.url.indexOf(result.containerName));
|
||||
assert.ok(containerClient.url.indexOf(result.containerName));
|
||||
assert.equal(
|
||||
result._response.request.headers.get("x-ms-client-request-id"),
|
||||
result.clientRequestId
|
||||
|
@ -605,13 +570,13 @@ describe("ContainerAPIs", () => {
|
|||
|
||||
assert.deepStrictEqual(gotNames, blobNames);
|
||||
|
||||
for (const blob of blobURLs) {
|
||||
await blob.delete(Aborter.none);
|
||||
for (const blob of blobClients) {
|
||||
await blob.delete();
|
||||
}
|
||||
});
|
||||
|
||||
it("returns a valid, correct nextMarker @loki @sql", async () => {
|
||||
const blobURLs = [];
|
||||
it("returns a valid, correct continuationToken @loki @sql", async () => {
|
||||
const blobClients = [];
|
||||
let blobNames: Array<string> = [
|
||||
"blockblob/abc-001",
|
||||
"blockblob/abc-004",
|
||||
|
@ -626,26 +591,25 @@ describe("ContainerAPIs", () => {
|
|||
];
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const blobURL = BlobURL.fromContainerURL(containerURL, blobNames[i]);
|
||||
const blockBlobURL = BlockBlobURL.fromBlobURL(blobURL);
|
||||
await blockBlobURL.upload(Aborter.none, "", 0);
|
||||
blobURLs.push(blobURL);
|
||||
const blobClient = containerClient.getBlobClient(blobNames[i]);
|
||||
const blockBlobClient = blobClient.getBlockBlobClient();
|
||||
await blockBlobClient.upload("", 0);
|
||||
blobClients.push(blobClient);
|
||||
}
|
||||
|
||||
// Sort blob names for comparison
|
||||
blobNames = blobNames.sort();
|
||||
|
||||
const inputmarker = undefined;
|
||||
let result = await containerURL.listBlobFlatSegment(
|
||||
Aborter.none,
|
||||
inputmarker,
|
||||
{
|
||||
maxresults: 4
|
||||
}
|
||||
);
|
||||
let result = (
|
||||
await containerClient
|
||||
.listBlobsFlat()
|
||||
.byPage({ continuationToken: inputmarker, maxPageSize: 4 })
|
||||
.next()
|
||||
).value;
|
||||
assert.ok(result.serviceEndpoint.length > 0);
|
||||
assert.ok(containerURL.url.indexOf(result.containerName));
|
||||
assert.equal(result.nextMarker, "blockblob/abc-003");
|
||||
assert.ok(containerClient.url.indexOf(result.containerName));
|
||||
assert.equal(result.continuationToken, "blockblob/abc-003");
|
||||
assert.equal(result.segment.blobItems.length, 4);
|
||||
assert.equal(
|
||||
result._response.request.headers.get("x-ms-client-request-id"),
|
||||
|
@ -658,16 +622,18 @@ describe("ContainerAPIs", () => {
|
|||
gotNames.push(item.name);
|
||||
}
|
||||
|
||||
result = await containerURL.listBlobFlatSegment(
|
||||
Aborter.none,
|
||||
result.nextMarker,
|
||||
{
|
||||
maxresults: 4
|
||||
}
|
||||
);
|
||||
result = (
|
||||
await containerClient
|
||||
.listBlobsFlat()
|
||||
.byPage({
|
||||
continuationToken: result.continuationToken,
|
||||
maxPageSize: 4
|
||||
})
|
||||
.next()
|
||||
).value;
|
||||
assert.ok(result.serviceEndpoint.length > 0);
|
||||
assert.ok(containerURL.url.indexOf(result.containerName));
|
||||
assert.equal(result.nextMarker, "blockblob/abc-007");
|
||||
assert.ok(containerClient.url.indexOf(result.containerName));
|
||||
assert.equal(result.continuationToken, "blockblob/abc-007");
|
||||
assert.equal(result.segment.blobItems.length, 4);
|
||||
assert.equal(
|
||||
result._response.request.headers.get("x-ms-client-request-id"),
|
||||
|
@ -678,16 +644,18 @@ describe("ContainerAPIs", () => {
|
|||
gotNames.push(item.name);
|
||||
}
|
||||
|
||||
result = await containerURL.listBlobFlatSegment(
|
||||
Aborter.none,
|
||||
result.nextMarker,
|
||||
{
|
||||
maxresults: 4
|
||||
}
|
||||
);
|
||||
result = (
|
||||
await containerClient
|
||||
.listBlobsFlat()
|
||||
.byPage({
|
||||
continuationToken: result.continuationToken,
|
||||
maxPageSize: 4
|
||||
})
|
||||
.next()
|
||||
).value;
|
||||
assert.ok(result.serviceEndpoint.length > 0);
|
||||
assert.ok(containerURL.url.indexOf(result.containerName));
|
||||
assert.strictEqual(result.nextMarker, "");
|
||||
assert.ok(containerClient.url.indexOf(result.containerName));
|
||||
assert.strictEqual(result.continuationToken, "");
|
||||
assert.equal(result.segment.blobItems.length, 2);
|
||||
assert.equal(
|
||||
result._response.request.headers.get("x-ms-client-request-id"),
|
||||
|
@ -700,14 +668,14 @@ describe("ContainerAPIs", () => {
|
|||
|
||||
assert.deepStrictEqual(gotNames, blobNames);
|
||||
|
||||
for (const blob of blobURLs) {
|
||||
await blob.delete(Aborter.none);
|
||||
for (const blob of blobClients) {
|
||||
await blob.delete();
|
||||
}
|
||||
});
|
||||
|
||||
it("getAccessPolicy @loki @sql", async () => {
|
||||
const result = await containerURL.getAccessPolicy(Aborter.none);
|
||||
assert.ok(result.eTag!.length > 0);
|
||||
const result = await containerClient.getAccessPolicy();
|
||||
assert.ok(result.etag!.length > 0);
|
||||
assert.ok(result.lastModified);
|
||||
assert.ok(result.requestId);
|
||||
assert.ok(result.version);
|
||||
|
@ -723,15 +691,15 @@ describe("ContainerAPIs", () => {
|
|||
const containerAcl = [
|
||||
{
|
||||
accessPolicy: {
|
||||
expiry: new Date("2018-12-31T11:22:33.4567890Z"),
|
||||
permission: "rwd",
|
||||
start: new Date("2017-12-31T11:22:33.4567890Z")
|
||||
expiresOn: new Date("2018-12-31T11:22:33.4567890Z"),
|
||||
permissions: "rwd",
|
||||
startsOn: new Date("2017-12-31T11:22:33.4567890Z")
|
||||
},
|
||||
id: "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="
|
||||
}
|
||||
];
|
||||
await containerURL.setAccessPolicy(Aborter.none, access, containerAcl);
|
||||
const result = await containerURL.getAccessPolicy(Aborter.none);
|
||||
await containerClient.setAccessPolicy(access, containerAcl);
|
||||
const result = await containerClient.getAccessPolicy();
|
||||
// assert.deepEqual(result.signedIdentifiers, containerAcl);
|
||||
assert.deepEqual(result.blobPublicAccess, access);
|
||||
assert.equal(
|
||||
|
@ -746,24 +714,23 @@ describe("ContainerAPIs", () => {
|
|||
const containerAcl = [
|
||||
{
|
||||
accessPolicy: {
|
||||
expiry: new Date("2018-12-31T11:22:33.4567890Z"),
|
||||
permission: "rwdl",
|
||||
start: new Date("2017-12-31T11:22:33.4567890Z")
|
||||
expiresOn: new Date("2018-12-31T11:22:33.4567890Z"),
|
||||
permissions: "rwdl",
|
||||
startsOn: new Date("2017-12-31T11:22:33.4567890Z")
|
||||
},
|
||||
id: "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="
|
||||
},
|
||||
{
|
||||
accessPolicy: {
|
||||
expiry: new Date("2030-11-31T11:22:33.4567890Z"),
|
||||
permission: "w",
|
||||
start: new Date("2017-12-31T11:22:33.4567890Z")
|
||||
expiresOn: new Date("2030-11-31T11:22:33.4567890Z"),
|
||||
permissions: "w",
|
||||
startsOn: new Date("2017-12-31T11:22:33.4567890Z")
|
||||
},
|
||||
id: "policy2"
|
||||
}
|
||||
];
|
||||
|
||||
const result_set = await containerURL.setAccessPolicy(
|
||||
Aborter.none,
|
||||
const result_set = await containerClient.setAccessPolicy(
|
||||
access,
|
||||
containerAcl
|
||||
);
|
||||
|
@ -771,7 +738,7 @@ describe("ContainerAPIs", () => {
|
|||
result_set._response.request.headers.get("x-ms-client-request-id"),
|
||||
result_set.clientRequestId
|
||||
);
|
||||
const result = await containerURL.getAccessPolicy(Aborter.none);
|
||||
const result = await containerClient.getAccessPolicy();
|
||||
assert.deepEqual(result.signedIdentifiers, containerAcl);
|
||||
assert.deepEqual(result.blobPublicAccess, access);
|
||||
});
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,9 +1,7 @@
|
|||
import {
|
||||
Aborter,
|
||||
ContainerURL,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL
|
||||
BlobServiceClient,
|
||||
newPipeline,
|
||||
StorageSharedKeyCredential
|
||||
} from "@azure/storage-blob";
|
||||
import * as assert from "assert";
|
||||
|
||||
|
@ -27,12 +25,17 @@ describe("ServiceAPIs", () => {
|
|||
const server = factory.createServer();
|
||||
|
||||
const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`;
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
)
|
||||
);
|
||||
|
@ -47,7 +50,7 @@ describe("ServiceAPIs", () => {
|
|||
});
|
||||
|
||||
it("GetServiceProperties @loki @sql", async () => {
|
||||
const result = await serviceURL.getProperties(Aborter.none);
|
||||
const result = await serviceClient.getProperties();
|
||||
|
||||
assert.ok(typeof result.requestId);
|
||||
assert.ok(result.requestId!.length > 0);
|
||||
|
@ -68,7 +71,7 @@ describe("ServiceAPIs", () => {
|
|||
});
|
||||
|
||||
it("Set CORS with empty AllowedHeaders, ExposedHeaders @loki @sql", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "",
|
||||
|
@ -80,16 +83,16 @@ describe("ServiceAPIs", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
const result = await serviceURL.getProperties(Aborter.none);
|
||||
const result = await serviceClient.getProperties();
|
||||
assert.deepStrictEqual(result.cors![0], newCORS);
|
||||
});
|
||||
|
||||
it("SetServiceProperties @loki @sql", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
serviceProperties.logging = {
|
||||
serviceProperties.blobAnalyticsLogging = {
|
||||
deleteProperty: true,
|
||||
read: true,
|
||||
retentionPolicy: {
|
||||
|
@ -140,16 +143,13 @@ describe("ServiceAPIs", () => {
|
|||
};
|
||||
}
|
||||
|
||||
const result_set = await serviceURL.setProperties(
|
||||
Aborter.none,
|
||||
serviceProperties
|
||||
);
|
||||
const result_set = await serviceClient.setProperties(serviceProperties);
|
||||
assert.equal(
|
||||
result_set._response.request.headers.get("x-ms-client-request-id"),
|
||||
result_set.clientRequestId
|
||||
);
|
||||
|
||||
const result = await serviceURL.getProperties(Aborter.none);
|
||||
const result = await serviceClient.getProperties();
|
||||
assert.ok(typeof result.requestId);
|
||||
assert.ok(result.requestId!.length > 0);
|
||||
assert.ok(typeof result.version);
|
||||
|
@ -166,35 +166,27 @@ describe("ServiceAPIs", () => {
|
|||
const containerName1 = `${containerNamePrefix}cc`;
|
||||
const containerName2 = `${containerNamePrefix}aa`;
|
||||
const containerName3 = `${containerNamePrefix}bb`;
|
||||
const containerURL1 = ContainerURL.fromServiceURL(
|
||||
serviceURL,
|
||||
containerName1
|
||||
);
|
||||
const containerURL2 = ContainerURL.fromServiceURL(
|
||||
serviceURL,
|
||||
containerName2
|
||||
);
|
||||
const containerURL3 = ContainerURL.fromServiceURL(
|
||||
serviceURL,
|
||||
containerName3
|
||||
);
|
||||
await containerURL1.create(Aborter.none);
|
||||
await containerURL2.create(Aborter.none);
|
||||
await containerURL3.create(Aborter.none);
|
||||
const result = await serviceURL.listContainersSegment(
|
||||
Aborter.none,
|
||||
undefined,
|
||||
{
|
||||
prefix: containerNamePrefix
|
||||
}
|
||||
);
|
||||
const containerClient1 = serviceClient.getContainerClient(containerName1);
|
||||
const containerClient2 = serviceClient.getContainerClient(containerName2);
|
||||
const containerClient3 = serviceClient.getContainerClient(containerName3);
|
||||
await containerClient1.create();
|
||||
await containerClient2.create();
|
||||
await containerClient3.create();
|
||||
const result = (
|
||||
await serviceClient
|
||||
.listContainers({
|
||||
prefix: containerNamePrefix
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.equal(result.containerItems.length, 3);
|
||||
assert.ok(result.containerItems[0].name.endsWith("aa"));
|
||||
assert.ok(result.containerItems[1].name.endsWith("bb"));
|
||||
assert.ok(result.containerItems[2].name.endsWith("cc"));
|
||||
await containerURL1.delete(Aborter.none);
|
||||
await containerURL2.delete(Aborter.none);
|
||||
await containerURL3.delete(Aborter.none);
|
||||
await containerClient1.delete();
|
||||
await containerClient2.delete();
|
||||
await containerClient3.delete();
|
||||
});
|
||||
|
||||
it("List containers with marker @loki @sql", async () => {
|
||||
|
@ -202,34 +194,26 @@ describe("ServiceAPIs", () => {
|
|||
const containerName1 = `${containerNamePrefix}cc`;
|
||||
const containerName2 = `${containerNamePrefix}aa`;
|
||||
const containerName3 = `${containerNamePrefix}bb`;
|
||||
const containerURL1 = ContainerURL.fromServiceURL(
|
||||
serviceURL,
|
||||
containerName1
|
||||
);
|
||||
const containerURL2 = ContainerURL.fromServiceURL(
|
||||
serviceURL,
|
||||
containerName2
|
||||
);
|
||||
const containerURL3 = ContainerURL.fromServiceURL(
|
||||
serviceURL,
|
||||
containerName3
|
||||
);
|
||||
await containerURL1.create(Aborter.none);
|
||||
await containerURL2.create(Aborter.none);
|
||||
await containerURL3.create(Aborter.none);
|
||||
const result = await serviceURL.listContainersSegment(
|
||||
Aborter.none,
|
||||
containerName2,
|
||||
{
|
||||
prefix: containerNamePrefix
|
||||
}
|
||||
);
|
||||
const containerClient1 = serviceClient.getContainerClient(containerName1);
|
||||
const containerClient2 = serviceClient.getContainerClient(containerName2);
|
||||
const containerClient3 = serviceClient.getContainerClient(containerName3);
|
||||
await containerClient1.create();
|
||||
await containerClient2.create();
|
||||
await containerClient3.create();
|
||||
const result = (
|
||||
await serviceClient
|
||||
.listContainers({
|
||||
prefix: containerNamePrefix
|
||||
})
|
||||
.byPage({ continuationToken: containerName2 })
|
||||
.next()
|
||||
).value;
|
||||
assert.equal(result.containerItems.length, 2);
|
||||
assert.equal(result.containerItems[0].name, containerName3);
|
||||
assert.equal(result.containerItems[1].name, containerName1);
|
||||
await containerURL1.delete(Aborter.none);
|
||||
await containerURL2.delete(Aborter.none);
|
||||
await containerURL3.delete(Aborter.none);
|
||||
await containerClient1.delete();
|
||||
await containerClient2.delete();
|
||||
await containerClient3.delete();
|
||||
});
|
||||
|
||||
it("List containers with marker and max result length less than result size @loki @sql", async () => {
|
||||
|
@ -237,47 +221,43 @@ describe("ServiceAPIs", () => {
|
|||
const containerName1 = `${containerNamePrefix}cc`;
|
||||
const containerName2 = `${containerNamePrefix}aa`;
|
||||
const containerName3 = `${containerNamePrefix}bb`;
|
||||
const containerURL1 = ContainerURL.fromServiceURL(
|
||||
serviceURL,
|
||||
containerName1
|
||||
);
|
||||
const containerURL2 = ContainerURL.fromServiceURL(
|
||||
serviceURL,
|
||||
containerName2
|
||||
);
|
||||
const containerURL3 = ContainerURL.fromServiceURL(
|
||||
serviceURL,
|
||||
containerName3
|
||||
);
|
||||
await containerURL1.create(Aborter.none);
|
||||
await containerURL2.create(Aborter.none);
|
||||
await containerURL3.create(Aborter.none);
|
||||
const result1 = await serviceURL.listContainersSegment(
|
||||
Aborter.none,
|
||||
containerName2,
|
||||
{ maxresults: 1, prefix: containerNamePrefix }
|
||||
);
|
||||
const containerClient1 = serviceClient.getContainerClient(containerName1);
|
||||
const containerClient2 = serviceClient.getContainerClient(containerName2);
|
||||
const containerClient3 = serviceClient.getContainerClient(containerName3);
|
||||
await containerClient1.create();
|
||||
await containerClient2.create();
|
||||
await containerClient3.create();
|
||||
const result1 = (
|
||||
await serviceClient
|
||||
.listContainers({ prefix: containerNamePrefix })
|
||||
.byPage({ continuationToken: containerName2, maxPageSize: 1 })
|
||||
.next()
|
||||
).value;
|
||||
|
||||
assert.equal(result1.containerItems.length, 1);
|
||||
assert.equal(result1.containerItems[0].name, containerName3);
|
||||
assert.equal(result1.nextMarker, containerName3);
|
||||
assert.equal(result1.continuationToken, containerName3);
|
||||
|
||||
const result2 = await serviceURL.listContainersSegment(
|
||||
Aborter.none,
|
||||
result1.nextMarker,
|
||||
{ maxresults: 1, prefix: containerNamePrefix }
|
||||
);
|
||||
const result2 = (
|
||||
await serviceClient
|
||||
.listContainers({ prefix: containerNamePrefix })
|
||||
.byPage({
|
||||
continuationToken: result1.continuationToken,
|
||||
maxPageSize: 1
|
||||
})
|
||||
.next()
|
||||
).value;
|
||||
assert.equal(result2.containerItems.length, 1);
|
||||
assert.ok(result2.containerItems[0].name, containerName1);
|
||||
assert.equal(result2.nextMarker, "");
|
||||
assert.equal(result2.continuationToken, "");
|
||||
|
||||
await containerURL1.delete(Aborter.none);
|
||||
await containerURL2.delete(Aborter.none);
|
||||
await containerURL3.delete(Aborter.none);
|
||||
await containerClient1.delete();
|
||||
await containerClient2.delete();
|
||||
await containerClient3.delete();
|
||||
});
|
||||
|
||||
it("ListContainers with default parameters @loki @sql", async () => {
|
||||
const result = await serviceURL.listContainersSegment(Aborter.none);
|
||||
const result = (await serviceClient.listContainers().byPage().next()).value;
|
||||
assert.ok(typeof result.requestId);
|
||||
assert.ok(result.requestId!.length > 0);
|
||||
assert.ok(typeof result.version);
|
||||
|
@ -302,28 +282,22 @@ describe("ServiceAPIs", () => {
|
|||
const containerNamePrefix = getUniqueName("container");
|
||||
const containerName1 = `${containerNamePrefix}x1`;
|
||||
const containerName2 = `${containerNamePrefix}x2`;
|
||||
const containerURL1 = ContainerURL.fromServiceURL(
|
||||
serviceURL,
|
||||
containerName1
|
||||
);
|
||||
const containerURL2 = ContainerURL.fromServiceURL(
|
||||
serviceURL,
|
||||
containerName2
|
||||
);
|
||||
await containerURL1.create(Aborter.none, { metadata: { key: "val" } });
|
||||
await containerURL2.create(Aborter.none, { metadata: { key: "val" } });
|
||||
const containerClient1 = serviceClient.getContainerClient(containerName1);
|
||||
const containerClient2 = serviceClient.getContainerClient(containerName2);
|
||||
await containerClient1.create({ metadata: { key: "val" } });
|
||||
await containerClient2.create({ metadata: { key: "val" } });
|
||||
|
||||
const result1 = await serviceURL.listContainersSegment(
|
||||
Aborter.none,
|
||||
undefined,
|
||||
{
|
||||
include: "metadata",
|
||||
maxresults: 1,
|
||||
prefix: containerNamePrefix
|
||||
}
|
||||
);
|
||||
const result1 = (
|
||||
await serviceClient
|
||||
.listContainers({
|
||||
includeMetadata: true,
|
||||
prefix: containerNamePrefix
|
||||
})
|
||||
.byPage({ maxPageSize: 1 })
|
||||
.next()
|
||||
).value;
|
||||
|
||||
assert.ok(result1.nextMarker);
|
||||
assert.ok(result1.continuationToken);
|
||||
assert.equal(result1.containerItems!.length, 1);
|
||||
assert.ok(result1.containerItems![0].name.startsWith(containerNamePrefix));
|
||||
assert.ok(result1.containerItems![0].properties.etag.length > 0);
|
||||
|
@ -344,15 +318,18 @@ describe("ServiceAPIs", () => {
|
|||
result1.clientRequestId
|
||||
);
|
||||
|
||||
const result2 = await serviceURL.listContainersSegment(
|
||||
Aborter.none,
|
||||
result1.nextMarker,
|
||||
{
|
||||
include: "metadata",
|
||||
maxresults: 1,
|
||||
prefix: containerNamePrefix
|
||||
}
|
||||
);
|
||||
const result2 = (
|
||||
await serviceClient
|
||||
.listContainers({
|
||||
includeMetadata: true,
|
||||
prefix: containerNamePrefix
|
||||
})
|
||||
.byPage({
|
||||
continuationToken: result1.continuationToken,
|
||||
maxPageSize: 1
|
||||
})
|
||||
.next()
|
||||
).value;
|
||||
|
||||
assert.equal(result2.containerItems!.length, 1);
|
||||
assert.ok(result2.containerItems![0].name.startsWith(containerNamePrefix));
|
||||
|
@ -370,12 +347,12 @@ describe("ServiceAPIs", () => {
|
|||
);
|
||||
assert.deepEqual(result2.containerItems![0].metadata!.key, "val");
|
||||
|
||||
await containerURL1.delete(Aborter.none);
|
||||
await containerURL2.delete(Aborter.none);
|
||||
await containerClient1.delete();
|
||||
await containerClient2.delete();
|
||||
});
|
||||
|
||||
it("get Account info @loki @sql", async () => {
|
||||
const result = await serviceURL.getAccountInfo(Aborter.none);
|
||||
const result = await serviceClient.getAccountInfo();
|
||||
assert.equal(result.accountKind, EMULATOR_ACCOUNT_KIND);
|
||||
assert.equal(result.skuName, EMULATOR_ACCOUNT_SKUNAME);
|
||||
assert.equal(
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import {
|
||||
Aborter,
|
||||
AnonymousCredential,
|
||||
ContainerURL,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL
|
||||
StorageSharedKeyCredential,
|
||||
newPipeline,
|
||||
BlobServiceClient,
|
||||
AnonymousCredential
|
||||
} from "@azure/storage-blob";
|
||||
import * as assert from "assert";
|
||||
|
||||
|
@ -35,25 +33,27 @@ describe("Authentication", () => {
|
|||
});
|
||||
|
||||
it(`Should not work without credential @loki @sql`, async () => {
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new AnonymousCredential(), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
newPipeline(new AnonymousCredential(), {
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
})
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
|
||||
let err;
|
||||
try {
|
||||
await containerURL.create(Aborter.none);
|
||||
await containerClient.create();
|
||||
} catch (error) {
|
||||
err = error;
|
||||
} finally {
|
||||
if (err === undefined) {
|
||||
try {
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.delete();
|
||||
} catch (error) {
|
||||
/* Noop */
|
||||
}
|
||||
|
@ -63,28 +63,30 @@ describe("Authentication", () => {
|
|||
});
|
||||
|
||||
it(`Should not work without correct account name @loki @sql`, async () => {
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential("invalid", EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential("invalid", EMULATOR_ACCOUNT_KEY),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
|
||||
let err;
|
||||
try {
|
||||
await containerURL.create(Aborter.none);
|
||||
await containerClient.create();
|
||||
} catch (error) {
|
||||
err = error;
|
||||
} finally {
|
||||
if (err === undefined) {
|
||||
try {
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.delete();
|
||||
} catch (error) {
|
||||
/* Noop */
|
||||
}
|
||||
|
@ -94,28 +96,30 @@ describe("Authentication", () => {
|
|||
});
|
||||
|
||||
it(`Should not work without correct account key @loki @sql`, async () => {
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, "invalidkey"),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(EMULATOR_ACCOUNT_NAME, "invalidkey"),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
|
||||
let err;
|
||||
try {
|
||||
await containerURL.create(Aborter.none);
|
||||
await containerClient.create();
|
||||
} catch (error) {
|
||||
err = error;
|
||||
} finally {
|
||||
if (err === undefined) {
|
||||
try {
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.delete();
|
||||
} catch (error) {
|
||||
/* Noop */
|
||||
}
|
||||
|
@ -125,20 +129,25 @@ describe("Authentication", () => {
|
|||
});
|
||||
|
||||
it(`Should work with correct shared key @loki @sql`, async () => {
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
|
||||
await containerURL.create(Aborter.none);
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.create();
|
||||
await containerClient.delete();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import {
|
||||
Aborter,
|
||||
ContainerURL,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL
|
||||
newPipeline,
|
||||
BlobServiceClient,
|
||||
StorageSharedKeyCredential
|
||||
} from "@azure/storage-blob";
|
||||
import * as assert from "assert";
|
||||
|
||||
|
@ -25,12 +23,17 @@ describe("Blob Cors requests test", () => {
|
|||
const server = factory.createServer();
|
||||
|
||||
const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`;
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
)
|
||||
);
|
||||
|
@ -45,41 +48,46 @@ describe("Blob Cors requests test", () => {
|
|||
});
|
||||
|
||||
it("OPTIONS request without cors rules in server should be fail @loki @sql", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
serviceProperties.cors = [];
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
const origin = "Origin";
|
||||
const requestMethod = "GET";
|
||||
|
||||
const pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
const pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod)
|
||||
);
|
||||
const serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
const serviceClientForOptions = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
await serviceClientForOptions.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error.statusCode === 403);
|
||||
assert.ok(
|
||||
error.body.message.includes(
|
||||
error.message.includes(
|
||||
"CORS not enabled or no matching rule found for this request."
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it("OPTIONS request should not work without matching cors rules @loki @sql", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "header",
|
||||
|
@ -91,34 +99,39 @@ describe("Blob Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
let origin = "Origin";
|
||||
let requestMethod = "GET";
|
||||
|
||||
let pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
let pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod)
|
||||
);
|
||||
let serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
let serviceClientForOptions = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
await serviceClientForOptions.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error.statusCode === 403);
|
||||
assert.ok(
|
||||
error.body.message.includes(
|
||||
error.message.includes(
|
||||
"CORS not enabled or no matching rule found for this request."
|
||||
)
|
||||
);
|
||||
|
@ -126,23 +139,28 @@ describe("Blob Cors requests test", () => {
|
|||
origin = "test";
|
||||
requestMethod = "GET";
|
||||
|
||||
pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod)
|
||||
);
|
||||
serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
serviceClientForOptions = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
const res = await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
const res = await serviceClientForOptions.getProperties();
|
||||
assert.ok(res._response.status === 200);
|
||||
});
|
||||
|
||||
it("OPTIONS request should not work without Origin header or matching allowedOrigins @loki @sql", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "header",
|
||||
|
@ -154,65 +172,75 @@ describe("Blob Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "Origin";
|
||||
const requestMethod = "GET";
|
||||
|
||||
let pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
let pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod)
|
||||
);
|
||||
let serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
let serviceClientForOptions = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
await serviceClientForOptions.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error.statusCode === 403);
|
||||
assert.ok(
|
||||
error.body.message.includes(
|
||||
error.message.includes(
|
||||
"CORS not enabled or no matching rule found for this request."
|
||||
)
|
||||
);
|
||||
|
||||
pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(undefined, requestMethod)
|
||||
);
|
||||
serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
serviceClientForOptions = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
try {
|
||||
await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
await serviceClientForOptions.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error.statusCode === 403);
|
||||
assert.ok(
|
||||
error.body.message.includes(
|
||||
error.message.includes(
|
||||
"CORS not enabled or no matching rule found for this request."
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it("OPTIONS request should not work without requestMethod header or matching allowedMethods @loki @sql", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "header",
|
||||
|
@ -224,63 +252,71 @@ describe("Blob Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "test";
|
||||
const requestMethod = "PUT";
|
||||
|
||||
let pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
let pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod)
|
||||
);
|
||||
let serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
let serviceClientForOptions = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
await serviceClientForOptions.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error.statusCode === 403);
|
||||
assert.ok(
|
||||
error.body.message.includes(
|
||||
error.message.includes(
|
||||
"CORS not enabled or no matching rule found for this request."
|
||||
)
|
||||
);
|
||||
|
||||
pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, undefined)
|
||||
);
|
||||
serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
serviceClientForOptions = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
try {
|
||||
await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
await serviceClientForOptions.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error.statusCode === 400);
|
||||
assert.ok(
|
||||
error.body.message.includes("A required CORS header is not present.")
|
||||
);
|
||||
assert.ok(error.message.includes("A required CORS header is not present."));
|
||||
});
|
||||
|
||||
it("OPTIONS request should check the defined requestHeaders @loki @sql", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = [
|
||||
{
|
||||
|
@ -308,7 +344,7 @@ describe("Blob Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = newCORS;
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
|
@ -317,27 +353,32 @@ describe("Blob Cors requests test", () => {
|
|||
let requestMethod = "GET";
|
||||
let reqestHeaders = "head";
|
||||
|
||||
let pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
let pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod, reqestHeaders)
|
||||
);
|
||||
let serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
let serviceClientForOptions = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
await serviceClientForOptions.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error.statusCode === 403);
|
||||
assert.ok(
|
||||
error.body.message.includes(
|
||||
error.message.includes(
|
||||
"CORS not enabled or no matching rule found for this request."
|
||||
)
|
||||
);
|
||||
|
@ -347,18 +388,23 @@ describe("Blob Cors requests test", () => {
|
|||
requestMethod = "GET";
|
||||
reqestHeaders = "header";
|
||||
|
||||
pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod, reqestHeaders)
|
||||
);
|
||||
serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
serviceClientForOptions = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
let res = await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
let res = await serviceClientForOptions.getProperties();
|
||||
assert.ok(res._response.status === 200);
|
||||
|
||||
// Match second cors.
|
||||
|
@ -366,18 +412,23 @@ describe("Blob Cors requests test", () => {
|
|||
requestMethod = "PUT";
|
||||
reqestHeaders = "head";
|
||||
|
||||
pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod, reqestHeaders)
|
||||
);
|
||||
serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
serviceClientForOptions = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
res = await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
res = await serviceClientForOptions.getProperties();
|
||||
assert.ok(res._response.status === 200);
|
||||
|
||||
// No match.
|
||||
|
@ -385,27 +436,32 @@ describe("Blob Cors requests test", () => {
|
|||
requestMethod = "POST";
|
||||
reqestHeaders = "hea";
|
||||
|
||||
pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod, reqestHeaders)
|
||||
);
|
||||
serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
serviceClientForOptions = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
error;
|
||||
try {
|
||||
await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
await serviceClientForOptions.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error.statusCode === 403);
|
||||
assert.ok(
|
||||
error.body.message.includes(
|
||||
error.message.includes(
|
||||
"CORS not enabled or no matching rule found for this request."
|
||||
)
|
||||
);
|
||||
|
@ -415,23 +471,28 @@ describe("Blob Cors requests test", () => {
|
|||
requestMethod = "POST";
|
||||
reqestHeaders = "headerheader";
|
||||
|
||||
pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod, reqestHeaders)
|
||||
);
|
||||
serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
serviceClientForOptions = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
res = await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
res = await serviceClientForOptions.getProperties();
|
||||
assert.ok(res._response.status === 200);
|
||||
});
|
||||
|
||||
it("OPTIONS request should work with matching rule containing Origion * @loki @sql", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "header",
|
||||
|
@ -443,48 +504,58 @@ describe("Blob Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "anyOrigin";
|
||||
const requestMethod = "GET";
|
||||
|
||||
const pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
const pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod)
|
||||
);
|
||||
const serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
const serviceClientForOptions = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
const res = await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
const res = await serviceClientForOptions.getProperties();
|
||||
assert.ok(res._response.status === 200);
|
||||
});
|
||||
|
||||
it("Response of request to service without cors rules should not contains cors info @loki @sql", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
serviceProperties.cors = [];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "anyOrigin";
|
||||
const pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
const pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(new OriginPolicyFactory(origin));
|
||||
const serviceURLwithOrigin = new ServiceURL(baseURL, pipeline);
|
||||
const serviceClientWithOrigin = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
const res: any = await serviceURLwithOrigin.getProperties(Aborter.none);
|
||||
const res: any = await serviceClientWithOrigin.getProperties();
|
||||
|
||||
assert.ok(res["access-control-allow-origin"] === undefined);
|
||||
assert.ok(res["access-control-expose-headers"] === undefined);
|
||||
|
@ -492,7 +563,7 @@ describe("Blob Cors requests test", () => {
|
|||
});
|
||||
|
||||
it("Service with mismatching cors rules should response header Vary @loki @sql", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "header",
|
||||
|
@ -504,29 +575,34 @@ describe("Blob Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "anyOrigin";
|
||||
const pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
const pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(new OriginPolicyFactory(origin));
|
||||
const serviceURLwithOrigin = new ServiceURL(baseURL, pipeline);
|
||||
const serviceClientWithOrigin = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
let res: any = await serviceURLwithOrigin.getProperties(Aborter.none);
|
||||
let res: any = await serviceClientWithOrigin.getProperties();
|
||||
assert.ok(res.vary !== undefined);
|
||||
|
||||
res = await serviceURL.getProperties(Aborter.none);
|
||||
res = await serviceClient.getProperties();
|
||||
assert.ok(res.vary === undefined);
|
||||
});
|
||||
|
||||
it("Request Match rule exists that allows all origins (*) @loki @sql", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "header",
|
||||
|
@ -538,33 +614,38 @@ describe("Blob Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "anyOrigin";
|
||||
const pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
const pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(new OriginPolicyFactory(origin));
|
||||
const serviceURLwithOrigin = new ServiceURL(baseURL, pipeline);
|
||||
const serviceClientWithOrigin = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
let res: any = await serviceURLwithOrigin.getProperties(Aborter.none);
|
||||
let res: any = await serviceClientWithOrigin.getProperties();
|
||||
assert.ok(res["access-control-allow-origin"] === "*");
|
||||
assert.ok(res.vary === undefined);
|
||||
assert.ok(res["access-control-expose-headers"] !== undefined);
|
||||
|
||||
res = await serviceURL.getProperties(Aborter.none);
|
||||
res = await serviceClient.getProperties();
|
||||
assert.ok(res["access-control-allow-origin"] === undefined);
|
||||
assert.ok(res.vary === undefined);
|
||||
assert.ok(res["access-control-expose-headers"] === undefined);
|
||||
});
|
||||
|
||||
it("Request Match rule exists for exact origin @loki @sql", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "header",
|
||||
|
@ -576,28 +657,33 @@ describe("Blob Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "exactOrigin";
|
||||
const pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
const pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(new OriginPolicyFactory(origin));
|
||||
const serviceURLwithOrigin = new ServiceURL(baseURL, pipeline);
|
||||
const serviceClientWithOrigin = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
const res: any = await serviceURLwithOrigin.getProperties(Aborter.none);
|
||||
const res: any = await serviceClientWithOrigin.getProperties();
|
||||
assert.ok(res["access-control-allow-origin"] === origin);
|
||||
assert.ok(res.vary !== undefined);
|
||||
assert.ok(res["access-control-expose-headers"] !== undefined);
|
||||
});
|
||||
|
||||
it("Requests with error response should apply for CORS @loki @sql", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "header",
|
||||
|
@ -609,27 +695,31 @@ describe("Blob Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "exactOrigin";
|
||||
const pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
const pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(new OriginPolicyFactory(origin));
|
||||
const serviceURLwithOrigin = new ServiceURL(baseURL, pipeline);
|
||||
const serviceClientWithOrigin = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
const containerURLwithOrigin = ContainerURL.fromServiceURL(
|
||||
serviceURLwithOrigin,
|
||||
const containerClientWithOrigin = serviceClientWithOrigin.getContainerClient(
|
||||
"notexistcontainer"
|
||||
);
|
||||
|
||||
try {
|
||||
await containerURLwithOrigin.getProperties(Aborter.none);
|
||||
await containerClientWithOrigin.getProperties();
|
||||
} catch (err) {
|
||||
assert.ok(
|
||||
err.response.headers._headersMap["access-control-allow-origin"]
|
||||
|
@ -644,7 +734,7 @@ describe("Blob Cors requests test", () => {
|
|||
});
|
||||
|
||||
it("Request Match rule in sequence @loki @sql", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = [
|
||||
{
|
||||
|
@ -665,21 +755,26 @@ describe("Blob Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = newCORS;
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "exactOrigin";
|
||||
const pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
const pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(new OriginPolicyFactory(origin));
|
||||
const serviceURLwithOrigin = new ServiceURL(baseURL, pipeline);
|
||||
const serviceClientWithOrigin = new BlobServiceClient(baseURL, pipeline);
|
||||
|
||||
const res: any = await serviceURLwithOrigin.getProperties(Aborter.none);
|
||||
const res: any = await serviceClientWithOrigin.getProperties();
|
||||
assert.ok(res["access-control-allow-origin"] === origin);
|
||||
assert.ok(res.vary !== undefined);
|
||||
assert.ok(res["access-control-expose-headers"] !== undefined);
|
||||
|
|
|
@ -1,14 +1,8 @@
|
|||
import { AbortController } from "@azure/abort-controller";
|
||||
import {
|
||||
Aborter,
|
||||
BlobURL,
|
||||
BlockBlobURL,
|
||||
ContainerURL,
|
||||
downloadBlobToBuffer,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL,
|
||||
uploadFileToBlockBlob,
|
||||
uploadStreamToBlockBlob
|
||||
BlobServiceClient,
|
||||
newPipeline,
|
||||
StorageSharedKeyCredential
|
||||
} from "@azure/storage-blob";
|
||||
import assert = require("assert");
|
||||
import * as fs from "fs";
|
||||
|
@ -36,38 +30,44 @@ describe("BlockBlobHighlevel", () => {
|
|||
const server = factory.createServer(true);
|
||||
|
||||
const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`;
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
let containerName = getUniqueName("container");
|
||||
let containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
let containerClient = serviceClient.getContainerClient(containerName);
|
||||
let blobName = getUniqueName("blob");
|
||||
let blobURL = BlobURL.fromContainerURL(containerURL, blobName);
|
||||
let blockBlobURL = BlockBlobURL.fromBlobURL(blobURL);
|
||||
let blobClient = containerClient.getBlobClient(blobName);
|
||||
let blockBlobClient = blobClient.getBlockBlobClient();
|
||||
let tempFileSmall: string;
|
||||
let tempFileSmallLength: number;
|
||||
let tempFileLarge: string;
|
||||
let tempFileLargeLength: number;
|
||||
const tempFolderPath = "temp";
|
||||
const timeoutForLargeFileUploadingTest = 20 * 60 * 1000;
|
||||
|
||||
beforeEach(async () => {
|
||||
containerName = getUniqueName("container");
|
||||
containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
await containerURL.create(Aborter.none);
|
||||
containerClient = serviceClient.getContainerClient(containerName);
|
||||
await containerClient.create();
|
||||
blobName = getUniqueName("blob");
|
||||
blobURL = BlobURL.fromContainerURL(containerURL, blobName);
|
||||
blockBlobURL = BlockBlobURL.fromBlobURL(blobURL);
|
||||
blobClient = containerClient.getBlobClient(blobName);
|
||||
blockBlobClient = blobClient.getBlockBlobClient();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await containerURL.delete(Aborter.none);
|
||||
afterEach(async function () {
|
||||
await containerClient.delete();
|
||||
});
|
||||
|
||||
before(async () => {
|
||||
|
@ -100,22 +100,17 @@ describe("BlockBlobHighlevel", () => {
|
|||
await server.clean();
|
||||
});
|
||||
|
||||
it("uploadFileToBlockBlob should success when blob >= BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES @loki @sql", async () => {
|
||||
const result = await uploadFileToBlockBlob(
|
||||
Aborter.none,
|
||||
tempFileLarge,
|
||||
blockBlobURL,
|
||||
{
|
||||
blockSize: 4 * 1024 * 1024,
|
||||
parallelism: 20
|
||||
}
|
||||
);
|
||||
it("uploadFile should success when blob >= BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES @loki @sql", async () => {
|
||||
const result = await blockBlobClient.uploadFile(tempFileLarge, {
|
||||
blockSize: 4 * 1024 * 1024,
|
||||
concurrency: 20
|
||||
});
|
||||
assert.equal(
|
||||
result._response.request.headers.get("x-ms-client-request-id"),
|
||||
result.clientRequestId
|
||||
);
|
||||
|
||||
const downloadResponse = await blockBlobURL.download(Aborter.none, 0);
|
||||
const downloadResponse = await blockBlobClient.download(0);
|
||||
const downloadedFile = join(tempFolderPath, getUniqueName("downloadfile."));
|
||||
await readStreamToLocalFile(
|
||||
downloadResponse.readableStreamBody!,
|
||||
|
@ -127,15 +122,15 @@ describe("BlockBlobHighlevel", () => {
|
|||
|
||||
fs.unlinkSync(downloadedFile);
|
||||
assert.ok(downloadedData.equals(uploadedData));
|
||||
});
|
||||
}).timeout(timeoutForLargeFileUploadingTest);
|
||||
|
||||
it("uploadFileToBlockBlob should success when blob < BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES @loki @sql", async () => {
|
||||
await uploadFileToBlockBlob(Aborter.none, tempFileSmall, blockBlobURL, {
|
||||
it("uploadFile should success when blob < BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES @loki @sql", async () => {
|
||||
await blockBlobClient.uploadFile(tempFileSmall, {
|
||||
blockSize: 4 * 1024 * 1024,
|
||||
parallelism: 20
|
||||
concurrency: 20
|
||||
});
|
||||
|
||||
const downloadResponse = await blockBlobURL.download(Aborter.none, 0);
|
||||
const downloadResponse = await blockBlobClient.download(0);
|
||||
const downloadedFile = join(tempFolderPath, getUniqueName("downloadfile."));
|
||||
await readStreamToLocalFile(
|
||||
downloadResponse.readableStreamBody!,
|
||||
|
@ -150,12 +145,12 @@ describe("BlockBlobHighlevel", () => {
|
|||
});
|
||||
|
||||
// tslint:disable-next-line:max-line-length
|
||||
it("uploadFileToBlockBlob should success when blob < BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES and configured maxSingleShotSize @loki @sql", async () => {
|
||||
await uploadFileToBlockBlob(Aborter.none, tempFileSmall, blockBlobURL, {
|
||||
it("uploadFile should success when blob < BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES and configured maxSingleShotSize @loki @sql", async () => {
|
||||
await blockBlobClient.uploadFile(tempFileSmall, {
|
||||
maxSingleShotSize: 0
|
||||
});
|
||||
|
||||
const downloadResponse = await blockBlobURL.download(Aborter.none, 0);
|
||||
const downloadResponse = await blockBlobClient.download(0);
|
||||
const downloadedFile = join(tempFolderPath, getUniqueName("downloadfile."));
|
||||
await readStreamToLocalFile(
|
||||
downloadResponse.readableStreamBody!,
|
||||
|
@ -170,15 +165,15 @@ describe("BlockBlobHighlevel", () => {
|
|||
});
|
||||
|
||||
// tslint:disable-next-line: max-line-length
|
||||
it("uploadFileToBlockBlob should update progress when blob >= BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES @loki @sql", async () => {
|
||||
it("uploadFile should update progress when blob >= BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES @loki @sql", async () => {
|
||||
let eventTriggered = false;
|
||||
const aborter = Aborter.none;
|
||||
const aborter = new AbortController();
|
||||
|
||||
try {
|
||||
await uploadFileToBlockBlob(aborter, tempFileLarge, blockBlobURL, {
|
||||
await blockBlobClient.uploadFile(tempFileLarge, {
|
||||
blockSize: 4 * 1024 * 1024,
|
||||
parallelism: 20,
|
||||
progress: ev => {
|
||||
concurrency: 20,
|
||||
onProgress: (ev: any) => {
|
||||
assert.ok(ev.loadedBytes);
|
||||
eventTriggered = true;
|
||||
aborter.abort();
|
||||
|
@ -186,18 +181,18 @@ describe("BlockBlobHighlevel", () => {
|
|||
});
|
||||
} catch (err) {}
|
||||
assert.ok(eventTriggered);
|
||||
});
|
||||
}).timeout(timeoutForLargeFileUploadingTest);
|
||||
|
||||
// tslint:disable-next-line: max-line-length
|
||||
it("uploadFileToBlockBlob should update progress when blob < BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES @loki @sql", async () => {
|
||||
it("uploadFile should update progress when blob < BLOCK_BLOB_MAX_UPLOAD_BLOB_BYTES @loki @sql", async () => {
|
||||
let eventTriggered = false;
|
||||
const aborter = Aborter.none;
|
||||
const aborter = new AbortController();
|
||||
|
||||
try {
|
||||
await uploadFileToBlockBlob(aborter, tempFileSmall, blockBlobURL, {
|
||||
await blockBlobClient.uploadFile(tempFileSmall, {
|
||||
blockSize: 4 * 1024 * 1024,
|
||||
parallelism: 20,
|
||||
progress: ev => {
|
||||
concurrency: 20,
|
||||
onProgress: (ev: any) => {
|
||||
assert.ok(ev.loadedBytes);
|
||||
eventTriggered = true;
|
||||
aborter.abort();
|
||||
|
@ -207,21 +202,15 @@ describe("BlockBlobHighlevel", () => {
|
|||
assert.ok(eventTriggered);
|
||||
});
|
||||
|
||||
it("uploadStreamToBlockBlob should success @loki @sql", async () => {
|
||||
it("uploadStream should success @loki @sql", async () => {
|
||||
const rs = fs.createReadStream(tempFileLarge);
|
||||
const result = await uploadStreamToBlockBlob(
|
||||
Aborter.none,
|
||||
rs,
|
||||
blockBlobURL,
|
||||
4 * 1024 * 1024,
|
||||
20
|
||||
);
|
||||
const result = await blockBlobClient.uploadStream(rs, 4 * 1024 * 1024, 20);
|
||||
assert.equal(
|
||||
result._response.request.headers.get("x-ms-client-request-id"),
|
||||
result.clientRequestId
|
||||
);
|
||||
|
||||
const downloadResponse = await blockBlobURL.download(Aborter.none, 0);
|
||||
const downloadResponse = await blockBlobClient.download(0);
|
||||
|
||||
const downloadFilePath = join(
|
||||
tempFolderPath,
|
||||
|
@ -239,20 +228,14 @@ describe("BlockBlobHighlevel", () => {
|
|||
fs.unlinkSync(downloadFilePath);
|
||||
});
|
||||
|
||||
it("uploadStreamToBlockBlob should success for tiny buffers @loki @sql", async () => {
|
||||
it("uploadStream should success for tiny buffers @loki @sql", async () => {
|
||||
const buf = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]);
|
||||
const bufferStream = new PassThrough();
|
||||
bufferStream.end(buf);
|
||||
|
||||
await uploadStreamToBlockBlob(
|
||||
Aborter.none,
|
||||
bufferStream,
|
||||
blockBlobURL,
|
||||
4 * 1024 * 1024,
|
||||
20
|
||||
);
|
||||
await blockBlobClient.uploadStream(bufferStream, 4 * 1024 * 1024, 20);
|
||||
|
||||
const downloadResponse = await blockBlobURL.download(Aborter.none, 0);
|
||||
const downloadResponse = await blockBlobClient.download(0);
|
||||
|
||||
const downloadFilePath = join(
|
||||
tempFolderPath,
|
||||
|
@ -269,121 +252,92 @@ describe("BlockBlobHighlevel", () => {
|
|||
fs.unlinkSync(downloadFilePath);
|
||||
});
|
||||
|
||||
it("uploadStreamToBlockBlob should abort @loki @sql", async () => {
|
||||
it("uploadStream should abort @loki @sql", async () => {
|
||||
const rs = fs.createReadStream(tempFileLarge);
|
||||
const aborter = Aborter.timeout(1);
|
||||
|
||||
try {
|
||||
await uploadStreamToBlockBlob(
|
||||
aborter,
|
||||
rs,
|
||||
blockBlobURL,
|
||||
4 * 1024 * 1024,
|
||||
20
|
||||
);
|
||||
await blockBlobClient.uploadStream(rs, 4 * 1024 * 1024, 20, {
|
||||
abortSignal: AbortController.timeout(1)
|
||||
});
|
||||
assert.fail();
|
||||
} catch (err) {
|
||||
assert.ok((err.code as string).toLowerCase().includes("abort"));
|
||||
assert.ok((err.message as string).toLowerCase().includes("abort"));
|
||||
}
|
||||
});
|
||||
}).timeout(timeoutForLargeFileUploadingTest);
|
||||
|
||||
it("uploadStreamToBlockBlob should update progress event @loki @sql", async () => {
|
||||
it("uploadStream should update progress event @loki @sql", async () => {
|
||||
const rs = fs.createReadStream(tempFileLarge);
|
||||
let eventTriggered = false;
|
||||
|
||||
await uploadStreamToBlockBlob(
|
||||
Aborter.none,
|
||||
rs,
|
||||
blockBlobURL,
|
||||
4 * 1024 * 1024,
|
||||
20,
|
||||
{
|
||||
progress: ev => {
|
||||
assert.ok(ev.loadedBytes);
|
||||
eventTriggered = true;
|
||||
}
|
||||
await blockBlobClient.uploadStream(rs, 4 * 1024 * 1024, 20, {
|
||||
onProgress: (ev: any) => {
|
||||
assert.ok(ev.loadedBytes);
|
||||
eventTriggered = true;
|
||||
}
|
||||
);
|
||||
});
|
||||
assert.ok(eventTriggered);
|
||||
});
|
||||
}).timeout(timeoutForLargeFileUploadingTest);
|
||||
|
||||
it("downloadBlobToBuffer should success @loki @sql", async () => {
|
||||
it("downloadToBuffer should success @loki @sql", async () => {
|
||||
const rs = fs.createReadStream(tempFileLarge);
|
||||
const result = await uploadStreamToBlockBlob(
|
||||
Aborter.none,
|
||||
rs,
|
||||
blockBlobURL,
|
||||
4 * 1024 * 1024,
|
||||
20
|
||||
);
|
||||
const result = await blockBlobClient.uploadStream(rs, 4 * 1024 * 1024, 20);
|
||||
assert.equal(
|
||||
result._response.request.headers.get("x-ms-client-request-id"),
|
||||
result.clientRequestId
|
||||
);
|
||||
|
||||
const buf = Buffer.alloc(tempFileLargeLength);
|
||||
await downloadBlobToBuffer(Aborter.none, buf, blockBlobURL, 0, undefined, {
|
||||
await blockBlobClient.downloadToBuffer(buf, 0, undefined, {
|
||||
blockSize: 4 * 1024 * 1024,
|
||||
maxRetryRequestsPerBlock: 5,
|
||||
parallelism: 20
|
||||
concurrency: 20
|
||||
});
|
||||
|
||||
const localFileContent = fs.readFileSync(tempFileLarge);
|
||||
assert.ok(localFileContent.equals(buf));
|
||||
});
|
||||
}).timeout(timeoutForLargeFileUploadingTest);
|
||||
|
||||
it("downloadBlobToBuffer should update progress event @loki @sql", async () => {
|
||||
it("downloadToBuffer should update progress event @loki @sql", async () => {
|
||||
const rs = fs.createReadStream(tempFileSmall);
|
||||
await uploadStreamToBlockBlob(
|
||||
Aborter.none,
|
||||
rs,
|
||||
blockBlobURL,
|
||||
4 * 1024 * 1024,
|
||||
10
|
||||
);
|
||||
await blockBlobClient.uploadStream(rs, 4 * 1024 * 1024, 10);
|
||||
|
||||
let eventTriggered = false;
|
||||
const buf = Buffer.alloc(tempFileSmallLength);
|
||||
const aborter = Aborter.none;
|
||||
const aborter = new AbortController();
|
||||
try {
|
||||
await downloadBlobToBuffer(aborter, buf, blockBlobURL, 0, undefined, {
|
||||
await blockBlobClient.downloadToBuffer(buf, 0, undefined, {
|
||||
blockSize: 1 * 1024,
|
||||
maxRetryRequestsPerBlock: 5,
|
||||
parallelism: 1,
|
||||
progress: () => {
|
||||
concurrency: 1,
|
||||
onProgress: () => {
|
||||
eventTriggered = true;
|
||||
aborter.abort();
|
||||
}
|
||||
});
|
||||
} catch (err) {}
|
||||
assert.ok(eventTriggered);
|
||||
});
|
||||
}).timeout(timeoutForLargeFileUploadingTest);
|
||||
|
||||
it("bloburl.download should success when internal stream unexpected ends at the stream end @loki @sql", async () => {
|
||||
await uploadFileToBlockBlob(Aborter.none, tempFileSmall, blockBlobURL, {
|
||||
it("blobclient.download should success when internal stream unexpected ends at the stream end @loki @sql", async () => {
|
||||
await blockBlobClient.uploadFile(tempFileSmall, {
|
||||
blockSize: 4 * 1024 * 1024,
|
||||
parallelism: 20
|
||||
concurrency: 20
|
||||
});
|
||||
|
||||
let retirableReadableStreamOptions: any;
|
||||
const downloadResponse = await blockBlobURL.download(
|
||||
Aborter.none,
|
||||
0,
|
||||
undefined,
|
||||
{
|
||||
blobAccessConditions: {
|
||||
// modifiedAccessConditions: {
|
||||
// ifMatch: uploadResponse.eTag
|
||||
// }
|
||||
},
|
||||
maxRetryRequests: 1,
|
||||
progress: ev => {
|
||||
if (ev.loadedBytes >= tempFileSmallLength) {
|
||||
retirableReadableStreamOptions.doInjectErrorOnce = true;
|
||||
}
|
||||
const downloadResponse = await blockBlobClient.download(0, undefined, {
|
||||
conditions: {
|
||||
// modifiedAccessConditions: {
|
||||
// ifMatch: uploadResponse.eTag
|
||||
// }
|
||||
},
|
||||
maxRetryRequests: 1,
|
||||
onProgress: (ev) => {
|
||||
if (ev.loadedBytes >= tempFileSmallLength) {
|
||||
retirableReadableStreamOptions.doInjectErrorOnce = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
assert.equal(
|
||||
downloadResponse._response.request.headers.get("x-ms-client-request-id"),
|
||||
downloadResponse.clientRequestId
|
||||
|
@ -406,32 +360,27 @@ describe("BlockBlobHighlevel", () => {
|
|||
});
|
||||
|
||||
// tslint:disable-next-line: max-line-length
|
||||
it("bloburl.download should download full data successfully when internal stream unexpected ends @loki @sql", async () => {
|
||||
await uploadFileToBlockBlob(Aborter.none, tempFileSmall, blockBlobURL, {
|
||||
it("blobclient.download should download full data successfully when internal stream unexpected ends @loki @sql", async () => {
|
||||
await blockBlobClient.uploadFile(tempFileSmall, {
|
||||
blockSize: 4 * 1024 * 1024,
|
||||
parallelism: 20
|
||||
concurrency: 20
|
||||
});
|
||||
|
||||
let retirableReadableStreamOptions: any;
|
||||
let injectedErrors = 0;
|
||||
const downloadResponse = await blockBlobURL.download(
|
||||
Aborter.none,
|
||||
0,
|
||||
undefined,
|
||||
{
|
||||
blobAccessConditions: {
|
||||
// modifiedAccessConditions: {
|
||||
// ifMatch: uploadResponse.eTag
|
||||
// }
|
||||
},
|
||||
maxRetryRequests: 3,
|
||||
progress: () => {
|
||||
if (injectedErrors++ < 3) {
|
||||
retirableReadableStreamOptions.doInjectErrorOnce = true;
|
||||
}
|
||||
const downloadResponse = await blockBlobClient.download(0, undefined, {
|
||||
conditions: {
|
||||
// modifiedAccessConditions: {
|
||||
// ifMatch: uploadResponse.eTag
|
||||
// }
|
||||
},
|
||||
maxRetryRequests: 3,
|
||||
onProgress: () => {
|
||||
if (injectedErrors++ < 3) {
|
||||
retirableReadableStreamOptions.doInjectErrorOnce = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
retirableReadableStreamOptions = (downloadResponse.readableStreamBody! as any)
|
||||
.options;
|
||||
|
@ -449,34 +398,29 @@ describe("BlockBlobHighlevel", () => {
|
|||
assert.ok(downloadedData.equals(uploadedData));
|
||||
});
|
||||
|
||||
it("bloburl.download should download partial data when internal stream unexpected ends @loki @sql", async () => {
|
||||
await uploadFileToBlockBlob(Aborter.none, tempFileSmall, blockBlobURL, {
|
||||
it("blobclient.download should download partial data when internal stream unexpected ends @loki @sql", async () => {
|
||||
await blockBlobClient.uploadFile(tempFileSmall, {
|
||||
blockSize: 4 * 1024 * 1024,
|
||||
parallelism: 20
|
||||
concurrency: 20
|
||||
});
|
||||
|
||||
const partialSize = 500 * 1024;
|
||||
|
||||
let retirableReadableStreamOptions: any;
|
||||
let injectedErrors = 0;
|
||||
const downloadResponse = await blockBlobURL.download(
|
||||
Aborter.none,
|
||||
0,
|
||||
partialSize,
|
||||
{
|
||||
blobAccessConditions: {
|
||||
// modifiedAccessConditions: {
|
||||
// ifMatch: uploadResponse.eTag
|
||||
// }
|
||||
},
|
||||
maxRetryRequests: 3,
|
||||
progress: () => {
|
||||
if (injectedErrors++ < 3) {
|
||||
retirableReadableStreamOptions.doInjectErrorOnce = true;
|
||||
}
|
||||
const downloadResponse = await blockBlobClient.download(0, partialSize, {
|
||||
conditions: {
|
||||
// modifiedAccessConditions: {
|
||||
// ifMatch: uploadResponse.eTag
|
||||
// }
|
||||
},
|
||||
maxRetryRequests: 3,
|
||||
onProgress: () => {
|
||||
if (injectedErrors++ < 3) {
|
||||
retirableReadableStreamOptions.doInjectErrorOnce = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
retirableReadableStreamOptions = (downloadResponse.readableStreamBody! as any)
|
||||
.options;
|
||||
|
@ -498,10 +442,10 @@ describe("BlockBlobHighlevel", () => {
|
|||
);
|
||||
});
|
||||
|
||||
it("bloburl.download should download data failed when exceeding max stream retry requests @loki @sql", async () => {
|
||||
await uploadFileToBlockBlob(Aborter.none, tempFileSmall, blockBlobURL, {
|
||||
it("blobclient.download should download data failed when exceeding max stream retry requests @loki @sql", async () => {
|
||||
await blockBlobClient.uploadFile(tempFileSmall, {
|
||||
blockSize: 4 * 1024 * 1024,
|
||||
parallelism: 20
|
||||
concurrency: 20
|
||||
});
|
||||
|
||||
const downloadedFile = join(tempFolderPath, getUniqueName("downloadfile."));
|
||||
|
@ -511,24 +455,19 @@ describe("BlockBlobHighlevel", () => {
|
|||
let expectedError = false;
|
||||
|
||||
try {
|
||||
const downloadResponse = await blockBlobURL.download(
|
||||
Aborter.none,
|
||||
0,
|
||||
undefined,
|
||||
{
|
||||
blobAccessConditions: {
|
||||
// modifiedAccessConditions: {
|
||||
// ifMatch: uploadResponse.eTag
|
||||
// }
|
||||
},
|
||||
maxRetryRequests: 0,
|
||||
progress: () => {
|
||||
if (injectedErrors++ < 1) {
|
||||
retirableReadableStreamOptions.doInjectErrorOnce = true;
|
||||
}
|
||||
const downloadResponse = await blockBlobClient.download(0, undefined, {
|
||||
conditions: {
|
||||
// modifiedAccessConditions: {
|
||||
// ifMatch: uploadResponse.eTag
|
||||
// }
|
||||
},
|
||||
maxRetryRequests: 0,
|
||||
onProgress: () => {
|
||||
if (injectedErrors++ < 1) {
|
||||
retirableReadableStreamOptions.doInjectErrorOnce = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
retirableReadableStreamOptions = (downloadResponse.readableStreamBody! as any)
|
||||
.options;
|
||||
await readStreamToLocalFile(
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import {
|
||||
Aborter,
|
||||
ContainerURL,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL
|
||||
BlobServiceClient,
|
||||
newPipeline,
|
||||
StorageSharedKeyCredential
|
||||
} from "@azure/storage-blob";
|
||||
|
||||
import { configLogger } from "../../src/common/Logger";
|
||||
|
@ -32,20 +30,25 @@ describe("Blob HTTPS", () => {
|
|||
});
|
||||
|
||||
it(`Should work with correct shared key using HTTPS endpoint @loki @sql`, async () => {
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
|
||||
await containerURL.create(Aborter.none);
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.create();
|
||||
await containerClient.delete();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
import {
|
||||
Aborter,
|
||||
ContainerURL,
|
||||
ServiceURL,
|
||||
StorageURL,
|
||||
TokenCredential
|
||||
} from "@azure/storage-blob";
|
||||
import { BlobServiceClient, newPipeline } from "@azure/storage-blob";
|
||||
|
||||
import * as assert from "assert";
|
||||
|
||||
import { configLogger } from "../../src/common/Logger";
|
||||
import BlobTestServerFactory from "../BlobTestServerFactory";
|
||||
import { generateJWTToken, getUniqueName } from "../testutils";
|
||||
import { SimpleTokenCredential } from "../simpleTokenCredential";
|
||||
|
||||
// Set true to enable debug log
|
||||
configLogger(false);
|
||||
|
@ -39,34 +34,38 @@ describe("Blob OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
})
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
|
||||
await containerURL.create(Aborter.none);
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.create();
|
||||
await containerClient.delete();
|
||||
});
|
||||
|
||||
it(`Should not work with invalid JWT token @loki @sql`, async () => {
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential("invalid token"), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
newPipeline(new SimpleTokenCredential("invalid token"), {
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
})
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
|
||||
try {
|
||||
await containerURL.create(Aborter.none);
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.create();
|
||||
await containerClient.delete();
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(
|
||||
err.message.includes("AuthenticationFailed"),
|
||||
|
@ -102,21 +101,20 @@ describe("Blob OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
})
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(
|
||||
serviceURL,
|
||||
containerName
|
||||
);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
|
||||
await containerURL.create(Aborter.none);
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.create();
|
||||
await containerClient.delete();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -130,19 +128,21 @@ describe("Blob OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
})
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
|
||||
try {
|
||||
await containerURL.create(Aborter.none);
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.create();
|
||||
await containerClient.delete();
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(
|
||||
err.message.includes("AuthenticationFailed"),
|
||||
|
@ -172,21 +172,20 @@ describe("Blob OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
})
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(
|
||||
serviceURL,
|
||||
containerName
|
||||
);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
|
||||
await containerURL.create(Aborter.none);
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.create();
|
||||
await containerClient.delete();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -200,19 +199,21 @@ describe("Blob OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
})
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
|
||||
try {
|
||||
await containerURL.create(Aborter.none);
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.create();
|
||||
await containerClient.delete();
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(
|
||||
err.message.includes("AuthenticationFailed"),
|
||||
|
@ -234,19 +235,21 @@ describe("Blob OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
})
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
|
||||
try {
|
||||
await containerURL.create(Aborter.none);
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.create();
|
||||
await containerClient.delete();
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(
|
||||
err.message.includes("AuthenticationFailed"),
|
||||
|
@ -268,19 +271,21 @@ describe("Blob OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
})
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
|
||||
try {
|
||||
await containerURL.create(Aborter.none);
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.create();
|
||||
await containerClient.delete();
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(
|
||||
err.message.includes("AuthenticationFailed"),
|
||||
|
@ -302,28 +307,30 @@ describe("Blob OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
})
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
await containerURL.create(Aborter.none);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
await containerClient.create();
|
||||
|
||||
try {
|
||||
await containerURL.getAccessPolicy(Aborter.none);
|
||||
await containerClient.getAccessPolicy();
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(
|
||||
err.message.includes("AuthorizationFailure"),
|
||||
true
|
||||
);
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.delete();
|
||||
return;
|
||||
}
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.delete();
|
||||
assert.fail();
|
||||
});
|
||||
|
||||
|
@ -337,28 +344,30 @@ describe("Blob OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
})
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
await containerURL.create(Aborter.none);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
await containerClient.create();
|
||||
|
||||
try {
|
||||
await containerURL.setAccessPolicy(Aborter.none, "container");
|
||||
await containerClient.setAccessPolicy("container");
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(
|
||||
err.message.includes("AuthorizationFailure"),
|
||||
true
|
||||
);
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.delete();
|
||||
return;
|
||||
}
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.delete();
|
||||
assert.fail();
|
||||
});
|
||||
|
||||
|
@ -380,19 +389,21 @@ describe("Blob OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
httpBaseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
})
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
|
||||
try {
|
||||
await containerURL.create(Aborter.none);
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.create();
|
||||
await containerClient.delete();
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(
|
||||
err.message.includes("AuthenticationFailed"),
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,12 +1,10 @@
|
|||
import dns = require("dns");
|
||||
|
||||
import {
|
||||
Aborter,
|
||||
BlockBlobURL,
|
||||
ContainerURL,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL
|
||||
BlobServiceClient,
|
||||
newPipeline,
|
||||
StorageSharedKeyCredential,
|
||||
BlockBlobClient
|
||||
} from "@azure/storage-blob";
|
||||
import assert = require("assert");
|
||||
|
||||
|
@ -29,153 +27,158 @@ describe("SpecialNaming", () => {
|
|||
const baseURL = `http://${server.config.host}:${server.config.port}/devstoreaccount1`;
|
||||
const productionStyleHostName = "devstoreaccount1.localhost"; // Use hosts file to make this resolve
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new BlobServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
const containerName: string = getUniqueName("1container-with-dash");
|
||||
const containerURL = ContainerURL.fromServiceURL(serviceURL, containerName);
|
||||
const containerClient = serviceClient.getContainerClient(containerName);
|
||||
|
||||
before(async () => {
|
||||
await server.start();
|
||||
await containerURL.create(Aborter.none);
|
||||
await containerClient.create();
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await containerURL.delete(Aborter.none);
|
||||
await containerClient.delete();
|
||||
await server.close();
|
||||
await server.clean();
|
||||
});
|
||||
|
||||
it("Should work with special container and blob names with spaces @loki @sql", async () => {
|
||||
const blobName: string = getUniqueName("blob empty");
|
||||
const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, blobName);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobName
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobName
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
it("Should work with special container and blob names with unicode @loki @sql", async () => {
|
||||
const blobName: string = getUniqueName("unicod\u00e9");
|
||||
const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, blobName);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobName
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobName
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
assert.deepStrictEqual(response.segment.blobItems[0].name, blobName);
|
||||
});
|
||||
|
||||
it("Should work with special container and blob names with spaces in URL string @loki @sql", async () => {
|
||||
const blobName: string = getUniqueName("blob empty");
|
||||
const blockBlobURL = new BlockBlobURL(
|
||||
appendToURLPath(containerURL.url, blobName),
|
||||
containerURL.pipeline
|
||||
const blockBlobClient = new BlockBlobClient(
|
||||
appendToURLPath(containerClient.url, blobName),
|
||||
(containerClient as any).pipeline
|
||||
);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobName
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobName
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
it("Should work with special container and blob names with / @loki @sql", async () => {
|
||||
const blobName: string = getUniqueName("////blob/empty /another");
|
||||
const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, blobName);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobName
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobName
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
it("Should work with special container and blob names with / in URL string @loki @sql", async () => {
|
||||
const blobName: string = getUniqueName("////blob/empty /another");
|
||||
const blockBlobURL = new BlockBlobURL(
|
||||
appendToURLPath(containerURL.url, blobName),
|
||||
containerURL.pipeline
|
||||
const blockBlobClient = new BlockBlobClient(
|
||||
appendToURLPath(containerClient.url, blobName),
|
||||
(containerClient as any).pipeline
|
||||
);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobName
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobName
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
it("Should work with special container and blob names uppercase @loki @sql", async () => {
|
||||
const blobName: string = getUniqueName("////Upper/blob/empty /another");
|
||||
const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, blobName);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobName
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobName
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
it("Should work with special container and blob names uppercase in URL string @loki @sql", async () => {
|
||||
const blobName: string = getUniqueName("////Upper/blob/empty /another");
|
||||
const blockBlobURL = new BlockBlobURL(
|
||||
appendToURLPath(containerURL.url, blobName),
|
||||
containerURL.pipeline
|
||||
const blockBlobClient = new BlockBlobClient(
|
||||
appendToURLPath(containerClient.url, blobName),
|
||||
(containerClient as any).pipeline
|
||||
);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobName
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobName
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
|
@ -183,18 +186,18 @@ describe("SpecialNaming", () => {
|
|||
const blobName: string = getUniqueName(
|
||||
"////Upper/blob/empty /another 汉字"
|
||||
);
|
||||
const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, blobName);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobName
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobName
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
|
@ -202,21 +205,21 @@ describe("SpecialNaming", () => {
|
|||
const blobName: string = getUniqueName(
|
||||
"////Upper/blob/empty /another 汉字"
|
||||
);
|
||||
const blockBlobURL = new BlockBlobURL(
|
||||
appendToURLPath(containerURL.url, blobName),
|
||||
containerURL.pipeline
|
||||
const blockBlobClient = new BlockBlobClient(
|
||||
appendToURLPath(containerClient.url, blobName),
|
||||
(containerClient as any).pipeline
|
||||
);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobName
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobName
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
|
@ -224,19 +227,22 @@ describe("SpecialNaming", () => {
|
|||
const blobName: string = getUniqueName(
|
||||
"汉字. special ~!@#$%^&*()_+`1234567890-={}|[]\\:\";'<>?,/'"
|
||||
);
|
||||
const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, blobName);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"b", // A char doesn't exist in blob name
|
||||
undefined,
|
||||
{
|
||||
// NOTICE: Azure Storage Server will replace "\" with "/" in the blob names
|
||||
prefix: blobName.replace(/\\/g, "/")
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy(
|
||||
"b", // A char doesn't exist in blob name
|
||||
{
|
||||
// NOTICE: Azure Storage Server will replace "\" with "/" in the blob names
|
||||
prefix: blobName.replace(/\\/g, "/")
|
||||
}
|
||||
)
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
|
@ -244,241 +250,235 @@ describe("SpecialNaming", () => {
|
|||
const blobName: string = getUniqueName(
|
||||
"汉字. special ~!@#$%^&*()_+`1234567890-={}|[]\\:\";'<>?,/'"
|
||||
);
|
||||
const blockBlobURL = new BlockBlobURL(
|
||||
const blockBlobClient = new BlockBlobClient(
|
||||
// There are 2 special cases for a URL string:
|
||||
// Escape "%" when creating XXXURL object with URL strings
|
||||
// Escape "?" otherwise string after "?" will be treated as URL parameters
|
||||
appendToURLPath(
|
||||
containerURL.url,
|
||||
containerClient.url,
|
||||
blobName.replace(/%/g, "%25").replace(/\?/g, "%3F")
|
||||
),
|
||||
containerURL.pipeline
|
||||
(containerClient as any).pipeline
|
||||
);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"b", // "b" doesn't exist in blob name
|
||||
undefined,
|
||||
{
|
||||
// NOTICE: Azure Storage Server will replace "\" with "/" in the blob names
|
||||
prefix: blobName.replace(/\\/g, "/")
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy(
|
||||
"b", // "b" doesn't exist in blob name
|
||||
{
|
||||
// NOTICE: Azure Storage Server will replace "\" with "/" in the blob names
|
||||
prefix: blobName.replace(/\\/g, "/")
|
||||
}
|
||||
)
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
it("Should work with special blob name Russian URI encoded @loki @sql", async () => {
|
||||
const blobName: string = getUniqueName("ру́сский язы́к");
|
||||
const blobNameEncoded: string = encodeURIComponent(blobName);
|
||||
const blockBlobURL = BlockBlobURL.fromContainerURL(
|
||||
containerURL,
|
||||
blobNameEncoded
|
||||
);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(blobNameEncoded);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobNameEncoded
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobNameEncoded
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
it("Should work with special blob name Russian @loki @sql", async () => {
|
||||
const blobName: string = getUniqueName("ру́сский язы́к");
|
||||
const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, blobName);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobName
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobName
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
it("Should work with special blob name Russian in URL string @loki @sql", async () => {
|
||||
const blobName: string = getUniqueName("ру́сский язы́к");
|
||||
const blockBlobURL = new BlockBlobURL(
|
||||
appendToURLPath(containerURL.url, blobName),
|
||||
containerURL.pipeline
|
||||
const blockBlobClient = new BlockBlobClient(
|
||||
appendToURLPath(containerClient.url, blobName),
|
||||
(containerClient as any).pipeline
|
||||
);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobName
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobName
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
it("Should work with special blob name Arabic URI encoded @loki @sql", async () => {
|
||||
const blobName: string = getUniqueName("عربي/عربى");
|
||||
const blobNameEncoded: string = encodeURIComponent(blobName);
|
||||
const blockBlobURL = BlockBlobURL.fromContainerURL(
|
||||
containerURL,
|
||||
blobNameEncoded
|
||||
);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(blobNameEncoded);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobNameEncoded
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobNameEncoded
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
it("Should work with special blob name Arabic @loki @sql", async () => {
|
||||
const blobName: string = getUniqueName("عربي/عربى");
|
||||
const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, blobName);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobName
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobName
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
it("Should work with special blob name Arabic in URL string @loki @sql", async () => {
|
||||
const blobName: string = getUniqueName("عربي/عربى");
|
||||
const blockBlobURL = new BlockBlobURL(
|
||||
appendToURLPath(containerURL.url, blobName),
|
||||
containerURL.pipeline
|
||||
const blockBlobClient = new BlockBlobClient(
|
||||
appendToURLPath(containerClient.url, blobName),
|
||||
(containerClient as any).pipeline
|
||||
);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobName
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobName
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
it("Should work with special blob name Japanese URI encoded @loki @sql", async () => {
|
||||
const blobName: string = getUniqueName("にっぽんご/にほんご");
|
||||
const blobNameEncoded: string = encodeURIComponent(blobName);
|
||||
const blockBlobURL = BlockBlobURL.fromContainerURL(
|
||||
containerURL,
|
||||
blobNameEncoded
|
||||
);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(blobNameEncoded);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobNameEncoded
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobNameEncoded
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
it("Should work with special blob name Japanese @loki @sql", async () => {
|
||||
const blobName: string = getUniqueName("にっぽんご/にほんご");
|
||||
const blockBlobURL = BlockBlobURL.fromContainerURL(containerURL, blobName);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobName
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobName
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
it("Should work with special blob name Japanese in URL string @loki @sql", async () => {
|
||||
const blobName: string = getUniqueName("にっぽんご/にほんご");
|
||||
const blockBlobURL = new BlockBlobURL(
|
||||
appendToURLPath(containerURL.url, blobName),
|
||||
containerURL.pipeline
|
||||
const blockBlobClient = new BlockBlobClient(
|
||||
appendToURLPath(containerClient.url, blobName),
|
||||
(containerClient as any).pipeline
|
||||
);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "A", 1);
|
||||
await blockBlobURL.getProperties(Aborter.none);
|
||||
const response = await containerURL.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobName
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("A", 1);
|
||||
await blockBlobClient.getProperties();
|
||||
const response = (
|
||||
await containerClient
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobName
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
});
|
||||
|
||||
it(`Should work with production style URL when ${productionStyleHostName} is resolvable`, async () => {
|
||||
await dns.promises.lookup(productionStyleHostName).then(
|
||||
async lookupAddress => {
|
||||
async (lookupAddress) => {
|
||||
const baseURLProductionStyle = `http://${productionStyleHostName}:${server.config.port}`;
|
||||
const serviceURLProductionStyle = new ServiceURL(
|
||||
const serviceClientProductionStyle = new BlobServiceClient(
|
||||
baseURLProductionStyle,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
retryOptions: { maxTries: 1 },
|
||||
// Make sure socket is closed once the operation is done.
|
||||
keepAliveOptions: { enable: false }
|
||||
}
|
||||
)
|
||||
);
|
||||
const containerURLProductionStyle = ContainerURL.fromServiceURL(
|
||||
serviceURLProductionStyle,
|
||||
const containerClientProductionStyle = serviceClientProductionStyle.getContainerClient(
|
||||
containerName
|
||||
);
|
||||
|
||||
const blobName: string = getUniqueName("myblob");
|
||||
const blockBlobURL = BlockBlobURL.fromContainerURL(
|
||||
containerURLProductionStyle,
|
||||
const blockBlobClient = containerClientProductionStyle.getBlockBlobClient(
|
||||
blobName
|
||||
);
|
||||
|
||||
await blockBlobURL.upload(Aborter.none, "ABC", 3);
|
||||
const response = await containerURLProductionStyle.listBlobHierarchySegment(
|
||||
Aborter.none,
|
||||
"$",
|
||||
undefined,
|
||||
{
|
||||
prefix: blobName
|
||||
}
|
||||
);
|
||||
await blockBlobClient.upload("ABC", 3);
|
||||
const response = (
|
||||
await containerClientProductionStyle
|
||||
.listBlobsByHierarchy("$", {
|
||||
prefix: blobName
|
||||
})
|
||||
.byPage()
|
||||
.next()
|
||||
).value;
|
||||
assert.notDeepEqual(response.segment.blobItems.length, 0);
|
||||
},
|
||||
() => {
|
||||
|
|
|
@ -10,12 +10,15 @@ describe("Utils", () => {
|
|||
"x-ms-meta-name2",
|
||||
"234",
|
||||
"x-ms-meta-name1",
|
||||
"Value",
|
||||
"X-Ms-Meta-Name3",
|
||||
"Value"
|
||||
]);
|
||||
assert.deepStrictEqual(metadata, {
|
||||
Name1: "Value",
|
||||
name2: "234",
|
||||
name1: "Value"
|
||||
name1: "Value",
|
||||
Name3: "Value"
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
import * as assert from "assert";
|
||||
|
||||
import {
|
||||
Aborter,
|
||||
MessageIdURL,
|
||||
MessagesURL,
|
||||
QueueURL,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL
|
||||
QueueServiceClient,
|
||||
newPipeline,
|
||||
StorageSharedKeyCredential,
|
||||
QueueClient
|
||||
} from "@azure/storage-queue";
|
||||
|
||||
import { configLogger } from "../../../src/common/Logger";
|
||||
|
@ -51,10 +48,13 @@ describe("MessageId APIs test", () => {
|
|||
);
|
||||
|
||||
const baseURL = `http://${host}:${port}/devstoreaccount1`;
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ describe("MessageId APIs test", () => {
|
|||
let server: Server;
|
||||
|
||||
let queueName: string;
|
||||
let queueURL: QueueURL;
|
||||
let queueClient: QueueClient;
|
||||
const messageContent = "Hello World";
|
||||
|
||||
before(async () => {
|
||||
|
@ -79,26 +79,25 @@ describe("MessageId APIs test", () => {
|
|||
await rmRecursive(persistencePath);
|
||||
});
|
||||
|
||||
beforeEach(async function() {
|
||||
beforeEach(async function () {
|
||||
queueName = getUniqueName("queue");
|
||||
queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
queueClient = serviceClient.getQueueClient(queueName);
|
||||
await queueClient.create();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.delete();
|
||||
});
|
||||
|
||||
it("update and delete empty message with default parameters @loki", async () => {
|
||||
let messagesURL = MessagesURL.fromQueueURL(queueURL);
|
||||
let eResult = await messagesURL.enqueue(Aborter.none, messageContent);
|
||||
const eResult = await queueClient.sendMessage(messageContent);
|
||||
assert.ok(eResult.date);
|
||||
assert.ok(eResult.expirationTime);
|
||||
assert.ok(eResult.insertionTime);
|
||||
assert.ok(eResult.expiresOn);
|
||||
assert.ok(eResult.insertedOn);
|
||||
assert.ok(eResult.messageId);
|
||||
assert.ok(eResult.popReceipt);
|
||||
assert.ok(eResult.requestId);
|
||||
assert.ok(eResult.timeNextVisible);
|
||||
assert.ok(eResult.nextVisibleOn);
|
||||
assert.ok(eResult.version);
|
||||
assert.equal(
|
||||
eResult._response.request.headers.get("x-ms-client-request-id"),
|
||||
|
@ -106,18 +105,14 @@ describe("MessageId APIs test", () => {
|
|||
);
|
||||
|
||||
let newMessage = "";
|
||||
let messageIdURL = MessageIdURL.fromMessagesURL(
|
||||
messagesURL,
|
||||
eResult.messageId
|
||||
);
|
||||
let uResult = await messageIdURL.update(
|
||||
Aborter.none,
|
||||
const uResult = await queueClient.updateMessage(
|
||||
eResult.messageId,
|
||||
eResult.popReceipt,
|
||||
0,
|
||||
newMessage
|
||||
newMessage,
|
||||
0
|
||||
);
|
||||
assert.ok(uResult.version);
|
||||
assert.ok(uResult.timeNextVisible);
|
||||
assert.ok(uResult.nextVisibleOn);
|
||||
assert.ok(uResult.date);
|
||||
assert.ok(uResult.requestId);
|
||||
assert.ok(uResult.popReceipt);
|
||||
|
@ -126,7 +121,7 @@ describe("MessageId APIs test", () => {
|
|||
uResult.clientRequestId
|
||||
);
|
||||
|
||||
let pResult = await messagesURL.peek(Aborter.none);
|
||||
let pResult = await queueClient.peekMessages();
|
||||
assert.equal(pResult.peekedMessageItems.length, 1);
|
||||
assert.deepStrictEqual(
|
||||
pResult.peekedMessageItems[0].messageText,
|
||||
|
@ -137,7 +132,10 @@ describe("MessageId APIs test", () => {
|
|||
pResult.clientRequestId
|
||||
);
|
||||
|
||||
let dResult = await messageIdURL.delete(Aborter.none, uResult.popReceipt!);
|
||||
const dResult = await queueClient.deleteMessage(
|
||||
eResult.messageId,
|
||||
uResult.popReceipt!
|
||||
);
|
||||
assert.ok(dResult.date);
|
||||
assert.ok(dResult.requestId);
|
||||
assert.ok(dResult.version);
|
||||
|
@ -146,20 +144,19 @@ describe("MessageId APIs test", () => {
|
|||
dResult.clientRequestId
|
||||
);
|
||||
|
||||
pResult = await messagesURL.peek(Aborter.none);
|
||||
pResult = await queueClient.peekMessages();
|
||||
assert.equal(pResult.peekedMessageItems.length, 0);
|
||||
});
|
||||
|
||||
it("update and delete message with all parameters @loki", async () => {
|
||||
let messagesURL = MessagesURL.fromQueueURL(queueURL);
|
||||
let eResult = await messagesURL.enqueue(Aborter.none, messageContent);
|
||||
const eResult = await queueClient.sendMessage(messageContent);
|
||||
assert.ok(eResult.date);
|
||||
assert.ok(eResult.expirationTime);
|
||||
assert.ok(eResult.insertionTime);
|
||||
assert.ok(eResult.expiresOn);
|
||||
assert.ok(eResult.insertedOn);
|
||||
assert.ok(eResult.messageId);
|
||||
assert.ok(eResult.popReceipt);
|
||||
assert.ok(eResult.requestId);
|
||||
assert.ok(eResult.timeNextVisible);
|
||||
assert.ok(eResult.nextVisibleOn);
|
||||
assert.ok(eResult.version);
|
||||
assert.equal(
|
||||
eResult._response.request.headers.get("x-ms-client-request-id"),
|
||||
|
@ -167,18 +164,14 @@ describe("MessageId APIs test", () => {
|
|||
);
|
||||
|
||||
let newMessage = "New Message";
|
||||
let messageIdURL = MessageIdURL.fromMessagesURL(
|
||||
messagesURL,
|
||||
eResult.messageId
|
||||
);
|
||||
let uResult = await messageIdURL.update(
|
||||
Aborter.none,
|
||||
const uResult = await queueClient.updateMessage(
|
||||
eResult.messageId,
|
||||
eResult.popReceipt,
|
||||
5,
|
||||
newMessage
|
||||
newMessage,
|
||||
5
|
||||
);
|
||||
assert.ok(uResult.version);
|
||||
assert.ok(uResult.timeNextVisible);
|
||||
assert.ok(uResult.nextVisibleOn);
|
||||
assert.ok(uResult.date);
|
||||
assert.ok(uResult.requestId);
|
||||
assert.ok(uResult.popReceipt);
|
||||
|
@ -187,7 +180,7 @@ describe("MessageId APIs test", () => {
|
|||
uResult.clientRequestId
|
||||
);
|
||||
|
||||
let pResult = await messagesURL.peek(Aborter.none);
|
||||
let pResult = await queueClient.peekMessages();
|
||||
assert.equal(pResult.peekedMessageItems.length, 0);
|
||||
assert.equal(
|
||||
pResult._response.request.headers.get("x-ms-client-request-id"),
|
||||
|
@ -196,7 +189,7 @@ describe("MessageId APIs test", () => {
|
|||
|
||||
await sleep(6 * 1000);
|
||||
|
||||
let pResult2 = await messagesURL.peek(Aborter.none);
|
||||
let pResult2 = await queueClient.peekMessages();
|
||||
assert.equal(pResult2.peekedMessageItems.length, 1);
|
||||
assert.deepStrictEqual(
|
||||
pResult2.peekedMessageItems[0].messageText,
|
||||
|
@ -205,15 +198,14 @@ describe("MessageId APIs test", () => {
|
|||
});
|
||||
|
||||
it("update message with 64KB characters size which is computed after encoding @loki", async () => {
|
||||
let messagesURL = MessagesURL.fromQueueURL(queueURL);
|
||||
let eResult = await messagesURL.enqueue(Aborter.none, messageContent);
|
||||
const eResult = await queueClient.sendMessage(messageContent);
|
||||
assert.ok(eResult.date);
|
||||
assert.ok(eResult.expirationTime);
|
||||
assert.ok(eResult.insertionTime);
|
||||
assert.ok(eResult.expiresOn);
|
||||
assert.ok(eResult.insertedOn);
|
||||
assert.ok(eResult.messageId);
|
||||
assert.ok(eResult.popReceipt);
|
||||
assert.ok(eResult.requestId);
|
||||
assert.ok(eResult.timeNextVisible);
|
||||
assert.ok(eResult.nextVisibleOn);
|
||||
assert.ok(eResult.version);
|
||||
assert.equal(
|
||||
eResult._response.request.headers.get("x-ms-client-request-id"),
|
||||
|
@ -221,18 +213,14 @@ describe("MessageId APIs test", () => {
|
|||
);
|
||||
|
||||
let newMessage = new Array(64 * 1024 + 1).join("a");
|
||||
let messageIdURL = MessageIdURL.fromMessagesURL(
|
||||
messagesURL,
|
||||
eResult.messageId
|
||||
);
|
||||
let uResult = await messageIdURL.update(
|
||||
Aborter.none,
|
||||
const uResult = await queueClient.updateMessage(
|
||||
eResult.messageId,
|
||||
eResult.popReceipt,
|
||||
0,
|
||||
newMessage
|
||||
newMessage,
|
||||
0
|
||||
);
|
||||
assert.ok(uResult.version);
|
||||
assert.ok(uResult.timeNextVisible);
|
||||
assert.ok(uResult.nextVisibleOn);
|
||||
assert.ok(uResult.date);
|
||||
assert.ok(uResult.requestId);
|
||||
assert.ok(uResult.popReceipt);
|
||||
|
@ -241,7 +229,7 @@ describe("MessageId APIs test", () => {
|
|||
uResult.clientRequestId
|
||||
);
|
||||
|
||||
let pResult = await messagesURL.peek(Aborter.none);
|
||||
let pResult = await queueClient.peekMessages();
|
||||
assert.equal(pResult.peekedMessageItems.length, 1);
|
||||
assert.deepStrictEqual(
|
||||
pResult.peekedMessageItems[0].messageText,
|
||||
|
@ -254,31 +242,25 @@ describe("MessageId APIs test", () => {
|
|||
});
|
||||
|
||||
it("update message negative with 65537B (64KB+1B) characters size which is computed after encoding @loki", async () => {
|
||||
let messagesURL = MessagesURL.fromQueueURL(queueURL);
|
||||
let eResult = await messagesURL.enqueue(Aborter.none, messageContent);
|
||||
const eResult = await queueClient.sendMessage(messageContent);
|
||||
assert.ok(eResult.date);
|
||||
assert.ok(eResult.expirationTime);
|
||||
assert.ok(eResult.insertionTime);
|
||||
assert.ok(eResult.expiresOn);
|
||||
assert.ok(eResult.insertedOn);
|
||||
assert.ok(eResult.messageId);
|
||||
assert.ok(eResult.popReceipt);
|
||||
assert.ok(eResult.requestId);
|
||||
assert.ok(eResult.timeNextVisible);
|
||||
assert.ok(eResult.nextVisibleOn);
|
||||
assert.ok(eResult.version);
|
||||
|
||||
let newMessage = new Array(64 * 1024 + 2).join("a");
|
||||
|
||||
let messageIdURL = MessageIdURL.fromMessagesURL(
|
||||
messagesURL,
|
||||
eResult.messageId
|
||||
);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await messageIdURL.update(
|
||||
Aborter.none,
|
||||
await queueClient.updateMessage(
|
||||
eResult.messageId,
|
||||
eResult.popReceipt,
|
||||
0,
|
||||
newMessage
|
||||
newMessage,
|
||||
0
|
||||
);
|
||||
} catch (err) {
|
||||
error = err;
|
||||
|
@ -292,17 +274,11 @@ describe("MessageId APIs test", () => {
|
|||
});
|
||||
|
||||
it("delete message negative @loki", async () => {
|
||||
let messagesURL = MessagesURL.fromQueueURL(queueURL);
|
||||
let eResult = await messagesURL.enqueue(Aborter.none, messageContent);
|
||||
|
||||
let messageIdURL = MessageIdURL.fromMessagesURL(
|
||||
messagesURL,
|
||||
eResult.messageId
|
||||
);
|
||||
const eResult = await queueClient.sendMessage(messageContent);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await messageIdURL.delete(Aborter.none, "invalid");
|
||||
await queueClient.deleteMessage(eResult.messageId, "invalid");
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
import * as assert from "assert";
|
||||
|
||||
import {
|
||||
Aborter,
|
||||
MessagesURL,
|
||||
QueueURL,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL
|
||||
QueueServiceClient,
|
||||
newPipeline,
|
||||
StorageSharedKeyCredential,
|
||||
QueueClient
|
||||
} from "@azure/storage-queue";
|
||||
|
||||
import { configLogger } from "../../../src/common/Logger";
|
||||
|
@ -49,10 +47,13 @@ describe("Messages APIs test", () => {
|
|||
);
|
||||
|
||||
const baseURL = `http://${host}:${port}/devstoreaccount1`;
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -61,7 +62,7 @@ describe("Messages APIs test", () => {
|
|||
|
||||
let server: Server;
|
||||
let queueName: string;
|
||||
let queueURL: QueueURL;
|
||||
let queueClient: QueueClient;
|
||||
const messageContent = "Hello World";
|
||||
|
||||
before(async () => {
|
||||
|
@ -76,31 +77,30 @@ describe("Messages APIs test", () => {
|
|||
await rmRecursive(persistencePath);
|
||||
});
|
||||
|
||||
beforeEach(async function() {
|
||||
beforeEach(async function () {
|
||||
queueName = getUniqueName("queue");
|
||||
queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
queueClient = serviceClient.getQueueClient(queueName);
|
||||
await queueClient.create();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.delete();
|
||||
});
|
||||
|
||||
it("enqueue, peek, dequeue and clear message with default parameters @loki", async () => {
|
||||
let messagesURL = MessagesURL.fromQueueURL(queueURL);
|
||||
let eResult = await messagesURL.enqueue(Aborter.none, messageContent);
|
||||
const eResult = await queueClient.sendMessage(messageContent);
|
||||
assert.ok(eResult.date);
|
||||
assert.ok(eResult.expirationTime);
|
||||
assert.ok(eResult.insertionTime);
|
||||
assert.ok(eResult.expiresOn);
|
||||
assert.ok(eResult.insertedOn);
|
||||
assert.ok(eResult.messageId);
|
||||
assert.ok(eResult.popReceipt);
|
||||
assert.ok(eResult.requestId);
|
||||
assert.ok(eResult.timeNextVisible);
|
||||
assert.ok(eResult.nextVisibleOn);
|
||||
assert.ok(eResult.version);
|
||||
|
||||
await messagesURL.enqueue(Aborter.none, messageContent);
|
||||
await queueClient.sendMessage(messageContent);
|
||||
|
||||
let pResult = await messagesURL.peek(Aborter.none);
|
||||
const pResult = await queueClient.peekMessages();
|
||||
assert.ok(pResult.date);
|
||||
assert.ok(pResult.requestId);
|
||||
assert.ok(pResult.version);
|
||||
|
@ -114,18 +114,18 @@ describe("Messages APIs test", () => {
|
|||
eResult.messageId
|
||||
);
|
||||
|
||||
let dqResult = await messagesURL.dequeue(Aborter.none);
|
||||
let dqResult = await queueClient.receiveMessages();
|
||||
assert.ok(dqResult.date);
|
||||
assert.ok(dqResult.requestId);
|
||||
assert.ok(dqResult.version);
|
||||
assert.deepStrictEqual(dqResult.dequeuedMessageItems.length, 1);
|
||||
assert.ok(dqResult.dequeuedMessageItems[0].popReceipt);
|
||||
assert.deepStrictEqual(dqResult.receivedMessageItems.length, 1);
|
||||
assert.ok(dqResult.receivedMessageItems[0].popReceipt);
|
||||
assert.deepStrictEqual(
|
||||
dqResult.dequeuedMessageItems[0].messageText,
|
||||
dqResult.receivedMessageItems[0].messageText,
|
||||
messageContent
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
dqResult.dequeuedMessageItems[0].messageId,
|
||||
dqResult.receivedMessageItems[0].messageId,
|
||||
eResult.messageId
|
||||
);
|
||||
assert.equal(
|
||||
|
@ -133,7 +133,7 @@ describe("Messages APIs test", () => {
|
|||
dqResult.clientRequestId
|
||||
);
|
||||
|
||||
let cResult = await messagesURL.clear(Aborter.none);
|
||||
const cResult = await queueClient.clearMessages();
|
||||
assert.ok(cResult.date);
|
||||
assert.ok(cResult.requestId);
|
||||
assert.ok(cResult.version);
|
||||
|
@ -143,41 +143,41 @@ describe("Messages APIs test", () => {
|
|||
);
|
||||
|
||||
// check all messages are cleared
|
||||
let pResult2 = await messagesURL.peek(Aborter.none);
|
||||
const pResult2 = await queueClient.peekMessages();
|
||||
assert.ok(pResult2.date);
|
||||
assert.deepStrictEqual(pResult2.peekedMessageItems.length, 0);
|
||||
});
|
||||
|
||||
it("enqueue, peek, dequeue and clear message with all parameters @loki", async () => {
|
||||
let messagesURL = MessagesURL.fromQueueURL(queueURL);
|
||||
|
||||
let eResult = await messagesURL.enqueue(Aborter.none, messageContent, {
|
||||
const eResult = await queueClient.sendMessage(messageContent, {
|
||||
messageTimeToLive: 40,
|
||||
visibilitytimeout: 0
|
||||
visibilityTimeout: 0
|
||||
});
|
||||
assert.ok(eResult.date);
|
||||
assert.ok(eResult.expirationTime);
|
||||
assert.ok(eResult.insertionTime);
|
||||
assert.ok(eResult.expiresOn);
|
||||
assert.ok(eResult.insertedOn);
|
||||
assert.ok(eResult.messageId);
|
||||
assert.ok(eResult.popReceipt);
|
||||
assert.ok(eResult.requestId);
|
||||
assert.ok(eResult.timeNextVisible);
|
||||
assert.ok(eResult.nextVisibleOn);
|
||||
assert.ok(eResult.version);
|
||||
|
||||
let eResult2 = await messagesURL.enqueue(Aborter.none, messageContent, {
|
||||
let eResult2 = await queueClient.sendMessage(messageContent, {
|
||||
messageTimeToLive: 40,
|
||||
visibilitytimeout: 0
|
||||
visibilityTimeout: 0
|
||||
});
|
||||
await messagesURL.enqueue(Aborter.none, messageContent, {
|
||||
await queueClient.sendMessage(messageContent, {
|
||||
messageTimeToLive: 10,
|
||||
visibilitytimeout: 5
|
||||
visibilityTimeout: 5
|
||||
});
|
||||
await messagesURL.enqueue(Aborter.none, messageContent, {
|
||||
await queueClient.sendMessage(messageContent, {
|
||||
messageTimeToLive: Number.MAX_SAFE_INTEGER,
|
||||
visibilitytimeout: 19
|
||||
visibilityTimeout: 19
|
||||
});
|
||||
|
||||
let pResult = await messagesURL.peek(Aborter.none, { numberOfMessages: 2 });
|
||||
let pResult = await queueClient.peekMessages({
|
||||
numberOfMessages: 2
|
||||
});
|
||||
assert.ok(pResult.date);
|
||||
assert.ok(pResult.requestId);
|
||||
assert.ok(pResult.version);
|
||||
|
@ -192,12 +192,12 @@ describe("Messages APIs test", () => {
|
|||
eResult.messageId
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
pResult.peekedMessageItems[0].insertionTime,
|
||||
eResult.insertionTime
|
||||
pResult.peekedMessageItems[0].insertedOn,
|
||||
eResult.insertedOn
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
pResult.peekedMessageItems[0].expirationTime,
|
||||
eResult.expirationTime
|
||||
pResult.peekedMessageItems[0].expiresOn,
|
||||
eResult.expiresOn
|
||||
);
|
||||
|
||||
assert.deepStrictEqual(
|
||||
|
@ -210,41 +210,41 @@ describe("Messages APIs test", () => {
|
|||
eResult2.messageId
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
pResult.peekedMessageItems[1].insertionTime,
|
||||
eResult2.insertionTime
|
||||
pResult.peekedMessageItems[1].insertedOn,
|
||||
eResult2.insertedOn
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
pResult.peekedMessageItems[1].expirationTime,
|
||||
eResult2.expirationTime
|
||||
pResult.peekedMessageItems[1].expiresOn,
|
||||
eResult2.expiresOn
|
||||
);
|
||||
|
||||
let dResult = await messagesURL.dequeue(Aborter.none, {
|
||||
let dResult = await queueClient.receiveMessages({
|
||||
visibilitytimeout: 10,
|
||||
numberOfMessages: 2
|
||||
});
|
||||
assert.ok(dResult.date);
|
||||
assert.ok(dResult.requestId);
|
||||
assert.ok(dResult.version);
|
||||
assert.deepStrictEqual(dResult.dequeuedMessageItems.length, 2);
|
||||
assert.deepStrictEqual(dResult.receivedMessageItems.length, 2);
|
||||
assert.deepStrictEqual(
|
||||
dResult.dequeuedMessageItems[0].messageText,
|
||||
dResult.receivedMessageItems[0].messageText,
|
||||
messageContent
|
||||
);
|
||||
assert.deepStrictEqual(dResult.dequeuedMessageItems[0].dequeueCount, 1);
|
||||
assert.deepStrictEqual(dResult.receivedMessageItems[0].dequeueCount, 1);
|
||||
assert.deepStrictEqual(
|
||||
dResult.dequeuedMessageItems[0].messageId,
|
||||
dResult.receivedMessageItems[0].messageId,
|
||||
eResult.messageId
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
dResult.dequeuedMessageItems[0].insertionTime,
|
||||
eResult.insertionTime
|
||||
dResult.receivedMessageItems[0].insertedOn,
|
||||
eResult.insertedOn
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
dResult.dequeuedMessageItems[0].expirationTime,
|
||||
eResult.expirationTime
|
||||
dResult.receivedMessageItems[0].expiresOn,
|
||||
eResult.expiresOn
|
||||
);
|
||||
assert.ok(dResult.dequeuedMessageItems[0].popReceipt);
|
||||
assert.ok(dResult.dequeuedMessageItems[0].timeNextVisible);
|
||||
assert.ok(dResult.receivedMessageItems[0].popReceipt);
|
||||
assert.ok(dResult.receivedMessageItems[0].nextVisibleOn);
|
||||
|
||||
assert.deepStrictEqual(
|
||||
pResult.peekedMessageItems[1].messageText,
|
||||
|
@ -252,28 +252,28 @@ describe("Messages APIs test", () => {
|
|||
);
|
||||
|
||||
// check no message is visible
|
||||
let pResult2 = await messagesURL.peek(Aborter.none);
|
||||
let pResult2 = await queueClient.peekMessages();
|
||||
assert.ok(pResult2.date);
|
||||
assert.deepStrictEqual(pResult2.peekedMessageItems.length, 0);
|
||||
});
|
||||
|
||||
it("enqueue, peek, dequeue empty message, and peek, dequeue with numberOfMessages > count(messages) @loki", async () => {
|
||||
let messagesURL = MessagesURL.fromQueueURL(queueURL);
|
||||
|
||||
let eResult = await messagesURL.enqueue(Aborter.none, "", {
|
||||
const eResult = await queueClient.sendMessage("", {
|
||||
messageTimeToLive: 40,
|
||||
visibilitytimeout: 0
|
||||
visibilityTimeout: 0
|
||||
});
|
||||
assert.ok(eResult.date);
|
||||
assert.ok(eResult.expirationTime);
|
||||
assert.ok(eResult.insertionTime);
|
||||
assert.ok(eResult.expiresOn);
|
||||
assert.ok(eResult.insertedOn);
|
||||
assert.ok(eResult.messageId);
|
||||
assert.ok(eResult.popReceipt);
|
||||
assert.ok(eResult.requestId);
|
||||
assert.ok(eResult.timeNextVisible);
|
||||
assert.ok(eResult.nextVisibleOn);
|
||||
assert.ok(eResult.version);
|
||||
|
||||
let pResult = await messagesURL.peek(Aborter.none, { numberOfMessages: 2 });
|
||||
const pResult = await queueClient.peekMessages({
|
||||
numberOfMessages: 2
|
||||
});
|
||||
assert.ok(pResult.date);
|
||||
assert.ok(pResult.requestId);
|
||||
assert.ok(pResult.version);
|
||||
|
@ -285,60 +285,58 @@ describe("Messages APIs test", () => {
|
|||
eResult.messageId
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
pResult.peekedMessageItems[0].insertionTime,
|
||||
eResult.insertionTime
|
||||
pResult.peekedMessageItems[0].insertedOn,
|
||||
eResult.insertedOn
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
pResult.peekedMessageItems[0].expirationTime,
|
||||
eResult.expirationTime
|
||||
pResult.peekedMessageItems[0].expiresOn,
|
||||
eResult.expiresOn
|
||||
);
|
||||
|
||||
let dResult = await messagesURL.dequeue(Aborter.none, {
|
||||
let dResult = await queueClient.receiveMessages({
|
||||
visibilitytimeout: 10,
|
||||
numberOfMessages: 2
|
||||
});
|
||||
assert.ok(dResult.date);
|
||||
assert.ok(dResult.requestId);
|
||||
assert.ok(dResult.version);
|
||||
assert.deepStrictEqual(dResult.dequeuedMessageItems.length, 1);
|
||||
assert.deepStrictEqual(dResult.dequeuedMessageItems[0].messageText, "");
|
||||
assert.deepStrictEqual(dResult.dequeuedMessageItems[0].dequeueCount, 1);
|
||||
assert.deepStrictEqual(dResult.receivedMessageItems.length, 1);
|
||||
assert.deepStrictEqual(dResult.receivedMessageItems[0].messageText, "");
|
||||
assert.deepStrictEqual(dResult.receivedMessageItems[0].dequeueCount, 1);
|
||||
assert.deepStrictEqual(
|
||||
dResult.dequeuedMessageItems[0].messageId,
|
||||
dResult.receivedMessageItems[0].messageId,
|
||||
eResult.messageId
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
dResult.dequeuedMessageItems[0].insertionTime,
|
||||
eResult.insertionTime
|
||||
dResult.receivedMessageItems[0].insertedOn,
|
||||
eResult.insertedOn
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
dResult.dequeuedMessageItems[0].expirationTime,
|
||||
eResult.expirationTime
|
||||
dResult.receivedMessageItems[0].expiresOn,
|
||||
eResult.expiresOn
|
||||
);
|
||||
assert.ok(dResult.dequeuedMessageItems[0].popReceipt);
|
||||
assert.ok(dResult.dequeuedMessageItems[0].timeNextVisible);
|
||||
assert.ok(dResult.receivedMessageItems[0].popReceipt);
|
||||
assert.ok(dResult.receivedMessageItems[0].nextVisibleOn);
|
||||
});
|
||||
|
||||
it("enqueue, peek, dequeue special characters @loki", async () => {
|
||||
let messagesURL = MessagesURL.fromQueueURL(queueURL);
|
||||
|
||||
let specialMessage =
|
||||
"!@#$%^&*()_+`-=[]|};'\":,./?><`~漢字㒈保ᨍ揫^p[뷁)7l鮍ͺ簣ڞ츊䈗㝯綞߫⯹?ÎᦡC왶żsmt㖩닡ОլFZ9tC榅ٻ컦驿Ϳ[𱿛봻烌ՌδŊϜ췮㐦9ͽƙp퐂ʩ由巩KFÓ֮⨿aBm旨Ϣջ֨ipnꝷՆ斡賆m˞Ӯ<Bu)á<џɏ嗂<C98F>⨣1PJ㬵┡ḸIˮaࢸ۳i灛ȯɨb뿶uٔ䎴Φ륽س_NƵ¦\u00E9";
|
||||
|
||||
let eResult = await messagesURL.enqueue(Aborter.none, specialMessage, {
|
||||
let eResult = await queueClient.sendMessage(specialMessage, {
|
||||
messageTimeToLive: 40,
|
||||
visibilitytimeout: 0
|
||||
});
|
||||
assert.ok(eResult.date);
|
||||
assert.ok(eResult.expirationTime);
|
||||
assert.ok(eResult.insertionTime);
|
||||
assert.ok(eResult.expiresOn);
|
||||
assert.ok(eResult.insertedOn);
|
||||
assert.ok(eResult.messageId);
|
||||
assert.ok(eResult.popReceipt);
|
||||
assert.ok(eResult.requestId);
|
||||
assert.ok(eResult.timeNextVisible);
|
||||
assert.ok(eResult.nextVisibleOn);
|
||||
assert.ok(eResult.version);
|
||||
|
||||
let pResult = await messagesURL.peek(Aborter.none, { numberOfMessages: 2 });
|
||||
let pResult = await queueClient.peekMessages({ numberOfMessages: 2 });
|
||||
assert.ok(pResult.date);
|
||||
assert.ok(pResult.requestId);
|
||||
assert.ok(pResult.version);
|
||||
|
@ -353,61 +351,60 @@ describe("Messages APIs test", () => {
|
|||
eResult.messageId
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
pResult.peekedMessageItems[0].insertionTime,
|
||||
eResult.insertionTime
|
||||
pResult.peekedMessageItems[0].insertedOn,
|
||||
eResult.insertedOn
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
pResult.peekedMessageItems[0].expirationTime,
|
||||
eResult.expirationTime
|
||||
pResult.peekedMessageItems[0].expiresOn,
|
||||
eResult.expiresOn
|
||||
);
|
||||
|
||||
let dResult = await messagesURL.dequeue(Aborter.none, {
|
||||
let dResult = await queueClient.receiveMessages({
|
||||
visibilitytimeout: 10,
|
||||
numberOfMessages: 2
|
||||
});
|
||||
assert.ok(dResult.date);
|
||||
assert.ok(dResult.requestId);
|
||||
assert.ok(dResult.version);
|
||||
assert.deepStrictEqual(dResult.dequeuedMessageItems.length, 1);
|
||||
assert.deepStrictEqual(dResult.receivedMessageItems.length, 1);
|
||||
assert.deepStrictEqual(
|
||||
dResult.dequeuedMessageItems[0].messageText,
|
||||
dResult.receivedMessageItems[0].messageText,
|
||||
specialMessage
|
||||
);
|
||||
assert.deepStrictEqual(dResult.dequeuedMessageItems[0].dequeueCount, 1);
|
||||
assert.deepStrictEqual(dResult.receivedMessageItems[0].dequeueCount, 1);
|
||||
assert.deepStrictEqual(
|
||||
dResult.dequeuedMessageItems[0].messageId,
|
||||
dResult.receivedMessageItems[0].messageId,
|
||||
eResult.messageId
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
dResult.dequeuedMessageItems[0].insertionTime,
|
||||
eResult.insertionTime
|
||||
dResult.receivedMessageItems[0].insertedOn,
|
||||
eResult.insertedOn
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
dResult.dequeuedMessageItems[0].expirationTime,
|
||||
eResult.expirationTime
|
||||
dResult.receivedMessageItems[0].expiresOn,
|
||||
eResult.expiresOn
|
||||
);
|
||||
assert.ok(dResult.dequeuedMessageItems[0].popReceipt);
|
||||
assert.ok(dResult.dequeuedMessageItems[0].timeNextVisible);
|
||||
assert.ok(dResult.receivedMessageItems[0].popReceipt);
|
||||
assert.ok(dResult.receivedMessageItems[0].nextVisibleOn);
|
||||
});
|
||||
|
||||
it("enqueue, peek, dequeue with 64KB characters size which is computed after encoding @loki", async () => {
|
||||
let messagesURL = MessagesURL.fromQueueURL(queueURL);
|
||||
let messageContent = new Array(64 * 1024 + 1).join("a");
|
||||
|
||||
let eResult = await messagesURL.enqueue(Aborter.none, messageContent, {
|
||||
const eResult = await queueClient.sendMessage(messageContent, {
|
||||
messageTimeToLive: 40,
|
||||
visibilitytimeout: 0
|
||||
visibilityTimeout: 0
|
||||
});
|
||||
assert.ok(eResult.date);
|
||||
assert.ok(eResult.expirationTime);
|
||||
assert.ok(eResult.insertionTime);
|
||||
assert.ok(eResult.expiresOn);
|
||||
assert.ok(eResult.insertedOn);
|
||||
assert.ok(eResult.messageId);
|
||||
assert.ok(eResult.popReceipt);
|
||||
assert.ok(eResult.requestId);
|
||||
assert.ok(eResult.timeNextVisible);
|
||||
assert.ok(eResult.nextVisibleOn);
|
||||
assert.ok(eResult.version);
|
||||
|
||||
let pResult = await messagesURL.peek(Aborter.none, { numberOfMessages: 2 });
|
||||
let pResult = await queueClient.peekMessages({ numberOfMessages: 2 });
|
||||
assert.ok(pResult.date);
|
||||
assert.ok(pResult.requestId);
|
||||
assert.ok(pResult.version);
|
||||
|
@ -422,61 +419,60 @@ describe("Messages APIs test", () => {
|
|||
eResult.messageId
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
pResult.peekedMessageItems[0].insertionTime,
|
||||
eResult.insertionTime
|
||||
pResult.peekedMessageItems[0].insertedOn,
|
||||
eResult.insertedOn
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
pResult.peekedMessageItems[0].expirationTime,
|
||||
eResult.expirationTime
|
||||
pResult.peekedMessageItems[0].expiresOn,
|
||||
eResult.expiresOn
|
||||
);
|
||||
|
||||
let dResult = await messagesURL.dequeue(Aborter.none, {
|
||||
let dResult = await queueClient.receiveMessages({
|
||||
visibilitytimeout: 10,
|
||||
numberOfMessages: 2
|
||||
});
|
||||
assert.ok(dResult.date);
|
||||
assert.ok(dResult.requestId);
|
||||
assert.ok(dResult.version);
|
||||
assert.deepStrictEqual(dResult.dequeuedMessageItems.length, 1);
|
||||
assert.deepStrictEqual(dResult.receivedMessageItems.length, 1);
|
||||
assert.deepStrictEqual(
|
||||
dResult.dequeuedMessageItems[0].messageText,
|
||||
dResult.receivedMessageItems[0].messageText,
|
||||
messageContent
|
||||
);
|
||||
assert.deepStrictEqual(dResult.dequeuedMessageItems[0].dequeueCount, 1);
|
||||
assert.deepStrictEqual(dResult.receivedMessageItems[0].dequeueCount, 1);
|
||||
assert.deepStrictEqual(
|
||||
dResult.dequeuedMessageItems[0].messageId,
|
||||
dResult.receivedMessageItems[0].messageId,
|
||||
eResult.messageId
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
dResult.dequeuedMessageItems[0].insertionTime,
|
||||
eResult.insertionTime
|
||||
dResult.receivedMessageItems[0].insertedOn,
|
||||
eResult.insertedOn
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
dResult.dequeuedMessageItems[0].expirationTime,
|
||||
eResult.expirationTime
|
||||
dResult.receivedMessageItems[0].expiresOn,
|
||||
eResult.expiresOn
|
||||
);
|
||||
assert.ok(dResult.dequeuedMessageItems[0].popReceipt);
|
||||
assert.ok(dResult.dequeuedMessageItems[0].timeNextVisible);
|
||||
assert.ok(dResult.receivedMessageItems[0].popReceipt);
|
||||
assert.ok(dResult.receivedMessageItems[0].nextVisibleOn);
|
||||
});
|
||||
|
||||
it("enqueue, peek and dequeue negative @loki", async () => {
|
||||
let messagesURL = MessagesURL.fromQueueURL(queueURL);
|
||||
let eResult = await messagesURL.enqueue(Aborter.none, messageContent, {
|
||||
const eResult = await queueClient.sendMessage(messageContent, {
|
||||
messageTimeToLive: 40
|
||||
});
|
||||
assert.ok(eResult.date);
|
||||
assert.ok(eResult.expirationTime);
|
||||
assert.ok(eResult.insertionTime);
|
||||
assert.ok(eResult.expiresOn);
|
||||
assert.ok(eResult.insertedOn);
|
||||
assert.ok(eResult.messageId);
|
||||
assert.ok(eResult.popReceipt);
|
||||
assert.ok(eResult.requestId);
|
||||
assert.ok(eResult.timeNextVisible);
|
||||
assert.ok(eResult.nextVisibleOn);
|
||||
assert.ok(eResult.version);
|
||||
let error;
|
||||
try {
|
||||
await messagesURL.enqueue(Aborter.none, messageContent, {
|
||||
await queueClient.sendMessage(messageContent, {
|
||||
messageTimeToLive: 30,
|
||||
visibilitytimeout: 30
|
||||
visibilityTimeout: 30
|
||||
});
|
||||
} catch (err) {
|
||||
error = err;
|
||||
|
@ -484,13 +480,13 @@ describe("Messages APIs test", () => {
|
|||
assert.ok(error);
|
||||
let errorPeek;
|
||||
try {
|
||||
await messagesURL.peek(Aborter.none, { numberOfMessages: 100 });
|
||||
await queueClient.peekMessages({ numberOfMessages: 100 });
|
||||
} catch (err) {
|
||||
errorPeek = err;
|
||||
}
|
||||
assert.ok(errorPeek);
|
||||
|
||||
let pResult = await messagesURL.peek(Aborter.none, { numberOfMessages: 2 });
|
||||
let pResult = await queueClient.peekMessages({ numberOfMessages: 2 });
|
||||
assert.ok(pResult.date);
|
||||
assert.ok(pResult.requestId);
|
||||
assert.ok(pResult.version);
|
||||
|
@ -505,28 +501,27 @@ describe("Messages APIs test", () => {
|
|||
eResult.messageId
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
pResult.peekedMessageItems[0].insertionTime,
|
||||
eResult.insertionTime
|
||||
pResult.peekedMessageItems[0].insertedOn,
|
||||
eResult.insertedOn
|
||||
);
|
||||
assert.deepStrictEqual(
|
||||
pResult.peekedMessageItems[0].expirationTime,
|
||||
eResult.expirationTime
|
||||
pResult.peekedMessageItems[0].expiresOn,
|
||||
eResult.expiresOn
|
||||
);
|
||||
|
||||
// Note visibility time could be larger then message time to live for dequeue.
|
||||
await messagesURL.dequeue(Aborter.none, {
|
||||
await queueClient.receiveMessages({
|
||||
visibilitytimeout: 40,
|
||||
numberOfMessages: 2
|
||||
});
|
||||
});
|
||||
|
||||
it("enqueue negative with 65537B(64KB+1B) characters size which is computed after encoding @loki", async () => {
|
||||
let messagesURL = MessagesURL.fromQueueURL(queueURL);
|
||||
let messageContent = new Array(64 * 1024 + 2).join("a");
|
||||
|
||||
let error;
|
||||
try {
|
||||
await messagesURL.enqueue(Aborter.none, messageContent, {});
|
||||
await queueClient.sendMessage(messageContent, {});
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import * as assert from "assert";
|
||||
|
||||
import {
|
||||
Aborter,
|
||||
QueueURL,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL
|
||||
newPipeline,
|
||||
QueueServiceClient,
|
||||
QueueClient,
|
||||
StorageSharedKeyCredential
|
||||
} from "@azure/storage-queue";
|
||||
|
||||
import { configLogger } from "../../../src/common/Logger";
|
||||
|
@ -48,10 +47,13 @@ describe("Queue APIs test", () => {
|
|||
);
|
||||
|
||||
const baseURL = `http://${host}:${port}/devstoreaccount1`;
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -60,7 +62,7 @@ describe("Queue APIs test", () => {
|
|||
|
||||
let server: Server;
|
||||
let queueName: string;
|
||||
let queueURL: QueueURL;
|
||||
let queueClient: QueueClient;
|
||||
|
||||
before(async () => {
|
||||
server = new Server(config);
|
||||
|
@ -74,14 +76,14 @@ describe("Queue APIs test", () => {
|
|||
await rmRecursive(persistencePath);
|
||||
});
|
||||
|
||||
beforeEach(async function() {
|
||||
beforeEach(async function () {
|
||||
queueName = getUniqueName("queue");
|
||||
queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
queueClient = serviceClient.getQueueClient(queueName);
|
||||
await queueClient.create();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.delete();
|
||||
});
|
||||
|
||||
it("setMetadata @loki", async () => {
|
||||
|
@ -90,13 +92,13 @@ describe("Queue APIs test", () => {
|
|||
keya: "vala",
|
||||
keyb: "valb"
|
||||
};
|
||||
const mResult = await queueURL.setMetadata(Aborter.none, metadata);
|
||||
const mResult = await queueClient.setMetadata(metadata);
|
||||
assert.equal(
|
||||
mResult._response.request.headers.get("x-ms-client-request-id"),
|
||||
mResult.clientRequestId
|
||||
);
|
||||
|
||||
const result = await queueURL.getProperties(Aborter.none);
|
||||
const result = await queueClient.getProperties();
|
||||
assert.deepEqual(result.metadata, metadata);
|
||||
assert.equal(
|
||||
result._response.request.headers.get("x-ms-client-request-id"),
|
||||
|
@ -105,7 +107,7 @@ describe("Queue APIs test", () => {
|
|||
});
|
||||
|
||||
it("getProperties with default/all parameters @loki", async () => {
|
||||
const result = await queueURL.getProperties(Aborter.none);
|
||||
const result = await queueClient.getProperties();
|
||||
assert.ok(result.approximateMessagesCount! >= 0);
|
||||
assert.ok(result.requestId);
|
||||
assert.ok(result.version);
|
||||
|
@ -114,10 +116,10 @@ describe("Queue APIs test", () => {
|
|||
|
||||
it("getProperties negative @loki", async () => {
|
||||
const queueName2 = getUniqueName("queue2");
|
||||
const queueURL2 = QueueURL.fromServiceURL(serviceURL, queueName2);
|
||||
const queueClient2 = serviceClient.getQueueClient(queueName2);
|
||||
let error;
|
||||
try {
|
||||
await queueURL2.getProperties(Aborter.none);
|
||||
await queueClient2.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
@ -125,41 +127,41 @@ describe("Queue APIs test", () => {
|
|||
assert.ok(error.statusCode);
|
||||
assert.deepEqual(error.statusCode, 404);
|
||||
assert.ok(error.response);
|
||||
assert.ok(error.response.body);
|
||||
assert.ok(error.response.body.includes("QueueNotFound"));
|
||||
assert.ok(error.response.bodyAsText);
|
||||
assert.ok(error.response.bodyAsText.includes("QueueNotFound"));
|
||||
});
|
||||
|
||||
it("create with default parameters", done => {
|
||||
it("create with default parameters", (done) => {
|
||||
// create() with default parameters has been tested in beforeEach
|
||||
done();
|
||||
});
|
||||
|
||||
it("create with all parameters @loki", async () => {
|
||||
const qURL = QueueURL.fromServiceURL(serviceURL, getUniqueName(queueName));
|
||||
const qClient = serviceClient.getQueueClient(getUniqueName(queueName));
|
||||
const metadata = { key: "value" };
|
||||
await qURL.create(Aborter.none, { metadata });
|
||||
const result = await qURL.getProperties(Aborter.none);
|
||||
await qClient.create({ metadata });
|
||||
const result = await qClient.getProperties();
|
||||
assert.deepEqual(result.metadata, metadata);
|
||||
});
|
||||
|
||||
// create with invalid queue name
|
||||
it("create negative @loki", async () => {
|
||||
const qURL = QueueURL.fromServiceURL(serviceURL, "");
|
||||
let error;
|
||||
try {
|
||||
await qURL.create(Aborter.none);
|
||||
const qClient = serviceClient.getQueueClient("");
|
||||
await qClient.create();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
assert.ok(error);
|
||||
assert.ok(error.statusCode);
|
||||
assert.deepEqual(error.statusCode, 400);
|
||||
assert.ok(error.response);
|
||||
assert.ok(error.response.body);
|
||||
assert.ok(error.response.body.includes("InvalidResourceName"));
|
||||
assert.equal(
|
||||
error.message,
|
||||
"Unable to extract queueName with provided information.",
|
||||
"Unexpected error caught: " + error
|
||||
);
|
||||
});
|
||||
|
||||
it("delete @loki", done => {
|
||||
it("delete @loki", (done) => {
|
||||
// delete() with default parameters has been tested in afterEach
|
||||
done();
|
||||
});
|
||||
|
@ -168,29 +170,29 @@ describe("Queue APIs test", () => {
|
|||
const queueAcl = [
|
||||
{
|
||||
accessPolicy: {
|
||||
expiry: new Date("2018-12-31T11:22:33.4567890Z"),
|
||||
permission: "raup",
|
||||
start: new Date("2017-12-31T11:22:33.4567890Z")
|
||||
expiresOn: new Date("2018-12-31T11:22:33.4567890Z"),
|
||||
permissions: "raup",
|
||||
startsOn: new Date("2017-12-31T11:22:33.4567890Z")
|
||||
},
|
||||
id: "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="
|
||||
},
|
||||
{
|
||||
accessPolicy: {
|
||||
expiry: new Date("2030-11-31T11:22:33.4567890Z"),
|
||||
permission: "a",
|
||||
start: new Date("2017-12-31T11:22:33.4567890Z")
|
||||
expiresOn: new Date("2030-11-31T11:22:33.4567890Z"),
|
||||
permissions: "a",
|
||||
startsOn: new Date("2017-12-31T11:22:33.4567890Z")
|
||||
},
|
||||
id: "policy2"
|
||||
}
|
||||
];
|
||||
|
||||
const sResult = await queueURL.setAccessPolicy(Aborter.none, queueAcl);
|
||||
const sResult = await queueClient.setAccessPolicy(queueAcl);
|
||||
assert.equal(
|
||||
sResult._response.request.headers.get("x-ms-client-request-id"),
|
||||
sResult.clientRequestId
|
||||
);
|
||||
|
||||
const result = await queueURL.getAccessPolicy(Aborter.none);
|
||||
const result = await queueClient.getAccessPolicy();
|
||||
assert.deepEqual(result.signedIdentifiers, queueAcl);
|
||||
assert.equal(
|
||||
result._response.request.headers.get("x-ms-client-request-id"),
|
||||
|
@ -201,17 +203,17 @@ describe("Queue APIs test", () => {
|
|||
const queueAcl = [
|
||||
{
|
||||
accessPolicy: {
|
||||
expiry: new Date("2018-12-31T11:22:33.4567890Z"),
|
||||
permission: "rwdl",
|
||||
start: new Date("2017-12-31T11:22:33.4567890Z")
|
||||
expiresOn: new Date("2018-12-31T11:22:33.4567890Z"),
|
||||
permissions: "rwdl",
|
||||
startsOn: new Date("2017-12-31T11:22:33.4567890Z")
|
||||
},
|
||||
id: "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI="
|
||||
},
|
||||
{
|
||||
accessPolicy: {
|
||||
expiry: new Date("2030-11-31T11:22:33.4567890Z"),
|
||||
permission: "a",
|
||||
start: new Date("2017-12-31T11:22:33.4567890Z")
|
||||
expiresOn: new Date("2030-11-31T11:22:33.4567890Z"),
|
||||
permissions: "a",
|
||||
startsOn: new Date("2017-12-31T11:22:33.4567890Z")
|
||||
},
|
||||
id: "policy2"
|
||||
}
|
||||
|
@ -219,7 +221,7 @@ describe("Queue APIs test", () => {
|
|||
|
||||
let error;
|
||||
try {
|
||||
await queueURL.setAccessPolicy(Aborter.none, queueAcl);
|
||||
await queueClient.setAccessPolicy(queueAcl);
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import {
|
||||
Aborter,
|
||||
QueueURL,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL
|
||||
QueueServiceClient,
|
||||
newPipeline,
|
||||
StorageSharedKeyCredential
|
||||
} from "@azure/storage-queue";
|
||||
import * as assert from "assert";
|
||||
|
||||
|
@ -48,10 +46,13 @@ describe("QueueServiceAPIs", () => {
|
|||
);
|
||||
|
||||
const baseURL = `http://${host}:${port}/devstoreaccount1`;
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -73,7 +74,7 @@ describe("QueueServiceAPIs", () => {
|
|||
});
|
||||
|
||||
it("Get Queue service properties @loki", async () => {
|
||||
const result = await serviceURL.getProperties(Aborter.none);
|
||||
const result = await serviceClient.getProperties();
|
||||
|
||||
assert.ok(typeof result.requestId);
|
||||
assert.ok(result.requestId!.length > 0);
|
||||
|
@ -90,7 +91,7 @@ describe("QueueServiceAPIs", () => {
|
|||
});
|
||||
|
||||
it("Set CORS with empty AllowedHeaders, ExposedHeaders @loki", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "",
|
||||
|
@ -102,20 +103,20 @@ describe("QueueServiceAPIs", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
const result = await serviceURL.getProperties(Aborter.none);
|
||||
const result = await serviceClient.getProperties();
|
||||
assert.deepStrictEqual(result.cors![0], newCORS);
|
||||
});
|
||||
|
||||
it("Set Queue service properties @loki", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
assert.equal(
|
||||
serviceProperties._response.request.headers.get("x-ms-client-request-id"),
|
||||
serviceProperties.clientRequestId
|
||||
);
|
||||
|
||||
serviceProperties.logging = {
|
||||
serviceProperties.queueAnalyticsLogging = {
|
||||
deleteProperty: true,
|
||||
read: true,
|
||||
retentionPolicy: {
|
||||
|
@ -159,10 +160,7 @@ describe("QueueServiceAPIs", () => {
|
|||
serviceProperties.cors.push(newCORS);
|
||||
}
|
||||
|
||||
const sResult = await serviceURL.setProperties(
|
||||
Aborter.none,
|
||||
serviceProperties
|
||||
);
|
||||
const sResult = await serviceClient.setProperties(serviceProperties);
|
||||
assert.equal(
|
||||
sResult._response.request.headers.get("x-ms-client-request-id"),
|
||||
sResult.clientRequestId
|
||||
|
@ -170,7 +168,7 @@ describe("QueueServiceAPIs", () => {
|
|||
|
||||
await sleep(1 * 1000);
|
||||
|
||||
const result = await serviceURL.getProperties(Aborter.none);
|
||||
const result = await serviceClient.getProperties();
|
||||
assert.ok(typeof result.requestId);
|
||||
assert.ok(result.requestId!.length > 0);
|
||||
assert.ok(typeof result.version);
|
||||
|
@ -179,7 +177,7 @@ describe("QueueServiceAPIs", () => {
|
|||
});
|
||||
|
||||
it("listQueuesSegment with default parameters @loki", async () => {
|
||||
const result = await serviceURL.listQueuesSegment(Aborter.none);
|
||||
const result = (await serviceClient.listQueues().byPage().next()).value;
|
||||
assert.ok(typeof result.requestId);
|
||||
assert.ok(result.requestId!.length > 0);
|
||||
assert.ok(typeof result.version);
|
||||
|
@ -202,10 +200,10 @@ describe("QueueServiceAPIs", () => {
|
|||
const queueNamePrefix = getUniqueName("queue");
|
||||
const queueName1 = `${queueNamePrefix}x1`;
|
||||
const queueName2 = `${queueNamePrefix}x2`;
|
||||
const queueURL1 = QueueURL.fromServiceURL(serviceURL, queueName1);
|
||||
const queueURL2 = QueueURL.fromServiceURL(serviceURL, queueName2);
|
||||
await queueURL1.create(Aborter.none, { metadata: { key: "val" } });
|
||||
const cResult = await queueURL2.create(Aborter.none, {
|
||||
const queueClient1 = serviceClient.getQueueClient(queueName1);
|
||||
const queueClient2 = serviceClient.getQueueClient(queueName2);
|
||||
await queueClient1.create({ metadata: { key: "val" } });
|
||||
const cResult = await queueClient2.create({
|
||||
metadata: { key: "val" }
|
||||
});
|
||||
assert.equal(
|
||||
|
@ -213,38 +211,41 @@ describe("QueueServiceAPIs", () => {
|
|||
cResult.clientRequestId
|
||||
);
|
||||
|
||||
const result1 = await serviceURL.listQueuesSegment(
|
||||
Aborter.none,
|
||||
undefined,
|
||||
{
|
||||
include: "metadata",
|
||||
maxresults: 1,
|
||||
prefix: queueNamePrefix
|
||||
}
|
||||
);
|
||||
const result1 = (
|
||||
await serviceClient
|
||||
.listQueues({
|
||||
includeMetadata: true,
|
||||
prefix: queueNamePrefix
|
||||
})
|
||||
.byPage({ maxPageSize: 1 })
|
||||
.next()
|
||||
).value;
|
||||
|
||||
assert.ok(result1.nextMarker);
|
||||
assert.ok(result1.continuationToken);
|
||||
assert.equal(result1.queueItems!.length, 1);
|
||||
assert.ok(result1.queueItems![0].name.startsWith(queueNamePrefix));
|
||||
assert.deepEqual(result1.queueItems![0].metadata!.key, "val");
|
||||
|
||||
const result2 = await serviceURL.listQueuesSegment(
|
||||
Aborter.none,
|
||||
result1.nextMarker,
|
||||
{
|
||||
include: "metadata",
|
||||
maxresults: 1,
|
||||
prefix: queueNamePrefix
|
||||
}
|
||||
);
|
||||
const result2 = (
|
||||
await serviceClient
|
||||
.listQueues({
|
||||
includeMetadata: true,
|
||||
prefix: queueNamePrefix
|
||||
})
|
||||
.byPage({
|
||||
continuationToken: result1.continuationToken,
|
||||
maxPageSize: 1
|
||||
})
|
||||
.next()
|
||||
).value;
|
||||
|
||||
assert.ok(!result2.nextMarker);
|
||||
assert.ok(!result2.continuationToken);
|
||||
assert.equal(result2.queueItems!.length, 1);
|
||||
assert.ok(result2.queueItems![0].name.startsWith(queueNamePrefix));
|
||||
assert.deepEqual(result2.queueItems![0].metadata!.key, "val");
|
||||
|
||||
await queueURL1.delete(Aborter.none);
|
||||
const dResult = await queueURL2.delete(Aborter.none);
|
||||
await queueClient1.delete();
|
||||
const dResult = await queueClient2.delete();
|
||||
assert.equal(
|
||||
dResult._response.request.headers.get("x-ms-client-request-id"),
|
||||
dResult.clientRequestId
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import {
|
||||
Aborter,
|
||||
QueueURL,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL
|
||||
QueueServiceClient,
|
||||
newPipeline,
|
||||
StorageSharedKeyCredential
|
||||
} from "@azure/storage-queue";
|
||||
|
||||
import { configLogger } from "../../src/common/Logger";
|
||||
|
@ -69,10 +67,13 @@ describe("Queue HTTPS", () => {
|
|||
const baseURL = `https://${host}:${port}/devstoreaccount1`;
|
||||
|
||||
it(`Should work with correct shared key when using HTTPS endpoint @loki`, async () => {
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -80,9 +81,9 @@ describe("Queue HTTPS", () => {
|
|||
);
|
||||
|
||||
const queueName: string = getUniqueName("queue-with-dash");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.create();
|
||||
await queueClient.delete();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,10 +1,4 @@
|
|||
import {
|
||||
Aborter,
|
||||
QueueURL,
|
||||
ServiceURL,
|
||||
StorageURL,
|
||||
TokenCredential
|
||||
} from "@azure/storage-queue";
|
||||
import { QueueServiceClient, newPipeline } from "@azure/storage-queue";
|
||||
|
||||
import * as assert from "assert";
|
||||
import Server from "../../src/queue/QueueServer";
|
||||
|
@ -13,6 +7,7 @@ import { configLogger } from "../../src/common/Logger";
|
|||
import { StoreDestinationArray } from "../../src/common/persistence/IExtentStore";
|
||||
import QueueConfiguration from "../../src/queue/QueueConfiguration";
|
||||
import { generateJWTToken, getUniqueName } from "../testutils";
|
||||
import { SimpleTokenCredential } from "../simpleTokenCredential";
|
||||
|
||||
// Set true to enable debug log
|
||||
configLogger(false);
|
||||
|
@ -75,34 +70,34 @@ describe("Queue OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
})
|
||||
);
|
||||
|
||||
const queueName: string = getUniqueName("1queue-with-dash");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.create();
|
||||
await queueClient.delete();
|
||||
});
|
||||
|
||||
it(`Should not work with invalid JWT token @loki @sql`, async () => {
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential("invalid token"), {
|
||||
newPipeline(new SimpleTokenCredential("invalid token"), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
})
|
||||
);
|
||||
|
||||
const queueName: string = getUniqueName("1queue-with-dash");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
|
||||
try {
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.create();
|
||||
await queueClient.delete();
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(
|
||||
err.message.includes("AuthenticationFailed"),
|
||||
|
@ -138,18 +133,18 @@ describe("Queue OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
})
|
||||
);
|
||||
|
||||
const queueName: string = getUniqueName("1queue-with-dash");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.create();
|
||||
await queueClient.delete();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -163,19 +158,19 @@ describe("Queue OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
})
|
||||
);
|
||||
|
||||
const queueName: string = getUniqueName("1queue-with-dash");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
|
||||
try {
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.create();
|
||||
await queueClient.delete();
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(
|
||||
err.message.includes("AuthenticationFailed"),
|
||||
|
@ -205,18 +200,18 @@ describe("Queue OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
})
|
||||
);
|
||||
|
||||
const queueName: string = getUniqueName("1queue-with-dash");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.create();
|
||||
await queueClient.delete();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -230,19 +225,19 @@ describe("Queue OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
})
|
||||
);
|
||||
|
||||
const queueName: string = getUniqueName("1queue-with-dash");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
|
||||
try {
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.create();
|
||||
await queueClient.delete();
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(
|
||||
err.message.includes("AuthenticationFailed"),
|
||||
|
@ -264,19 +259,19 @@ describe("Queue OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
})
|
||||
);
|
||||
|
||||
const queueName: string = getUniqueName("1queue-with-dash");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
|
||||
try {
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.create();
|
||||
await queueClient.delete();
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(
|
||||
err.message.includes("AuthenticationFailed"),
|
||||
|
@ -298,19 +293,19 @@ describe("Queue OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
})
|
||||
);
|
||||
|
||||
const queueName: string = getUniqueName("1queue-with-dash");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
|
||||
try {
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.create();
|
||||
await queueClient.delete();
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(
|
||||
err.message.includes("AuthenticationFailed"),
|
||||
|
@ -332,28 +327,28 @@ describe("Queue OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
})
|
||||
);
|
||||
|
||||
const queueName: string = getUniqueName("1queue-with-dash");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
await queueClient.create();
|
||||
|
||||
try {
|
||||
await queueURL.getAccessPolicy(Aborter.none);
|
||||
await queueClient.getAccessPolicy();
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(
|
||||
err.message.includes("AuthorizationFailure"),
|
||||
true
|
||||
);
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.delete();
|
||||
return;
|
||||
}
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.delete();
|
||||
assert.fail();
|
||||
});
|
||||
|
||||
|
@ -367,28 +362,28 @@ describe("Queue OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
})
|
||||
);
|
||||
|
||||
const queueName: string = getUniqueName("1queue-with-dash");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
await queueClient.create();
|
||||
|
||||
try {
|
||||
await queueURL.setAccessPolicy(Aborter.none, []);
|
||||
await queueClient.setAccessPolicy([]);
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(
|
||||
err.message.includes("AuthorizationFailure"),
|
||||
true
|
||||
);
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.delete();
|
||||
return;
|
||||
}
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.delete();
|
||||
assert.fail();
|
||||
});
|
||||
|
||||
|
@ -428,19 +423,19 @@ describe("Queue OAuth Basic", () => {
|
|||
"user_impersonation"
|
||||
);
|
||||
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
httpBaseURL,
|
||||
StorageURL.newPipeline(new TokenCredential(token), {
|
||||
newPipeline(new SimpleTokenCredential(token), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
})
|
||||
);
|
||||
|
||||
const queueName: string = getUniqueName("1queue-with-dash");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
|
||||
try {
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.create();
|
||||
await queueClient.delete();
|
||||
} catch (err) {
|
||||
assert.deepStrictEqual(
|
||||
err.message.includes("AuthenticationFailed"),
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
import * as assert from "assert";
|
||||
|
||||
import {
|
||||
Aborter,
|
||||
AnonymousCredential,
|
||||
QueueURL,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL
|
||||
StorageSharedKeyCredential,
|
||||
newPipeline,
|
||||
QueueServiceClient
|
||||
} from "@azure/storage-queue";
|
||||
|
||||
import { configLogger } from "../../src/common/Logger";
|
||||
|
@ -65,25 +63,25 @@ describe("Queue Authentication", () => {
|
|||
const baseURL = `http://${host}:${port}/devstoreaccount1`;
|
||||
|
||||
it(`Should not work without credential @loki`, async () => {
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(new AnonymousCredential(), {
|
||||
newPipeline(new AnonymousCredential(), {
|
||||
retryOptions: { maxTries: 1 }
|
||||
})
|
||||
);
|
||||
|
||||
const queueName: string = getUniqueName("queue-with-dash");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
|
||||
let err;
|
||||
try {
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueClient.create();
|
||||
} catch (error) {
|
||||
err = error;
|
||||
} finally {
|
||||
if (err === undefined) {
|
||||
try {
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.delete();
|
||||
} catch (error) {
|
||||
/* Noop */
|
||||
}
|
||||
|
@ -93,10 +91,10 @@ describe("Queue Authentication", () => {
|
|||
});
|
||||
|
||||
it(`Should not work without correct account name @loki`, async () => {
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential("invalid", EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential("invalid", EMULATOR_ACCOUNT_KEY),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -104,17 +102,17 @@ describe("Queue Authentication", () => {
|
|||
);
|
||||
|
||||
const queueName: string = getUniqueName("queue-with-dash");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
|
||||
let err;
|
||||
try {
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueClient.create();
|
||||
} catch (error) {
|
||||
err = error;
|
||||
} finally {
|
||||
if (err === undefined) {
|
||||
try {
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.delete();
|
||||
} catch (error) {
|
||||
/* Noop */
|
||||
}
|
||||
|
@ -124,10 +122,10 @@ describe("Queue Authentication", () => {
|
|||
});
|
||||
|
||||
it(`Should not work without correct account key @loki`, async () => {
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, "invalidkey"),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(EMULATOR_ACCOUNT_NAME, "invalidkey"),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -135,17 +133,17 @@ describe("Queue Authentication", () => {
|
|||
);
|
||||
|
||||
const queueName: string = getUniqueName("queue-with-dash");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
|
||||
let err;
|
||||
try {
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueClient.create();
|
||||
} catch (error) {
|
||||
err = error;
|
||||
} finally {
|
||||
if (err === undefined) {
|
||||
try {
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.delete();
|
||||
} catch (error) {
|
||||
/* Noop */
|
||||
}
|
||||
|
@ -155,10 +153,13 @@ describe("Queue Authentication", () => {
|
|||
});
|
||||
|
||||
it(`Should work with correct shared key @loki`, async () => {
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -166,9 +167,9 @@ describe("Queue Authentication", () => {
|
|||
);
|
||||
|
||||
const queueName: string = getUniqueName("queue-with-dash");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.create();
|
||||
await queueClient.delete();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import {
|
||||
Aborter,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL,
|
||||
QueueURL
|
||||
StorageSharedKeyCredential,
|
||||
newPipeline,
|
||||
QueueServiceClient
|
||||
} from "@azure/storage-queue";
|
||||
import * as assert from "assert";
|
||||
|
||||
|
@ -49,10 +47,13 @@ describe("Queue Cors requests test", () => {
|
|||
);
|
||||
|
||||
const baseURL = `http://${host}:${port}/devstoreaccount1`;
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -73,15 +74,18 @@ describe("Queue Cors requests test", () => {
|
|||
});
|
||||
|
||||
it("OPTIONS request without cors rules in server should be fail @loki", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
serviceProperties.cors = [];
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
const origin = "Origin";
|
||||
const requestMethod = "GET";
|
||||
|
||||
const pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
const pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -89,25 +93,25 @@ describe("Queue Cors requests test", () => {
|
|||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod)
|
||||
);
|
||||
const serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
const serviceClientForOPTIONS = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
await serviceClientForOPTIONS.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error.statusCode === 403);
|
||||
assert.ok(
|
||||
error.body.message.includes(
|
||||
error.message.includes(
|
||||
"CORS not enabled or no matching rule found for this request."
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it("OPTIONS request should not work without matching cors rules @loki", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "header",
|
||||
|
@ -119,15 +123,18 @@ describe("Queue Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
let origin = "Origin";
|
||||
let requestMethod = "GET";
|
||||
|
||||
let pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
let pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -135,18 +142,18 @@ describe("Queue Cors requests test", () => {
|
|||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod)
|
||||
);
|
||||
let serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
let serviceClientForOPTIONS = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
await serviceClientForOPTIONS.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error.statusCode === 403);
|
||||
assert.ok(
|
||||
error.body.message.includes(
|
||||
error.message.includes(
|
||||
"CORS not enabled or no matching rule found for this request."
|
||||
)
|
||||
);
|
||||
|
@ -154,8 +161,11 @@ describe("Queue Cors requests test", () => {
|
|||
origin = "test";
|
||||
requestMethod = "GET";
|
||||
|
||||
pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -163,14 +173,14 @@ describe("Queue Cors requests test", () => {
|
|||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod)
|
||||
);
|
||||
serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
serviceClientForOPTIONS = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
const res = await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
const res = await serviceClientForOPTIONS.getProperties();
|
||||
assert.ok(res._response.status === 200);
|
||||
});
|
||||
|
||||
it("OPTIONS request should not work without Origin header or matching allowedOrigins @loki", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "header",
|
||||
|
@ -182,15 +192,18 @@ describe("Queue Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "Origin";
|
||||
const requestMethod = "GET";
|
||||
|
||||
let pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
let pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -198,24 +211,27 @@ describe("Queue Cors requests test", () => {
|
|||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod)
|
||||
);
|
||||
let serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
let serviceClientForOPTIONS = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
await serviceClientForOPTIONS.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error.statusCode === 403);
|
||||
assert.ok(
|
||||
error.body.message.includes(
|
||||
error.message.includes(
|
||||
"CORS not enabled or no matching rule found for this request."
|
||||
)
|
||||
);
|
||||
|
||||
pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -223,24 +239,24 @@ describe("Queue Cors requests test", () => {
|
|||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(undefined, requestMethod)
|
||||
);
|
||||
serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
serviceClientForOPTIONS = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
try {
|
||||
await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
await serviceClientForOPTIONS.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error.statusCode === 403);
|
||||
assert.ok(
|
||||
error.body.message.includes(
|
||||
error.message.includes(
|
||||
"CORS not enabled or no matching rule found for this request."
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
it("OPTIONS request should not work without requestMethod header or matching allowedMethods @loki", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "header",
|
||||
|
@ -252,15 +268,18 @@ describe("Queue Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "test";
|
||||
const requestMethod = "PUT";
|
||||
|
||||
let pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
let pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -268,24 +287,27 @@ describe("Queue Cors requests test", () => {
|
|||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod)
|
||||
);
|
||||
let serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
let serviceClientForOPTIONS = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
await serviceClientForOPTIONS.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error.statusCode === 403);
|
||||
assert.ok(
|
||||
error.body.message.includes(
|
||||
error.message.includes(
|
||||
"CORS not enabled or no matching rule found for this request."
|
||||
)
|
||||
);
|
||||
|
||||
pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -293,22 +315,20 @@ describe("Queue Cors requests test", () => {
|
|||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, undefined)
|
||||
);
|
||||
serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
serviceClientForOPTIONS = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
try {
|
||||
await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
await serviceClientForOPTIONS.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error.statusCode === 400);
|
||||
assert.ok(
|
||||
error.body.message.includes("A required CORS header is not present.")
|
||||
);
|
||||
assert.ok(error.message.includes("A required CORS header is not present."));
|
||||
});
|
||||
|
||||
it("OPTIONS request should check the defined requestHeaders @loki", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = [
|
||||
{
|
||||
|
@ -336,7 +356,7 @@ describe("Queue Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = newCORS;
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
|
@ -345,8 +365,11 @@ describe("Queue Cors requests test", () => {
|
|||
let requestMethod = "GET";
|
||||
let reqestHeaders = "head";
|
||||
|
||||
let pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
let pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -354,18 +377,18 @@ describe("Queue Cors requests test", () => {
|
|||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod, reqestHeaders)
|
||||
);
|
||||
let serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
let serviceClientForOPTIONS = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
await serviceClientForOPTIONS.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error.statusCode === 403);
|
||||
assert.ok(
|
||||
error.body.message.includes(
|
||||
error.message.includes(
|
||||
"CORS not enabled or no matching rule found for this request."
|
||||
)
|
||||
);
|
||||
|
@ -375,8 +398,11 @@ describe("Queue Cors requests test", () => {
|
|||
requestMethod = "GET";
|
||||
reqestHeaders = "header";
|
||||
|
||||
pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -384,9 +410,9 @@ describe("Queue Cors requests test", () => {
|
|||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod, reqestHeaders)
|
||||
);
|
||||
serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
serviceClientForOPTIONS = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
let res = await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
let res = await serviceClientForOPTIONS.getProperties();
|
||||
assert.ok(res._response.status === 200);
|
||||
|
||||
// Match second cors.
|
||||
|
@ -394,8 +420,11 @@ describe("Queue Cors requests test", () => {
|
|||
requestMethod = "PUT";
|
||||
reqestHeaders = "head";
|
||||
|
||||
pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -403,9 +432,9 @@ describe("Queue Cors requests test", () => {
|
|||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod, reqestHeaders)
|
||||
);
|
||||
serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
serviceClientForOPTIONS = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
res = await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
res = await serviceClientForOPTIONS.getProperties();
|
||||
assert.ok(res._response.status === 200);
|
||||
|
||||
// No match.
|
||||
|
@ -413,8 +442,11 @@ describe("Queue Cors requests test", () => {
|
|||
requestMethod = "POST";
|
||||
reqestHeaders = "hea";
|
||||
|
||||
pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -422,18 +454,18 @@ describe("Queue Cors requests test", () => {
|
|||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod, reqestHeaders)
|
||||
);
|
||||
serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
serviceClientForOPTIONS = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
error;
|
||||
try {
|
||||
await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
await serviceClientForOPTIONS.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
assert.ok(error.statusCode === 403);
|
||||
assert.ok(
|
||||
error.body.message.includes(
|
||||
error.message.includes(
|
||||
"CORS not enabled or no matching rule found for this request."
|
||||
)
|
||||
);
|
||||
|
@ -443,8 +475,11 @@ describe("Queue Cors requests test", () => {
|
|||
requestMethod = "POST";
|
||||
reqestHeaders = "headerheader";
|
||||
|
||||
pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -452,14 +487,14 @@ describe("Queue Cors requests test", () => {
|
|||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod, reqestHeaders)
|
||||
);
|
||||
serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
serviceClientForOPTIONS = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
res = await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
res = await serviceClientForOPTIONS.getProperties();
|
||||
assert.ok(res._response.status === 200);
|
||||
});
|
||||
|
||||
it("OPTIONS request should work with matching rule containing Origion * @loki", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "header",
|
||||
|
@ -471,15 +506,18 @@ describe("Queue Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "anyOrigin";
|
||||
const requestMethod = "GET";
|
||||
|
||||
const pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
const pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -487,32 +525,35 @@ describe("Queue Cors requests test", () => {
|
|||
pipeline.factories.unshift(
|
||||
new OPTIONSRequestPolicyFactory(origin, requestMethod)
|
||||
);
|
||||
const serviceURLforOPTIONS = new ServiceURL(baseURL, pipeline);
|
||||
const serviceClientForOPTIONS = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
const res = await serviceURLforOPTIONS.getProperties(Aborter.none);
|
||||
const res = await serviceClientForOPTIONS.getProperties();
|
||||
assert.ok(res._response.status === 200);
|
||||
});
|
||||
|
||||
it("Response of request to service without cors rules should not contains cors info @loki", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
serviceProperties.cors = [];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "anyOrigin";
|
||||
const pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
const pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(new OriginPolicyFactory(origin));
|
||||
const serviceURLwithOrigin = new ServiceURL(baseURL, pipeline);
|
||||
const serviceClientWithOrigin = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
const res: any = await serviceURLwithOrigin.getProperties(Aborter.none);
|
||||
const res: any = await serviceClientWithOrigin.getProperties();
|
||||
|
||||
assert.ok(res["access-control-allow-origin"] === undefined);
|
||||
assert.ok(res["access-control-expose-headers"] === undefined);
|
||||
|
@ -520,7 +561,7 @@ describe("Queue Cors requests test", () => {
|
|||
});
|
||||
|
||||
it("Service with mismatching cors rules should response header Vary @loki", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "header",
|
||||
|
@ -532,29 +573,32 @@ describe("Queue Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "anyOrigin";
|
||||
const pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
const pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(new OriginPolicyFactory(origin));
|
||||
const serviceURLwithOrigin = new ServiceURL(baseURL, pipeline);
|
||||
const serviceClientWithOrigin = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
let res: any = await serviceURLwithOrigin.getProperties(Aborter.none);
|
||||
let res: any = await serviceClientWithOrigin.getProperties();
|
||||
assert.ok(res.vary !== undefined);
|
||||
|
||||
res = await serviceURL.getProperties(Aborter.none);
|
||||
res = await serviceClient.getProperties();
|
||||
assert.ok(res.vary === undefined);
|
||||
});
|
||||
|
||||
it("Request Match rule exists that allows all origins (*) @loki", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "header",
|
||||
|
@ -566,33 +610,36 @@ describe("Queue Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "anyOrigin";
|
||||
const pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
const pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(new OriginPolicyFactory(origin));
|
||||
const serviceURLwithOrigin = new ServiceURL(baseURL, pipeline);
|
||||
const serviceClientWithOrigin = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
let res: any = await serviceURLwithOrigin.getProperties(Aborter.none);
|
||||
let res: any = await serviceClientWithOrigin.getProperties();
|
||||
assert.ok(res["access-control-allow-origin"] === "*");
|
||||
assert.ok(res.vary === undefined);
|
||||
assert.ok(res["access-control-expose-headers"] !== undefined);
|
||||
|
||||
res = await serviceURL.getProperties(Aborter.none);
|
||||
res = await serviceClient.getProperties();
|
||||
assert.ok(res["access-control-allow-origin"] === undefined);
|
||||
assert.ok(res.vary === undefined);
|
||||
assert.ok(res["access-control-expose-headers"] === undefined);
|
||||
});
|
||||
|
||||
it("Request Match rule exists for exact origin @loki", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "header",
|
||||
|
@ -604,28 +651,31 @@ describe("Queue Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "exactOrigin";
|
||||
const pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
const pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(new OriginPolicyFactory(origin));
|
||||
const serviceURLwithOrigin = new ServiceURL(baseURL, pipeline);
|
||||
const serviceClientWithOrigin = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
const res: any = await serviceURLwithOrigin.getProperties(Aborter.none);
|
||||
const res: any = await serviceClientWithOrigin.getProperties();
|
||||
assert.ok(res["access-control-allow-origin"] === origin);
|
||||
assert.ok(res.vary !== undefined);
|
||||
assert.ok(res["access-control-expose-headers"] !== undefined);
|
||||
});
|
||||
|
||||
it("Requests with error response should apply for CORS @loki", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = {
|
||||
allowedHeaders: "header",
|
||||
|
@ -637,27 +687,29 @@ describe("Queue Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = [newCORS];
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "exactOrigin";
|
||||
const pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
const pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(new OriginPolicyFactory(origin));
|
||||
const serviceURLwithOrigin = new ServiceURL(baseURL, pipeline);
|
||||
const serviceClientWithOrigin = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
const queueURLwithOrigin = QueueURL.fromServiceURL(
|
||||
serviceURLwithOrigin,
|
||||
const queueClientWithOrigin = serviceClientWithOrigin.getQueueClient(
|
||||
"notexistcontainer"
|
||||
);
|
||||
|
||||
try {
|
||||
await queueURLwithOrigin.getProperties(Aborter.none);
|
||||
await queueClientWithOrigin.getProperties();
|
||||
} catch (err) {
|
||||
assert.ok(
|
||||
err.response.headers._headersMap["access-control-allow-origin"]
|
||||
|
@ -672,7 +724,7 @@ describe("Queue Cors requests test", () => {
|
|||
});
|
||||
|
||||
it("Request Match rule in sequence @loki", async () => {
|
||||
const serviceProperties = await serviceURL.getProperties(Aborter.none);
|
||||
const serviceProperties = await serviceClient.getProperties();
|
||||
|
||||
const newCORS = [
|
||||
{
|
||||
|
@ -693,21 +745,24 @@ describe("Queue Cors requests test", () => {
|
|||
|
||||
serviceProperties.cors = newCORS;
|
||||
|
||||
await serviceURL.setProperties(Aborter.none, serviceProperties);
|
||||
await serviceClient.setProperties(serviceProperties);
|
||||
|
||||
await sleep(100);
|
||||
|
||||
const origin = "exactOrigin";
|
||||
const pipeline = StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
const pipeline = newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
);
|
||||
pipeline.factories.unshift(new OriginPolicyFactory(origin));
|
||||
const serviceURLwithOrigin = new ServiceURL(baseURL, pipeline);
|
||||
const serviceClientWithOrigin = new QueueServiceClient(baseURL, pipeline);
|
||||
|
||||
const res: any = await serviceURLwithOrigin.getProperties(Aborter.none);
|
||||
const res: any = await serviceClientWithOrigin.getProperties();
|
||||
assert.ok(res["access-control-allow-origin"] === origin);
|
||||
assert.ok(res.vary !== undefined);
|
||||
assert.ok(res["access-control-expose-headers"] !== undefined);
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
import * as assert from "assert";
|
||||
|
||||
import {
|
||||
Aborter,
|
||||
AccountSASPermissions,
|
||||
AccountSASResourceTypes,
|
||||
AccountSASServices,
|
||||
AnonymousCredential,
|
||||
generateAccountSASQueryParameters,
|
||||
generateQueueSASQueryParameters,
|
||||
MessageIdURL,
|
||||
MessagesURL,
|
||||
QueueSASPermissions,
|
||||
QueueURL,
|
||||
SASProtocol,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL
|
||||
StorageSharedKeyCredential,
|
||||
QueueServiceClient,
|
||||
newPipeline,
|
||||
QueueClient
|
||||
} from "@azure/storage-queue";
|
||||
|
||||
import { configLogger } from "../../src/common/Logger";
|
||||
|
@ -59,10 +56,13 @@ describe("Queue SAS test", () => {
|
|||
);
|
||||
|
||||
const baseURL = `http://${host}:${port}/devstoreaccount1`;
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -91,30 +91,30 @@ describe("Queue SAS test", () => {
|
|||
tmr.setDate(tmr.getDate() + 1);
|
||||
|
||||
// By default, credential is always the last element of pipeline factories
|
||||
const factories = serviceURL.pipeline.factories;
|
||||
const sharedKeyCredential = factories[factories.length - 1];
|
||||
const factories = (serviceClient as any).pipeline.factories;
|
||||
const storageSharedKeyCredential = factories[factories.length - 1];
|
||||
|
||||
const sas = generateAccountSASQueryParameters(
|
||||
{
|
||||
expiryTime: tmr,
|
||||
expiresOn: tmr,
|
||||
ipRange: { start: "0.0.0.0", end: "255.255.255.255" },
|
||||
permissions: AccountSASPermissions.parse("rwdlacup").toString(),
|
||||
protocol: SASProtocol.HTTPSandHTTP,
|
||||
permissions: AccountSASPermissions.parse("rwdlacup"),
|
||||
protocol: SASProtocol.HttpsAndHttp,
|
||||
resourceTypes: AccountSASResourceTypes.parse("sco").toString(),
|
||||
services: AccountSASServices.parse("btqf").toString(),
|
||||
startTime: now,
|
||||
startsOn: now,
|
||||
version: "2019-02-02"
|
||||
},
|
||||
sharedKeyCredential as SharedKeyCredential
|
||||
storageSharedKeyCredential as StorageSharedKeyCredential
|
||||
).toString();
|
||||
|
||||
const sasURL = `${serviceURL.url}?${sas}`;
|
||||
const serviceURLWithSAS = new ServiceURL(
|
||||
const sasURL = `${serviceClient.url}?${sas}`;
|
||||
const serviceClientWithSAS = new QueueServiceClient(
|
||||
sasURL,
|
||||
StorageURL.newPipeline(new AnonymousCredential())
|
||||
newPipeline(new AnonymousCredential())
|
||||
);
|
||||
|
||||
await serviceURLWithSAS.getProperties(Aborter.none);
|
||||
await serviceClientWithSAS.getProperties();
|
||||
});
|
||||
|
||||
it("generateAccountSASQueryParameters should not work with invalid permission @loki", async () => {
|
||||
|
@ -122,28 +122,28 @@ describe("Queue SAS test", () => {
|
|||
tmr.setDate(tmr.getDate() + 1);
|
||||
|
||||
// By default, credential is always the last element of pipeline factories
|
||||
const factories = serviceURL.pipeline.factories;
|
||||
const sharedKeyCredential = factories[factories.length - 1];
|
||||
const factories = (serviceClient as any).pipeline.factories;
|
||||
const storageSharedKeyCredential = factories[factories.length - 1];
|
||||
|
||||
const sas = generateAccountSASQueryParameters(
|
||||
{
|
||||
expiryTime: tmr,
|
||||
permissions: AccountSASPermissions.parse("wdlcup").toString(),
|
||||
expiresOn: tmr,
|
||||
permissions: AccountSASPermissions.parse("wdlcup"),
|
||||
resourceTypes: AccountSASResourceTypes.parse("sco").toString(),
|
||||
services: AccountSASServices.parse("btqf").toString()
|
||||
},
|
||||
sharedKeyCredential as SharedKeyCredential
|
||||
storageSharedKeyCredential as StorageSharedKeyCredential
|
||||
).toString();
|
||||
|
||||
const sasURL = `${serviceURL.url}?${sas}`;
|
||||
const serviceURLWithSAS = new ServiceURL(
|
||||
const sasURL = `${serviceClient.url}?${sas}`;
|
||||
const serviceClientWithSAS = new QueueServiceClient(
|
||||
sasURL,
|
||||
StorageURL.newPipeline(new AnonymousCredential())
|
||||
newPipeline(new AnonymousCredential())
|
||||
);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await serviceURLWithSAS.getProperties(Aborter.none);
|
||||
await serviceClientWithSAS.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
@ -157,28 +157,28 @@ describe("Queue SAS test", () => {
|
|||
tmr.setDate(tmr.getDate() + 1);
|
||||
|
||||
// By default, credential is always the last element of pipeline factories
|
||||
const factories = serviceURL.pipeline.factories;
|
||||
const sharedKeyCredential = factories[factories.length - 1];
|
||||
const factories = (serviceClient as any).pipeline.factories;
|
||||
const storageSharedKeyCredential = factories[factories.length - 1];
|
||||
|
||||
const sas = generateAccountSASQueryParameters(
|
||||
{
|
||||
expiryTime: tmr,
|
||||
permissions: AccountSASPermissions.parse("rwdlacup").toString(),
|
||||
expiresOn: tmr,
|
||||
permissions: AccountSASPermissions.parse("rwdlacup"),
|
||||
resourceTypes: AccountSASResourceTypes.parse("sco").toString(),
|
||||
services: AccountSASServices.parse("btf").toString()
|
||||
},
|
||||
sharedKeyCredential as SharedKeyCredential
|
||||
storageSharedKeyCredential as StorageSharedKeyCredential
|
||||
).toString();
|
||||
|
||||
const sasURL = `${serviceURL.url}?${sas}`;
|
||||
const serviceURLWithSAS = new ServiceURL(
|
||||
const sasURL = `${serviceClient.url}?${sas}`;
|
||||
const serviceClientWithSAS = new QueueServiceClient(
|
||||
sasURL,
|
||||
StorageURL.newPipeline(new AnonymousCredential())
|
||||
newPipeline(new AnonymousCredential())
|
||||
);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await serviceURLWithSAS.getProperties(Aborter.none);
|
||||
await serviceClientWithSAS.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
@ -191,31 +191,31 @@ describe("Queue SAS test", () => {
|
|||
tmr.setDate(tmr.getDate() + 1);
|
||||
|
||||
// By default, credential is always the last element of pipeline factories
|
||||
const factories = serviceURL.pipeline.factories;
|
||||
const sharedKeyCredential = factories[factories.length - 1];
|
||||
const factories = (serviceClient as any).pipeline.factories;
|
||||
const storageSharedKeyCredential = factories[factories.length - 1];
|
||||
|
||||
const sas = generateAccountSASQueryParameters(
|
||||
{
|
||||
expiryTime: tmr,
|
||||
expiresOn: tmr,
|
||||
ipRange: { start: "0.0.0.0", end: "255.255.255.255" },
|
||||
permissions: AccountSASPermissions.parse("rwdlacup").toString(),
|
||||
protocol: SASProtocol.HTTPSandHTTP,
|
||||
permissions: AccountSASPermissions.parse("rwdlacup"),
|
||||
protocol: SASProtocol.HttpsAndHttp,
|
||||
resourceTypes: AccountSASResourceTypes.parse("co").toString(),
|
||||
services: AccountSASServices.parse("btqf").toString(),
|
||||
version: "2019-02-02"
|
||||
},
|
||||
sharedKeyCredential as SharedKeyCredential
|
||||
storageSharedKeyCredential as StorageSharedKeyCredential
|
||||
).toString();
|
||||
|
||||
const sasURL = `${serviceURL.url}?${sas}`;
|
||||
const serviceURLWithSAS = new ServiceURL(
|
||||
const sasURL = `${serviceClient.url}?${sas}`;
|
||||
const serviceClientWithSAS = new QueueServiceClient(
|
||||
sasURL,
|
||||
StorageURL.newPipeline(new AnonymousCredential())
|
||||
newPipeline(new AnonymousCredential())
|
||||
);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await serviceURLWithSAS.getProperties(Aborter.none);
|
||||
await serviceClientWithSAS.getProperties();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
@ -228,58 +228,58 @@ describe("Queue SAS test", () => {
|
|||
tmr.setDate(tmr.getDate() + 1);
|
||||
|
||||
// By default, credential is always the last element of pipeline factories
|
||||
const factories = serviceURL.pipeline.factories;
|
||||
const sharedKeyCredential = factories[factories.length - 1];
|
||||
const factories = (serviceClient as any).pipeline.factories;
|
||||
const storageSharedKeyCredential = factories[factories.length - 1];
|
||||
|
||||
const sas1 = generateAccountSASQueryParameters(
|
||||
{
|
||||
expiryTime: tmr,
|
||||
expiresOn: tmr,
|
||||
ipRange: { start: "0.0.0.0", end: "255.255.255.255" },
|
||||
permissions: AccountSASPermissions.parse("rdlacup").toString(),
|
||||
protocol: SASProtocol.HTTPSandHTTP,
|
||||
permissions: AccountSASPermissions.parse("rdlacup"),
|
||||
protocol: SASProtocol.HttpsAndHttp,
|
||||
resourceTypes: AccountSASResourceTypes.parse("co").toString(),
|
||||
services: AccountSASServices.parse("btqf").toString(),
|
||||
version: "2019-02-02"
|
||||
},
|
||||
sharedKeyCredential as SharedKeyCredential
|
||||
storageSharedKeyCredential as StorageSharedKeyCredential
|
||||
).toString();
|
||||
|
||||
const sas2 = generateAccountSASQueryParameters(
|
||||
{
|
||||
expiryTime: tmr,
|
||||
expiresOn: tmr,
|
||||
ipRange: { start: "0.0.0.0", end: "255.255.255.255" },
|
||||
permissions: AccountSASPermissions.parse("rwdlaup").toString(),
|
||||
protocol: SASProtocol.HTTPSandHTTP,
|
||||
permissions: AccountSASPermissions.parse("rwdlaup"),
|
||||
protocol: SASProtocol.HttpsAndHttp,
|
||||
resourceTypes: AccountSASResourceTypes.parse("co").toString(),
|
||||
services: AccountSASServices.parse("btqf").toString(),
|
||||
version: "2019-02-02"
|
||||
},
|
||||
sharedKeyCredential as SharedKeyCredential
|
||||
storageSharedKeyCredential as StorageSharedKeyCredential
|
||||
).toString();
|
||||
|
||||
const sasURL1 = `${serviceURL.url}?${sas1}`;
|
||||
const sasURL2 = `${serviceURL.url}?${sas2}`;
|
||||
const sasURL1 = `${serviceClient.url}?${sas1}`;
|
||||
const sasURL2 = `${serviceClient.url}?${sas2}`;
|
||||
|
||||
const serviceURLWithSAS1 = new ServiceURL(
|
||||
const serviceClientWithSAS1 = new QueueServiceClient(
|
||||
sasURL1,
|
||||
StorageURL.newPipeline(new AnonymousCredential())
|
||||
newPipeline(new AnonymousCredential())
|
||||
);
|
||||
const serviceURLWithSAS2 = new ServiceURL(
|
||||
const serviceClientWithSAS2 = new QueueServiceClient(
|
||||
sasURL2,
|
||||
StorageURL.newPipeline(new AnonymousCredential())
|
||||
newPipeline(new AnonymousCredential())
|
||||
);
|
||||
|
||||
const queueName1 = getUniqueName("queue1");
|
||||
const queueName2 = getUniqueName("queue2");
|
||||
|
||||
const queueURL1 = QueueURL.fromServiceURL(serviceURLWithSAS1, queueName1);
|
||||
await queueURL1.create(Aborter.none);
|
||||
const queueClient1 = serviceClientWithSAS1.getQueueClient(queueName1);
|
||||
await queueClient1.create();
|
||||
|
||||
const queueURL2 = QueueURL.fromServiceURL(serviceURLWithSAS2, queueName2);
|
||||
await queueURL2.create(Aborter.none);
|
||||
const queueClient2 = serviceClientWithSAS2.getQueueClient(queueName2);
|
||||
await queueClient2.create();
|
||||
|
||||
await queueURL1.delete(Aborter.none);
|
||||
await queueURL2.delete(Aborter.none);
|
||||
await queueClient1.delete();
|
||||
await queueClient2.delete();
|
||||
});
|
||||
|
||||
it("Create queue shouldn't work without write (w) and create (c) permission in account SAS @loki", async () => {
|
||||
|
@ -287,34 +287,34 @@ describe("Queue SAS test", () => {
|
|||
tmr.setDate(tmr.getDate() + 1);
|
||||
|
||||
// By default, credential is always the last element of pipeline factories
|
||||
const factories = serviceURL.pipeline.factories;
|
||||
const sharedKeyCredential = factories[factories.length - 1];
|
||||
const factories = (serviceClient as any).pipeline.factories;
|
||||
const storageSharedKeyCredential = factories[factories.length - 1];
|
||||
|
||||
const sas = generateAccountSASQueryParameters(
|
||||
{
|
||||
expiryTime: tmr,
|
||||
expiresOn: tmr,
|
||||
ipRange: { start: "0.0.0.0", end: "255.255.255.255" },
|
||||
permissions: AccountSASPermissions.parse("rdlaup").toString(),
|
||||
protocol: SASProtocol.HTTPSandHTTP,
|
||||
permissions: AccountSASPermissions.parse("rdlaup"),
|
||||
protocol: SASProtocol.HttpsAndHttp,
|
||||
resourceTypes: AccountSASResourceTypes.parse("co").toString(),
|
||||
services: AccountSASServices.parse("btqf").toString(),
|
||||
version: "2019-02-02"
|
||||
},
|
||||
sharedKeyCredential as SharedKeyCredential
|
||||
storageSharedKeyCredential as StorageSharedKeyCredential
|
||||
).toString();
|
||||
|
||||
const sasURL = `${serviceURL.url}?${sas}`;
|
||||
const serviceURLWithSAS = new ServiceURL(
|
||||
const sasURL = `${serviceClient.url}?${sas}`;
|
||||
const serviceClientWithSAS = new QueueServiceClient(
|
||||
sasURL,
|
||||
StorageURL.newPipeline(new AnonymousCredential())
|
||||
newPipeline(new AnonymousCredential())
|
||||
);
|
||||
|
||||
const queueName = getUniqueName("queue");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURLWithSAS, queueName);
|
||||
const queueClient = serviceClientWithSAS.getQueueClient(queueName);
|
||||
// this copy should throw 403 error
|
||||
let error;
|
||||
try {
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueClient.create();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
@ -330,35 +330,35 @@ describe("Queue SAS test", () => {
|
|||
tmr.setDate(tmr.getDate() + 1);
|
||||
|
||||
// By default, credential is always the last element of pipeline factories
|
||||
const factories = serviceURL.pipeline.factories;
|
||||
const sharedKeyCredential = factories[factories.length - 1];
|
||||
const factories = (serviceClient as any).pipeline.factories;
|
||||
const storageSharedKeyCredential = factories[factories.length - 1];
|
||||
|
||||
const sas = generateAccountSASQueryParameters(
|
||||
{
|
||||
expiryTime: tmr,
|
||||
expiresOn: tmr,
|
||||
ipRange: { start: "0.0.0.0", end: "255.255.255.255" },
|
||||
permissions: AccountSASPermissions.parse("rwdlcaup").toString(),
|
||||
protocol: SASProtocol.HTTPSandHTTP,
|
||||
permissions: AccountSASPermissions.parse("rwdlcaup"),
|
||||
protocol: SASProtocol.HttpsAndHttp,
|
||||
resourceTypes: AccountSASResourceTypes.parse("co").toString(),
|
||||
services: AccountSASServices.parse("btqf").toString(),
|
||||
version: "2019-02-02"
|
||||
},
|
||||
sharedKeyCredential as SharedKeyCredential
|
||||
storageSharedKeyCredential as StorageSharedKeyCredential
|
||||
).toString();
|
||||
|
||||
const sasURL = `${serviceURL.url}?${sas}`;
|
||||
const serviceURLWithSAS = new ServiceURL(
|
||||
const sasURL = `${serviceClient.url}?${sas}`;
|
||||
const serviceClientWithSAS = new QueueServiceClient(
|
||||
sasURL,
|
||||
StorageURL.newPipeline(new AnonymousCredential())
|
||||
newPipeline(new AnonymousCredential())
|
||||
);
|
||||
const queueName = getUniqueName("queue");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURLWithSAS, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
const queueClient = serviceClientWithSAS.getQueueClient(queueName);
|
||||
await queueClient.create();
|
||||
|
||||
const properties = await queueURL.getProperties(Aborter.none);
|
||||
await queueURL.setMetadata(Aborter.none, properties.metadata);
|
||||
const properties = await queueClient.getProperties();
|
||||
await queueClient.setMetadata(properties.metadata);
|
||||
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.delete();
|
||||
});
|
||||
|
||||
it("Get/Set ACL with AccountSAS is not allowed @loki", async () => {
|
||||
|
@ -369,40 +369,37 @@ describe("Queue SAS test", () => {
|
|||
tmr.setDate(tmr.getDate() + 1);
|
||||
|
||||
// By default, credential is always the last element of pipeline factories
|
||||
const factories = serviceURL.pipeline.factories;
|
||||
const sharedKeyCredential = factories[factories.length - 1];
|
||||
const factories = (serviceClient as any).pipeline.factories;
|
||||
const storageSharedKeyCredential = factories[factories.length - 1];
|
||||
|
||||
const queueName = getUniqueName("queue");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
await queueClient.create();
|
||||
|
||||
const sas = generateAccountSASQueryParameters(
|
||||
{
|
||||
expiryTime: tmr,
|
||||
expiresOn: tmr,
|
||||
ipRange: { start: "0.0.0.0", end: "255.255.255.255" },
|
||||
permissions: AccountSASPermissions.parse("rwdlcaup").toString(),
|
||||
protocol: SASProtocol.HTTPSandHTTP,
|
||||
permissions: AccountSASPermissions.parse("rwdlcaup"),
|
||||
protocol: SASProtocol.HttpsAndHttp,
|
||||
resourceTypes: AccountSASResourceTypes.parse("co").toString(),
|
||||
services: AccountSASServices.parse("btqf").toString(),
|
||||
version: "2019-02-02"
|
||||
},
|
||||
sharedKeyCredential as SharedKeyCredential
|
||||
storageSharedKeyCredential as StorageSharedKeyCredential
|
||||
).toString();
|
||||
|
||||
const sasURL = `${serviceURL.url}?${sas}`;
|
||||
const serviceURLWithSAS = new ServiceURL(
|
||||
const sasURL = `${serviceClient.url}?${sas}`;
|
||||
const serviceClientWithSAS = new QueueServiceClient(
|
||||
sasURL,
|
||||
StorageURL.newPipeline(new AnonymousCredential())
|
||||
newPipeline(new AnonymousCredential())
|
||||
);
|
||||
|
||||
const queueURLwithSAS = QueueURL.fromServiceURL(
|
||||
serviceURLWithSAS,
|
||||
queueName
|
||||
);
|
||||
const queueClientWithSAS = serviceClientWithSAS.getQueueClient(queueName);
|
||||
|
||||
let errorGet;
|
||||
try {
|
||||
await queueURLwithSAS.getAccessPolicy(Aborter.none);
|
||||
await queueClientWithSAS.getAccessPolicy();
|
||||
} catch (err) {
|
||||
errorGet = err;
|
||||
}
|
||||
|
@ -411,14 +408,14 @@ describe("Queue SAS test", () => {
|
|||
|
||||
let errorSet;
|
||||
try {
|
||||
await queueURLwithSAS.setAccessPolicy(Aborter.none);
|
||||
await queueClientWithSAS.setAccessPolicy();
|
||||
} catch (err) {
|
||||
errorSet = err;
|
||||
}
|
||||
assert.ok(errorSet);
|
||||
assert.deepEqual(errorSet.statusCode, 403);
|
||||
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.delete();
|
||||
});
|
||||
|
||||
it("generateAccountSASQueryParameters should work for messages @loki", async () => {
|
||||
|
@ -429,49 +426,45 @@ describe("Queue SAS test", () => {
|
|||
tmr.setDate(tmr.getDate() + 1);
|
||||
|
||||
// By default, credential is always the last element of pipeline factories
|
||||
const factories = serviceURL.pipeline.factories;
|
||||
const sharedKeyCredential = factories[factories.length - 1];
|
||||
const factories = (serviceClient as any).pipeline.factories;
|
||||
const storageSharedKeyCredential = factories[factories.length - 1];
|
||||
|
||||
const queueName = getUniqueName("queue");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
await queueClient.create();
|
||||
|
||||
const sas = generateAccountSASQueryParameters(
|
||||
{
|
||||
expiryTime: tmr,
|
||||
expiresOn: tmr,
|
||||
ipRange: { start: "0.0.0.0", end: "255.255.255.255" },
|
||||
permissions: AccountSASPermissions.parse("rwdlcaup").toString(),
|
||||
protocol: SASProtocol.HTTPSandHTTP,
|
||||
permissions: AccountSASPermissions.parse("rwdlcaup"),
|
||||
protocol: SASProtocol.HttpsAndHttp,
|
||||
resourceTypes: AccountSASResourceTypes.parse("co").toString(),
|
||||
services: AccountSASServices.parse("btqf").toString(),
|
||||
version: "2019-02-02"
|
||||
},
|
||||
sharedKeyCredential as SharedKeyCredential
|
||||
storageSharedKeyCredential as StorageSharedKeyCredential
|
||||
).toString();
|
||||
|
||||
const sasURL = `${serviceURL.url}?${sas}`;
|
||||
const serviceURLWithSAS = new ServiceURL(
|
||||
const sasURL = `${serviceClient.url}?${sas}`;
|
||||
const serviceClientWithSAS = new QueueServiceClient(
|
||||
sasURL,
|
||||
StorageURL.newPipeline(new AnonymousCredential())
|
||||
newPipeline(new AnonymousCredential())
|
||||
);
|
||||
|
||||
const queueURLwithSAS = QueueURL.fromServiceURL(
|
||||
serviceURLWithSAS,
|
||||
queueName
|
||||
);
|
||||
const messagesURLwithSAS = MessagesURL.fromQueueURL(queueURLwithSAS);
|
||||
const queueClientWithSAS = serviceClientWithSAS.getQueueClient(queueName);
|
||||
const messageContent = "test text";
|
||||
|
||||
await messagesURLwithSAS.enqueue(Aborter.none, messageContent);
|
||||
await messagesURLwithSAS.enqueue(Aborter.none, messageContent);
|
||||
await messagesURLwithSAS.peek(Aborter.none);
|
||||
await messagesURLwithSAS.dequeue(Aborter.none);
|
||||
await messagesURLwithSAS.clear(Aborter.none);
|
||||
await queueClientWithSAS.sendMessage(messageContent);
|
||||
await queueClientWithSAS.sendMessage(messageContent);
|
||||
await queueClientWithSAS.peekMessages();
|
||||
await queueClientWithSAS.receiveMessages();
|
||||
await queueClientWithSAS.clearMessages();
|
||||
|
||||
let pResult2 = await messagesURLwithSAS.peek(Aborter.none);
|
||||
let pResult2 = await queueClientWithSAS.peekMessages();
|
||||
assert.deepStrictEqual(pResult2.peekedMessageItems.length, 0);
|
||||
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.delete();
|
||||
});
|
||||
|
||||
it("generateAccountSASQueryParameters should work for messages @loki", async () => {
|
||||
|
@ -482,49 +475,45 @@ describe("Queue SAS test", () => {
|
|||
tmr.setDate(tmr.getDate() + 1);
|
||||
|
||||
// By default, credential is always the last element of pipeline factories
|
||||
const factories = serviceURL.pipeline.factories;
|
||||
const sharedKeyCredential = factories[factories.length - 1];
|
||||
const factories = (serviceClient as any).pipeline.factories;
|
||||
const storageSharedKeyCredential = factories[factories.length - 1];
|
||||
|
||||
const queueName = getUniqueName("queue");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
await queueClient.create();
|
||||
|
||||
const sas = generateAccountSASQueryParameters(
|
||||
{
|
||||
expiryTime: tmr,
|
||||
expiresOn: tmr,
|
||||
ipRange: { start: "0.0.0.0", end: "255.255.255.255" },
|
||||
permissions: AccountSASPermissions.parse("rwdlcaup").toString(),
|
||||
protocol: SASProtocol.HTTPSandHTTP,
|
||||
permissions: AccountSASPermissions.parse("rwdlcaup"),
|
||||
protocol: SASProtocol.HttpsAndHttp,
|
||||
resourceTypes: AccountSASResourceTypes.parse("co").toString(),
|
||||
services: AccountSASServices.parse("btqf").toString(),
|
||||
version: "2019-02-02"
|
||||
},
|
||||
sharedKeyCredential as SharedKeyCredential
|
||||
storageSharedKeyCredential as StorageSharedKeyCredential
|
||||
).toString();
|
||||
|
||||
const sasURL = `${serviceURL.url}?${sas}`;
|
||||
const serviceURLWithSAS = new ServiceURL(
|
||||
const sasURL = `${serviceClient.url}?${sas}`;
|
||||
const serviceClientWithSAS = new QueueServiceClient(
|
||||
sasURL,
|
||||
StorageURL.newPipeline(new AnonymousCredential())
|
||||
newPipeline(new AnonymousCredential())
|
||||
);
|
||||
|
||||
const queueURLwithSAS = QueueURL.fromServiceURL(
|
||||
serviceURLWithSAS,
|
||||
queueName
|
||||
);
|
||||
const messagesURLwithSAS = MessagesURL.fromQueueURL(queueURLwithSAS);
|
||||
const queueClientWithSAS = serviceClientWithSAS.getQueueClient(queueName);
|
||||
const messageContent = "test text";
|
||||
|
||||
await messagesURLwithSAS.enqueue(Aborter.none, messageContent);
|
||||
await messagesURLwithSAS.enqueue(Aborter.none, messageContent);
|
||||
await messagesURLwithSAS.peek(Aborter.none);
|
||||
await messagesURLwithSAS.dequeue(Aborter.none);
|
||||
await messagesURLwithSAS.clear(Aborter.none);
|
||||
await queueClientWithSAS.sendMessage(messageContent);
|
||||
await queueClientWithSAS.sendMessage(messageContent);
|
||||
await queueClientWithSAS.peekMessages();
|
||||
await queueClientWithSAS.receiveMessages();
|
||||
await queueClientWithSAS.clearMessages();
|
||||
|
||||
let pResult2 = await messagesURLwithSAS.peek(Aborter.none);
|
||||
let pResult2 = await queueClientWithSAS.peekMessages();
|
||||
assert.deepStrictEqual(pResult2.peekedMessageItems.length, 0);
|
||||
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.delete();
|
||||
});
|
||||
|
||||
it("generateQueueSASQueryParameters should work for queue @loki", async () => {
|
||||
|
@ -535,34 +524,34 @@ describe("Queue SAS test", () => {
|
|||
tmr.setDate(tmr.getDate() + 1);
|
||||
|
||||
// By default, credential is always the last element of pipeline factories
|
||||
const factories = serviceURL.pipeline.factories;
|
||||
const sharedKeyCredential = factories[factories.length - 1];
|
||||
const factories = (serviceClient as any).pipeline.factories;
|
||||
const storageSharedKeyCredential = factories[factories.length - 1];
|
||||
|
||||
const queueName = getUniqueName("queue");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
await queueClient.create();
|
||||
|
||||
const queueSAS = generateQueueSASQueryParameters(
|
||||
{
|
||||
queueName,
|
||||
expiryTime: tmr,
|
||||
expiresOn: tmr,
|
||||
ipRange: { start: "0.0.0.0", end: "255.255.255.255" },
|
||||
permissions: QueueSASPermissions.parse("raup").toString(),
|
||||
protocol: SASProtocol.HTTPSandHTTP,
|
||||
startTime: now,
|
||||
permissions: QueueSASPermissions.parse("raup"),
|
||||
protocol: SASProtocol.HttpsAndHttp,
|
||||
startsOn: now,
|
||||
version: "2019-02-02"
|
||||
},
|
||||
sharedKeyCredential as SharedKeyCredential
|
||||
storageSharedKeyCredential as StorageSharedKeyCredential
|
||||
);
|
||||
|
||||
const sasURL = `${queueURL.url}?${queueSAS}`;
|
||||
const queueURLwithSAS = new QueueURL(
|
||||
const sasURL = `${queueClient.url}?${queueSAS}`;
|
||||
const queueClientWithSAS = new QueueClient(
|
||||
sasURL,
|
||||
StorageURL.newPipeline(new AnonymousCredential())
|
||||
newPipeline(new AnonymousCredential())
|
||||
);
|
||||
|
||||
await queueURLwithSAS.getProperties(Aborter.none);
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClientWithSAS.getProperties();
|
||||
await queueClient.delete();
|
||||
});
|
||||
|
||||
it("generateQueueSASQueryParameters should work for messages @loki", async () => {
|
||||
|
@ -573,58 +562,53 @@ describe("Queue SAS test", () => {
|
|||
tmr.setDate(tmr.getDate() + 1);
|
||||
|
||||
// By default, credential is always the last element of pipeline factories
|
||||
const factories = serviceURL.pipeline.factories;
|
||||
const sharedKeyCredential = factories[factories.length - 1];
|
||||
const factories = (serviceClient as any).pipeline.factories;
|
||||
const storageSharedKeyCredential = factories[factories.length - 1];
|
||||
|
||||
const queueName = getUniqueName("queue");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
await queueClient.create();
|
||||
|
||||
const queueSAS = generateQueueSASQueryParameters(
|
||||
{
|
||||
queueName: queueName,
|
||||
expiryTime: tmr,
|
||||
expiresOn: tmr,
|
||||
ipRange: { start: "0.0.0.0", end: "255.255.255.255" },
|
||||
permissions: QueueSASPermissions.parse("raup").toString(),
|
||||
protocol: SASProtocol.HTTPSandHTTP,
|
||||
startTime: now,
|
||||
permissions: QueueSASPermissions.parse("raup"),
|
||||
protocol: SASProtocol.HttpsAndHttp,
|
||||
startsOn: now,
|
||||
version: "2016-05-31"
|
||||
},
|
||||
sharedKeyCredential as SharedKeyCredential
|
||||
storageSharedKeyCredential as StorageSharedKeyCredential
|
||||
);
|
||||
|
||||
const messageContent = "Hello World!";
|
||||
|
||||
const messagesURL = MessagesURL.fromQueueURL(queueURL);
|
||||
const sasURLForMessages = `${messagesURL.url}?${queueSAS}`;
|
||||
const messagesURLWithSAS = new MessagesURL(
|
||||
const sasURLForMessages = `${queueClient.url}?${queueSAS}`;
|
||||
const queueClientWithSAS = new QueueClient(
|
||||
sasURLForMessages,
|
||||
StorageURL.newPipeline(new AnonymousCredential())
|
||||
);
|
||||
const enqueueResult = await messagesURLWithSAS.enqueue(
|
||||
Aborter.none,
|
||||
messageContent
|
||||
newPipeline(new AnonymousCredential())
|
||||
);
|
||||
const enqueueResult = await queueClientWithSAS.sendMessage(messageContent);
|
||||
|
||||
let pResult = await messagesURL.peek(Aborter.none);
|
||||
let pResult = await queueClientWithSAS.peekMessages();
|
||||
assert.deepStrictEqual(pResult.peekedMessageItems.length, 1);
|
||||
|
||||
const messageIdURL = MessageIdURL.fromMessagesURL(
|
||||
messagesURL,
|
||||
enqueueResult.messageId
|
||||
);
|
||||
const sasURLForMessageId = `${messageIdURL.url}?${queueSAS}`;
|
||||
const messageIdURLWithSAS = new MessageIdURL(
|
||||
const sasURLForMessageId = `${queueClientWithSAS.url}?${queueSAS}`;
|
||||
const queueIdClientWithSAS = new QueueClient(
|
||||
sasURLForMessageId,
|
||||
StorageURL.newPipeline(new AnonymousCredential())
|
||||
newPipeline(new AnonymousCredential())
|
||||
);
|
||||
|
||||
await messageIdURLWithSAS.delete(Aborter.none, enqueueResult.popReceipt);
|
||||
await queueIdClientWithSAS.deleteMessage(
|
||||
enqueueResult.messageId,
|
||||
enqueueResult.popReceipt
|
||||
);
|
||||
|
||||
pResult = await messagesURL.peek(Aborter.none);
|
||||
pResult = await queueClient.peekMessages();
|
||||
assert.deepStrictEqual(pResult.peekedMessageItems.length, 0);
|
||||
|
||||
await queueURL.delete(Aborter.none);
|
||||
await queueClient.delete();
|
||||
});
|
||||
|
||||
it("generateQueueSASQueryParameters should work for queue with access policy @loki", async () => {
|
||||
|
@ -635,20 +619,20 @@ describe("Queue SAS test", () => {
|
|||
tmr.setDate(tmr.getDate() + 1);
|
||||
|
||||
// By default, credential is always the last element of pipeline factories
|
||||
const factories = serviceURL.pipeline.factories;
|
||||
const sharedKeyCredential = factories[factories.length - 1];
|
||||
const factories = (serviceClient as any).pipeline.factories;
|
||||
const storageSharedKeyCredential = factories[factories.length - 1];
|
||||
|
||||
const queueName = getUniqueName("queue");
|
||||
const queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
const queueClient = serviceClient.getQueueClient(queueName);
|
||||
await queueClient.create();
|
||||
|
||||
const id = "unique-id";
|
||||
await queueURL.setAccessPolicy(Aborter.none, [
|
||||
await queueClient.setAccessPolicy([
|
||||
{
|
||||
accessPolicy: {
|
||||
expiry: tmr,
|
||||
permission: QueueSASPermissions.parse("raup").toString(),
|
||||
start: now
|
||||
expiresOn: tmr,
|
||||
permissions: QueueSASPermissions.parse("raup").toString(),
|
||||
startsOn: now
|
||||
},
|
||||
id
|
||||
}
|
||||
|
@ -659,52 +643,42 @@ describe("Queue SAS test", () => {
|
|||
queueName,
|
||||
identifier: id
|
||||
},
|
||||
sharedKeyCredential as SharedKeyCredential
|
||||
storageSharedKeyCredential as StorageSharedKeyCredential
|
||||
);
|
||||
|
||||
const messagesURL = MessagesURL.fromQueueURL(queueURL);
|
||||
|
||||
const sasURL = `${messagesURL.url}?${queueSAS}`;
|
||||
const messagesURLwithSAS = new MessagesURL(
|
||||
const sasURL = `${queueClient.url}?${queueSAS}`;
|
||||
const queueClientWithSAS = new QueueClient(
|
||||
sasURL,
|
||||
StorageURL.newPipeline(new AnonymousCredential())
|
||||
newPipeline(new AnonymousCredential())
|
||||
);
|
||||
|
||||
const messageContent = "hello";
|
||||
|
||||
const eResult = await messagesURLwithSAS.enqueue(
|
||||
Aborter.none,
|
||||
messageContent
|
||||
);
|
||||
const eResult = await queueClientWithSAS.sendMessage(messageContent);
|
||||
assert.ok(eResult.messageId);
|
||||
const pResult = await messagesURLwithSAS.peek(Aborter.none);
|
||||
const pResult = await queueClientWithSAS.peekMessages();
|
||||
assert.deepStrictEqual(
|
||||
pResult.peekedMessageItems[0].messageText,
|
||||
messageContent
|
||||
);
|
||||
const dResult = await messagesURLwithSAS.dequeue(Aborter.none, {
|
||||
const dResult = await queueClientWithSAS.receiveMessages({
|
||||
visibilitytimeout: 1
|
||||
});
|
||||
assert.deepStrictEqual(
|
||||
dResult.dequeuedMessageItems[0].messageText,
|
||||
dResult.receivedMessageItems[0].messageText,
|
||||
messageContent
|
||||
);
|
||||
|
||||
await sleep(2 * 1000);
|
||||
|
||||
const messageIdURL = MessageIdURL.fromMessagesURL(
|
||||
messagesURL,
|
||||
dResult.dequeuedMessageItems[0].messageId
|
||||
);
|
||||
|
||||
const sasURLForMessage = `${messageIdURL.url}?${queueSAS}`;
|
||||
const messageIdURLwithSAS = new MessageIdURL(
|
||||
const sasURLForMessage = `${queueClientWithSAS.url}?${queueSAS}`;
|
||||
const queueIdClientWithSAS = new QueueClient(
|
||||
sasURLForMessage,
|
||||
StorageURL.newPipeline(new AnonymousCredential())
|
||||
newPipeline(new AnonymousCredential())
|
||||
);
|
||||
const deleteResult = await messageIdURLwithSAS.delete(
|
||||
Aborter.none,
|
||||
dResult.dequeuedMessageItems[0].popReceipt
|
||||
const deleteResult = await queueIdClientWithSAS.deleteMessage(
|
||||
dResult.receivedMessageItems[0].messageId,
|
||||
dResult.receivedMessageItems[0].popReceipt
|
||||
);
|
||||
assert.ok(deleteResult.requestId);
|
||||
});
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
import * as assert from "assert";
|
||||
|
||||
import {
|
||||
Aborter,
|
||||
QueueURL,
|
||||
ServiceURL,
|
||||
SharedKeyCredential,
|
||||
StorageURL
|
||||
newPipeline,
|
||||
QueueServiceClient,
|
||||
StorageSharedKeyCredential
|
||||
} from "@azure/storage-queue";
|
||||
|
||||
import { configLogger } from "../../src/common/Logger";
|
||||
|
@ -47,10 +45,13 @@ describe("Queue SpecialNaming", () => {
|
|||
);
|
||||
|
||||
const baseURL = `http://${host}:${port}/devstoreaccount1`;
|
||||
const serviceURL = new ServiceURL(
|
||||
const serviceClient = new QueueServiceClient(
|
||||
baseURL,
|
||||
StorageURL.newPipeline(
|
||||
new SharedKeyCredential(EMULATOR_ACCOUNT_NAME, EMULATOR_ACCOUNT_KEY),
|
||||
newPipeline(
|
||||
new StorageSharedKeyCredential(
|
||||
EMULATOR_ACCOUNT_NAME,
|
||||
EMULATOR_ACCOUNT_KEY
|
||||
),
|
||||
{
|
||||
retryOptions: { maxTries: 1 }
|
||||
}
|
||||
|
@ -73,10 +74,10 @@ describe("Queue SpecialNaming", () => {
|
|||
|
||||
it("A queue name must be from 3 through 63 characters long @loki", async () => {
|
||||
let queueName = new Array(65).join("a");
|
||||
let queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
let queueClient = serviceClient.getQueueClient(queueName);
|
||||
let error;
|
||||
try {
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueClient.create();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
@ -88,10 +89,10 @@ describe("Queue SpecialNaming", () => {
|
|||
);
|
||||
|
||||
queueName = new Array(3).join("a");
|
||||
queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
queueClient = serviceClient.getQueueClient(queueName);
|
||||
error = undefined;
|
||||
try {
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueClient.create();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
@ -103,22 +104,22 @@ describe("Queue SpecialNaming", () => {
|
|||
);
|
||||
|
||||
queueName = new Array(4).join("a");
|
||||
queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueURL.delete(Aborter.none);
|
||||
queueClient = serviceClient.getQueueClient(queueName);
|
||||
await queueClient.create();
|
||||
await queueClient.delete();
|
||||
|
||||
queueName = new Array(64).join("a");
|
||||
queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueURL.delete(Aborter.none);
|
||||
queueClient = serviceClient.getQueueClient(queueName);
|
||||
await queueClient.create();
|
||||
await queueClient.delete();
|
||||
});
|
||||
|
||||
it("All letters in a queue name must be lowercase. @loki", async () => {
|
||||
let queueName = "Queue";
|
||||
let queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
let queueClient = serviceClient.getQueueClient(queueName);
|
||||
let error;
|
||||
try {
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueClient.create();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
@ -130,17 +131,17 @@ describe("Queue SpecialNaming", () => {
|
|||
);
|
||||
|
||||
queueName = "queue";
|
||||
queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueURL.delete(Aborter.none);
|
||||
queueClient = serviceClient.getQueueClient(queueName);
|
||||
await queueClient.create();
|
||||
await queueClient.delete();
|
||||
});
|
||||
|
||||
it("A queue name contains only letters, numbers, and the dash (-) character in rules @loki", async () => {
|
||||
let queueName = "-queue123";
|
||||
let queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
let queueClient = serviceClient.getQueueClient(queueName);
|
||||
let error;
|
||||
try {
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueClient.create();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
@ -152,10 +153,10 @@ describe("Queue SpecialNaming", () => {
|
|||
);
|
||||
|
||||
queueName = "queue123-";
|
||||
queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
queueClient = serviceClient.getQueueClient(queueName);
|
||||
error = undefined;
|
||||
try {
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueClient.create();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
@ -167,15 +168,15 @@ describe("Queue SpecialNaming", () => {
|
|||
);
|
||||
|
||||
queueName = "queue-123";
|
||||
queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueURL.delete(Aborter.none);
|
||||
queueClient = serviceClient.getQueueClient(queueName);
|
||||
await queueClient.create();
|
||||
await queueClient.delete();
|
||||
|
||||
queueName = "queue--123";
|
||||
queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
queueClient = serviceClient.getQueueClient(queueName);
|
||||
error = undefined;
|
||||
try {
|
||||
await queueURL.create(Aborter.none);
|
||||
await queueClient.create();
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
import {
|
||||
TokenCredential,
|
||||
AccessToken,
|
||||
GetTokenOptions
|
||||
} from "@azure/core-http";
|
||||
|
||||
export class SimpleTokenCredential implements TokenCredential {
|
||||
/**
|
||||
* The raw token string. Can be changed when the token needs to be updated.
|
||||
*/
|
||||
public token: string;
|
||||
|
||||
/**
|
||||
* The Date at which the token expires. Can be changed to update the expiration time.
|
||||
*/
|
||||
public expiresOn: number;
|
||||
|
||||
/**
|
||||
* Creates an instance of TokenCredential.
|
||||
* @param {string} token
|
||||
*/
|
||||
constructor(token: string, expiresOn?: Date) {
|
||||
this.token = token;
|
||||
this.expiresOn = expiresOn
|
||||
? expiresOn.getTime()
|
||||
: Date.now() + 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the token stored in this RawTokenCredential.
|
||||
*
|
||||
* @param _scopes Ignored since token is already known.
|
||||
* @param _options Ignored since token is already known.
|
||||
* @returns {AccessToken} The access token details.
|
||||
*/
|
||||
async getToken(
|
||||
_scopes: string | string[],
|
||||
_options?: GetTokenOptions
|
||||
): Promise<AccessToken | null> {
|
||||
return {
|
||||
token: this.token,
|
||||
expiresOnTimestamp: this.expiresOn
|
||||
};
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче