Update tests, CI and expose SASQueryParameters only in node platform.
This commit is contained in:
Родитель
b8738de066
Коммит
48453b9698
|
@ -15,7 +15,8 @@
|
|||
],
|
||||
"reporter": [
|
||||
"text-summary",
|
||||
"html"
|
||||
"html",
|
||||
"cobertura"
|
||||
],
|
||||
"sourceMap": true,
|
||||
"instrument": true,
|
||||
|
|
|
@ -1 +1,6 @@
|
|||
# Breaking Changes
|
||||
|
||||
2019.1 Version 10.1.0
|
||||
* Updated convenience layer methods enum type parameters into typescript union types, this will help to reduce bundle footprint.
|
||||
* `SASQueryParameters` is not going to be exported in browser bundle, and will be exported in Node.js runtime.
|
||||
* IE11 needs `Array.prototype.includes` and `Object.keys` polyfills loaded.
|
|
@ -1,5 +1,16 @@
|
|||
# Changelog
|
||||
|
||||
2019.1 Version 10.1.0
|
||||
|
||||
* [Breaking] Updated convenience layer methods enum type parameters into typescript union types, this will help to reduce bundle footprint.
|
||||
* [Breaking] `SASQueryParameters` is not going to be exported in browser bundle, and will be exported in Node.js runtime.
|
||||
* [Breaking] IE11 needs `Array.prototype.includes` and `Object.keys` polyfills loaded.
|
||||
* Updated dependency `ms-rest-js` to `@azure/ms-rest-js`.
|
||||
* Updated server timeout value for retry options `tryTimeoutInMs` to 30 seconds.
|
||||
* Fixed `Aborter.timeout()` misleading scale description.
|
||||
* Fixed an issue that enqueue/dequeue/peek fail to work with some utf8 characters.
|
||||
|
||||
|
||||
2018.12 Version 10.0.0-preview
|
||||
|
||||
* Initial Release. API version 2018-03-28 supported. Please see the README for information on the new design.
|
|
@ -27,13 +27,16 @@ This SDK is compatible with Node.js and browsers, and validated against LTS Node
|
|||
|
||||
You need polyfills to make this library work with IE11. The easiest way is to use [@babel/polyfill](https://babeljs.io/docs/en/babel-polyfill), or [polyfill service](https://polyfill.io/v2/docs/).
|
||||
Or you can load separate polyfills for missed ES feature(s).
|
||||
This library depends on following ES6 features which need external polyfills loaded.
|
||||
This library depends on following ES features which need external polyfills loaded.
|
||||
|
||||
* `Promise`
|
||||
* `String.prototype.startsWith`
|
||||
* `String.prototype.endsWith`
|
||||
* `String.prototype.repeat`
|
||||
* `String.prototype.includes`
|
||||
* `Array.prototype.includes`
|
||||
* `Object.keys` (Override IE11's `Object.keys` with ES6 polyfill forcely to enable [ES6 behavior](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys#Notes))
|
||||
|
||||
|
||||
#### Differences between Node.js and browsers
|
||||
|
||||
|
|
|
@ -26,7 +26,8 @@ module.exports = function(config) {
|
|||
// list of files / patterns to load in the browser
|
||||
files: [
|
||||
// polyfill service supporting IE11 missing features
|
||||
"https://cdn.polyfill.io/v2/polyfill.min.js?features=Promise,String.prototype.startsWith,String.prototype.endsWith,String.prototype.repeat,String.prototype.includes",
|
||||
// Promise,String.prototype.startsWith,String.prototype.endsWith,String.prototype.repeat,String.prototype.includes,Array.prototype.includes,Object.keys
|
||||
"https://cdn.polyfill.io/v2/polyfill.js?features=Promise,String.prototype.startsWith,String.prototype.endsWith,String.prototype.repeat,String.prototype.includes,Array.prototype.includes,Object.keys|always",
|
||||
"dist-test/index.browser.js"
|
||||
],
|
||||
|
||||
|
@ -57,7 +58,8 @@ module.exports = function(config) {
|
|||
// Coverage report settings
|
||||
remapCoverageReporter: {
|
||||
"text-summary": null, // to show summary in console
|
||||
html: "./coverage-browser"
|
||||
html: "./coverage-browser",
|
||||
cobertura: "./coverage-browser/cobertura-coverage.xml"
|
||||
},
|
||||
|
||||
// Exclude coverage calculation for following files
|
||||
|
@ -102,6 +104,8 @@ module.exports = function(config) {
|
|||
concurrency: 1,
|
||||
|
||||
browserNoActivityTimeout: 600000,
|
||||
browserDisconnectTimeout: 10000,
|
||||
browserDisconnectTolerance: 3,
|
||||
|
||||
client: {
|
||||
mocha: {
|
||||
|
|
|
@ -19,7 +19,6 @@ export * from "./policies/TokenCredentialPolicy";
|
|||
export * from "./QueueURL"
|
||||
export * from "./QueueSASPermissions";
|
||||
export * from "./UniqueRequestIDPolicyFactory";
|
||||
export * from "./SASQueryParameters";
|
||||
export * from "./ServiceURL";
|
||||
export * from "./StorageURL";
|
||||
export { Models, RestError };
|
||||
|
|
|
@ -28,4 +28,5 @@ export * from "./IQueueSASSignatureValues"
|
|||
export * from "./UniqueRequestIDPolicyFactory";
|
||||
export * from "./ServiceURL";
|
||||
export * from "./StorageURL";
|
||||
export * from "./SASQueryParameters";
|
||||
export { Models, RestError };
|
||||
|
|
|
@ -489,7 +489,7 @@
|
|||
"resolved": "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
|
||||
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
|
||||
"requires": {
|
||||
"follow-redirects": "1.5.10",
|
||||
"follow-redirects": "1.6.0",
|
||||
"is-buffer": "1.1.6"
|
||||
}
|
||||
},
|
||||
|
@ -1942,9 +1942,9 @@
|
|||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
|
||||
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.6.0.tgz",
|
||||
"integrity": "sha512-4Oh4eI3S9OueVV41AgJ1oLjpaJUhbJ7JDGOMhe0AFqoSejl5Q2nn3eGglAzRUKVKZE8jG5MNn66TjCJMAnpsWA==",
|
||||
"requires": {
|
||||
"debug": "3.1.0"
|
||||
}
|
||||
|
@ -2947,7 +2947,7 @@
|
|||
"dev": true,
|
||||
"requires": {
|
||||
"eventemitter3": "3.1.0",
|
||||
"follow-redirects": "1.5.10",
|
||||
"follow-redirects": "1.6.0",
|
||||
"requires-port": "1.0.0"
|
||||
}
|
||||
},
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
import { URLBuilder } from "@azure/ms-rest-js";
|
||||
import * as assert from "assert";
|
||||
|
||||
import { RestError, StorageURL } from "../lib";
|
||||
import { Aborter } from "../lib/Aborter";
|
||||
import { QueueURL } from "../lib/QueueURL";
|
||||
import { Pipeline } from "../lib/Pipeline";
|
||||
import { getQSU, getUniqueName } from "./utils";
|
||||
import { InjectorPolicyFactory } from "./utils/InjectorPolicyFactory";
|
||||
|
||||
describe("RetryPolicy", () => {
|
||||
const serviceURL = getQSU();
|
||||
let queueName: string = getUniqueName("queue");
|
||||
let queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
|
||||
beforeEach(async () => {
|
||||
queueName = getUniqueName("queue");
|
||||
queueURL = QueueURL.fromServiceURL(serviceURL, queueName);
|
||||
await queueURL.create(Aborter.none);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await queueURL.delete(Aborter.none);
|
||||
});
|
||||
|
||||
it("Retry policy should work when first request fails with 500", async () => {
|
||||
let injectCounter = 0;
|
||||
const injector = new InjectorPolicyFactory(() => {
|
||||
if (injectCounter === 0) {
|
||||
injectCounter++;
|
||||
return new RestError(
|
||||
"Server Internal Error",
|
||||
"ServerInternalError",
|
||||
500
|
||||
);
|
||||
}
|
||||
});
|
||||
const factories = queueURL.pipeline.factories.slice(); // clone factories array
|
||||
factories.push(injector);
|
||||
const pipeline = new Pipeline(factories);
|
||||
const injectqueueURL = queueURL.withPipeline(pipeline);
|
||||
|
||||
const metadata = {
|
||||
key0: "val0",
|
||||
keya: "vala",
|
||||
keyb: "valb"
|
||||
};
|
||||
await injectqueueURL.setMetadata(Aborter.none, metadata);
|
||||
|
||||
const result = await queueURL.getProperties(Aborter.none);
|
||||
assert.deepEqual(result.metadata, metadata);
|
||||
});
|
||||
|
||||
it("Retry policy should failed when requests always fail with 500", async () => {
|
||||
const injector = new InjectorPolicyFactory(() => {
|
||||
return new RestError("Server Internal Error", "ServerInternalError", 500);
|
||||
});
|
||||
|
||||
const credential =
|
||||
queueURL.pipeline.factories[
|
||||
queueURL.pipeline.factories.length - 1
|
||||
];
|
||||
const factories = StorageURL.newPipeline(credential, {
|
||||
retryOptions: { maxTries: 3 }
|
||||
}).factories;
|
||||
factories.push(injector);
|
||||
const pipeline = new Pipeline(factories);
|
||||
const injectqueueURL = queueURL.withPipeline(pipeline);
|
||||
|
||||
let hasError = false;
|
||||
try {
|
||||
const metadata = {
|
||||
key0: "val0",
|
||||
keya: "vala",
|
||||
keyb: "valb"
|
||||
};
|
||||
await injectqueueURL.setMetadata(Aborter.none, metadata);
|
||||
} catch (err) {
|
||||
hasError = true;
|
||||
}
|
||||
assert.ok(hasError);
|
||||
});
|
||||
|
||||
it("Retry policy should work for secondary endpoint", async () => {
|
||||
let injectCounter = 0;
|
||||
const injector = new InjectorPolicyFactory(() => {
|
||||
if (injectCounter++ < 1) {
|
||||
return new RestError(
|
||||
"Server Internal Error",
|
||||
"ServerInternalError",
|
||||
500
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const url = serviceURL.url;
|
||||
const urlParsed = URLBuilder.parse(url);
|
||||
const host = urlParsed.getHost()!;
|
||||
const hostParts = host.split(".");
|
||||
const account = hostParts.shift();
|
||||
const secondaryAccount = `${account}-secondary`;
|
||||
hostParts.unshift(secondaryAccount);
|
||||
const secondaryHost = hostParts.join(".");
|
||||
|
||||
const credential =
|
||||
queueURL.pipeline.factories[
|
||||
queueURL.pipeline.factories.length - 1
|
||||
];
|
||||
const factories = StorageURL.newPipeline(credential, {
|
||||
retryOptions: { maxTries: 2, secondaryHost }
|
||||
}).factories;
|
||||
factories.push(injector);
|
||||
const pipeline = new Pipeline(factories);
|
||||
const injectqueueURL = queueURL.withPipeline(pipeline);
|
||||
|
||||
let finalRequestURL = "";
|
||||
try {
|
||||
const response = await injectqueueURL.getProperties(Aborter.none);
|
||||
finalRequestURL = response._response.request.url;
|
||||
} catch (err) {
|
||||
finalRequestURL = err.request ? err.request.url : "";
|
||||
}
|
||||
|
||||
assert.deepStrictEqual(
|
||||
URLBuilder.parse(finalRequestURL).getHost(),
|
||||
secondaryHost
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,58 @@
|
|||
import {
|
||||
BaseRequestPolicy,
|
||||
HttpOperationResponse,
|
||||
RequestPolicy,
|
||||
RequestPolicyOptions,
|
||||
WebResource,
|
||||
RestError
|
||||
} from "../../lib";
|
||||
|
||||
export interface INextInjectErrorHolder {
|
||||
nextInjectError?: RestError;
|
||||
}
|
||||
|
||||
export type Injector = () => RestError | undefined;
|
||||
|
||||
/**
|
||||
* InjectorPolicy will inject a customized error before next HTTP request.
|
||||
*
|
||||
* @class InjectorPolicy
|
||||
* @extends {BaseRequestPolicy}
|
||||
*/
|
||||
export class InjectorPolicy extends BaseRequestPolicy {
|
||||
/**
|
||||
* Creates an instance of InjectorPolicy.
|
||||
*
|
||||
* @param {RequestPolicy} nextPolicy
|
||||
* @param {RequestPolicyOptions} options
|
||||
* @memberof InjectorPolicy
|
||||
*/
|
||||
public constructor(
|
||||
nextPolicy: RequestPolicy,
|
||||
options: RequestPolicyOptions,
|
||||
injector: Injector
|
||||
) {
|
||||
super(nextPolicy, options);
|
||||
this.injector = injector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends request.
|
||||
*
|
||||
* @param {WebResource} request
|
||||
* @returns {Promise<HttpOperationResponse>}
|
||||
* @memberof InjectorPolicy
|
||||
*/
|
||||
public async sendRequest(
|
||||
request: WebResource
|
||||
): Promise<HttpOperationResponse> {
|
||||
const error = this.injector();
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
return this._nextPolicy.sendRequest(request);
|
||||
}
|
||||
|
||||
private injector: Injector;
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import {
|
||||
RequestPolicy,
|
||||
RequestPolicyFactory,
|
||||
RequestPolicyOptions
|
||||
} from "../../lib";
|
||||
import { InjectorPolicy, Injector } from "./InjectorPolicy";
|
||||
|
||||
/**
|
||||
* InjectorPolicyFactory is a factory class injects customized errors for retry policy testing.
|
||||
*
|
||||
* @export
|
||||
* @class InjectorPolicyFactory
|
||||
* @implements {RequestPolicyFactory}
|
||||
*/
|
||||
export class InjectorPolicyFactory implements RequestPolicyFactory {
|
||||
public readonly injector: Injector;
|
||||
|
||||
public constructor(injector: Injector) {
|
||||
this.injector = injector;
|
||||
}
|
||||
|
||||
public create(
|
||||
nextPolicy: RequestPolicy,
|
||||
options: RequestPolicyOptions
|
||||
): InjectorPolicy {
|
||||
return new InjectorPolicy(nextPolicy, options, this.injector);
|
||||
}
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче