UNPKG

11.2 kBJavaScriptView Raw
1"use strict";
2/**
3 * -------------------------------------------------------------------------------------------
4 * Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
5 * See License in the project root for license information.
6 * -------------------------------------------------------------------------------------------
7 */
8Object.defineProperty(exports, "__esModule", { value: true });
9exports.ChaosHandler = void 0;
10var tslib_1 = require("tslib");
11var MiddlewareControl_1 = require("./MiddlewareControl");
12var MiddlewareUtil_1 = require("./MiddlewareUtil");
13var ChaosHandlerData_1 = require("./options/ChaosHandlerData");
14var ChaosHandlerOptions_1 = require("./options/ChaosHandlerOptions");
15var ChaosStrategy_1 = require("./options/ChaosStrategy");
16/**
17 * Class representing ChaosHandler
18 * @class
19 * Class
20 * @implements Middleware
21 */
22var ChaosHandler = /** @class */ (function () {
23 /**
24 * @public
25 * @constructor
26 * To create an instance of Testing Handler
27 * @param {ChaosHandlerOptions} [options = new ChaosHandlerOptions()] - The testing handler options instance
28 * @param manualMap - The Map passed by user containing url-statusCode info
29 * @returns An instance of Testing Handler
30 */
31 function ChaosHandler(options, manualMap) {
32 if (options === void 0) { options = new ChaosHandlerOptions_1.ChaosHandlerOptions(); }
33 this.options = options;
34 this.manualMap = manualMap;
35 }
36 /**
37 * Generates responseHeader
38 * @private
39 * @param {ChaosHandlerOptions} chaosHandlerOptions - The ChaosHandlerOptions object
40 * @param {string} requestID - request id
41 * @param {string} requestDate - date of the request
42 * @returns response Header
43 */
44 ChaosHandler.prototype.createResponseHeaders = function (chaosHandlerOptions, requestID, requestDate) {
45 var responseHeader = chaosHandlerOptions.headers ? new Headers(chaosHandlerOptions.headers) : new Headers();
46 responseHeader.append("Cache-Control", "no-store");
47 responseHeader.append("request-id", requestID);
48 responseHeader.append("client-request-id", requestID);
49 responseHeader.append("x-ms-ags-diagnostic", "");
50 responseHeader.append("Date", requestDate);
51 responseHeader.append("Strict-Transport-Security", "");
52 if (chaosHandlerOptions.statusCode === 429) {
53 // throttling case has to have a timeout scenario
54 responseHeader.append("retry-after", "3");
55 }
56 return responseHeader;
57 };
58 /**
59 * Generates responseBody
60 * @private
61 * @param {ChaosHandlerOptions} chaosHandlerOptions - The ChaosHandlerOptions object
62 * @param {string} requestID - request id
63 * @param {string} requestDate - date of the request
64 * * @returns response body
65 */
66 ChaosHandler.prototype.createResponseBody = function (chaosHandlerOptions, requestID, requestDate) {
67 if (chaosHandlerOptions.responseBody) {
68 return chaosHandlerOptions.responseBody;
69 }
70 var body;
71 if (chaosHandlerOptions.statusCode >= 400) {
72 var codeMessage = ChaosHandlerData_1.httpStatusCode[chaosHandlerOptions.statusCode];
73 var errMessage = chaosHandlerOptions.statusMessage;
74 body = {
75 error: {
76 code: codeMessage,
77 message: errMessage,
78 innerError: {
79 "request-id": requestID,
80 date: requestDate,
81 },
82 },
83 };
84 }
85 else {
86 body = {};
87 }
88 return body;
89 };
90 /**
91 * creates a response
92 * @private
93 * @param {ChaosHandlerOptions} chaosHandlerOptions - The ChaosHandlerOptions object
94 * @param {Context} context - Contains the context of the request
95 */
96 ChaosHandler.prototype.createResponse = function (chaosHandlerOptions, context) {
97 var requestURL = context.request;
98 var requestID = (0, MiddlewareUtil_1.generateUUID)();
99 var requestDate = new Date();
100 var responseHeader = this.createResponseHeaders(chaosHandlerOptions, requestID, requestDate.toString());
101 var responseBody = this.createResponseBody(chaosHandlerOptions, requestID, requestDate.toString());
102 var init = { url: requestURL, status: chaosHandlerOptions.statusCode, statusText: chaosHandlerOptions.statusMessage, headers: responseHeader };
103 context.response = new Response(typeof responseBody === "string" ? responseBody : JSON.stringify(responseBody), init);
104 };
105 /**
106 * Decides whether to send the request to the graph or not
107 * @private
108 * @param {ChaosHandlerOptions} chaosHandlerOptions - A ChaosHandlerOptions object
109 * @param {Context} context - Contains the context of the request
110 * @returns nothing
111 */
112 ChaosHandler.prototype.sendRequest = function (chaosHandlerOptions, context) {
113 return tslib_1.__awaiter(this, void 0, void 0, function () {
114 return tslib_1.__generator(this, function (_a) {
115 switch (_a.label) {
116 case 0:
117 this.setStatusCode(chaosHandlerOptions, context.request, context.options.method);
118 if (!((chaosHandlerOptions.chaosStrategy === ChaosStrategy_1.ChaosStrategy.MANUAL && !this.nextMiddleware) || Math.floor(Math.random() * 100) < chaosHandlerOptions.chaosPercentage)) return [3 /*break*/, 1];
119 this.createResponse(chaosHandlerOptions, context);
120 return [3 /*break*/, 3];
121 case 1:
122 if (!this.nextMiddleware) return [3 /*break*/, 3];
123 return [4 /*yield*/, this.nextMiddleware.execute(context)];
124 case 2:
125 _a.sent();
126 _a.label = 3;
127 case 3: return [2 /*return*/];
128 }
129 });
130 });
131 };
132 /**
133 * Fetches a random status code for the RANDOM mode from the predefined array
134 * @private
135 * @param {string} requestMethod - the API method for the request
136 * @returns a random status code from a given set of status codes
137 */
138 ChaosHandler.prototype.getRandomStatusCode = function (requestMethod) {
139 var statusCodeArray = ChaosHandlerData_1.methodStatusCode[requestMethod];
140 return statusCodeArray[Math.floor(Math.random() * statusCodeArray.length)];
141 };
142 /**
143 * To fetch the relative URL out of the complete URL using a predefined regex pattern
144 * @private
145 * @param {string} urlMethod - the complete URL
146 * @returns the string as relative URL
147 */
148 ChaosHandler.prototype.getRelativeURL = function (urlMethod) {
149 var pattern = /https?:\/\/graph\.microsoft\.com\/[^/]+(.+?)(\?|$)/;
150 var relativeURL;
151 if (pattern.exec(urlMethod) !== null) {
152 relativeURL = pattern.exec(urlMethod)[1];
153 }
154 return relativeURL;
155 };
156 /**
157 * To fetch the status code from the map(if needed), then returns response by calling createResponse
158 * @private
159 * @param {ChaosHandlerOptions} chaosHandlerOptions - The ChaosHandlerOptions object
160 * @param {string} requestURL - the URL for the request
161 * @param {string} requestMethod - the API method for the request
162 */
163 ChaosHandler.prototype.setStatusCode = function (chaosHandlerOptions, requestURL, requestMethod) {
164 var _this = this;
165 if (chaosHandlerOptions.chaosStrategy === ChaosStrategy_1.ChaosStrategy.MANUAL) {
166 if (chaosHandlerOptions.statusCode === undefined) {
167 // manual mode with no status code, can be a global level or request level without statusCode
168 var relativeURL_1 = this.getRelativeURL(requestURL);
169 if (this.manualMap.get(relativeURL_1) !== undefined) {
170 // checking Manual Map for exact match
171 if (this.manualMap.get(relativeURL_1).get(requestMethod) !== undefined) {
172 chaosHandlerOptions.statusCode = this.manualMap.get(relativeURL_1).get(requestMethod);
173 }
174 // else statusCode would be undefined
175 }
176 else {
177 // checking for regex match if exact match doesn't work
178 this.manualMap.forEach(function (value, key) {
179 var regexURL = new RegExp(key + "$");
180 if (regexURL.test(relativeURL_1)) {
181 if (_this.manualMap.get(key).get(requestMethod) !== undefined) {
182 chaosHandlerOptions.statusCode = _this.manualMap.get(key).get(requestMethod);
183 }
184 // else statusCode would be undefined
185 }
186 });
187 }
188 // Case of redirection or request url not in map ---> statusCode would be undefined
189 }
190 }
191 else {
192 // Handling the case of Random here
193 chaosHandlerOptions.statusCode = this.getRandomStatusCode(requestMethod);
194 // else statusCode would be undefined
195 }
196 };
197 /**
198 * To get the options for execution of the middleware
199 * @private
200 * @param {Context} context - The context object
201 * @returns options for middleware execution
202 */
203 ChaosHandler.prototype.getOptions = function (context) {
204 var options;
205 if (context.middlewareControl instanceof MiddlewareControl_1.MiddlewareControl) {
206 options = context.middlewareControl.getMiddlewareOptions(ChaosHandlerOptions_1.ChaosHandlerOptions);
207 }
208 if (typeof options === "undefined") {
209 options = Object.assign(new ChaosHandlerOptions_1.ChaosHandlerOptions(), this.options);
210 }
211 return options;
212 };
213 /**
214 * To execute the current middleware
215 * @public
216 * @async
217 * @param {Context} context - The context object of the request
218 * @returns A Promise that resolves to nothing
219 */
220 ChaosHandler.prototype.execute = function (context) {
221 return tslib_1.__awaiter(this, void 0, void 0, function () {
222 var chaosHandlerOptions;
223 return tslib_1.__generator(this, function (_a) {
224 switch (_a.label) {
225 case 0:
226 chaosHandlerOptions = this.getOptions(context);
227 return [4 /*yield*/, this.sendRequest(chaosHandlerOptions, context)];
228 case 1: return [2 /*return*/, _a.sent()];
229 }
230 });
231 });
232 };
233 /**
234 * @public
235 * To set the next middleware in the chain
236 * @param {Middleware} next - The middleware instance
237 * @returns Nothing
238 */
239 ChaosHandler.prototype.setNext = function (next) {
240 this.nextMiddleware = next;
241 };
242 return ChaosHandler;
243}());
244exports.ChaosHandler = ChaosHandler;
245//# sourceMappingURL=ChaosHandler.js.map
\No newline at end of file