@mbtest/mountebank 2.9.2-beta.9050

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (207) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +94 -0
  3. package/bin/mb +136 -0
  4. package/package.json +71 -0
  5. package/releases.json +52 -0
  6. package/src/cli/api.js +112 -0
  7. package/src/cli/cli.js +420 -0
  8. package/src/controllers/configController.js +64 -0
  9. package/src/controllers/feedController.js +115 -0
  10. package/src/controllers/homeController.js +58 -0
  11. package/src/controllers/imposterController.js +328 -0
  12. package/src/controllers/impostersController.js +215 -0
  13. package/src/controllers/logsController.js +52 -0
  14. package/src/models/behaviors.js +553 -0
  15. package/src/models/behaviorsValidator.js +186 -0
  16. package/src/models/compatibility.js +133 -0
  17. package/src/models/dryRunValidator.js +261 -0
  18. package/src/models/filesystemBackedImpostersRepository.js +908 -0
  19. package/src/models/http/baseHttpServer.js +207 -0
  20. package/src/models/http/headersMap.js +87 -0
  21. package/src/models/http/httpProxy.js +230 -0
  22. package/src/models/http/httpRequest.js +82 -0
  23. package/src/models/http/httpServer.js +18 -0
  24. package/src/models/http/index.js +18 -0
  25. package/src/models/https/cert/mb-cert.pem +20 -0
  26. package/src/models/https/cert/mb-csr.pem +16 -0
  27. package/src/models/https/cert/mb-key.pem +27 -0
  28. package/src/models/https/httpsServer.js +42 -0
  29. package/src/models/https/index.js +18 -0
  30. package/src/models/imposter.js +243 -0
  31. package/src/models/imposterPrinter.js +120 -0
  32. package/src/models/impostersRepository.js +49 -0
  33. package/src/models/inMemoryImpostersRepository.js +418 -0
  34. package/src/models/jsonpath.js +44 -0
  35. package/src/models/mbConnection.js +107 -0
  36. package/src/models/predicates.js +438 -0
  37. package/src/models/protocols.js +242 -0
  38. package/src/models/responseResolver.js +398 -0
  39. package/src/models/smtp/index.js +16 -0
  40. package/src/models/smtp/smtpRequest.js +60 -0
  41. package/src/models/smtp/smtpServer.js +109 -0
  42. package/src/models/tcp/index.js +18 -0
  43. package/src/models/tcp/tcpProxy.js +110 -0
  44. package/src/models/tcp/tcpRequest.js +23 -0
  45. package/src/models/tcp/tcpServer.js +156 -0
  46. package/src/models/tcp/tcpValidator.js +19 -0
  47. package/src/models/xpath.js +95 -0
  48. package/src/mountebank.js +245 -0
  49. package/src/public/images/arrow_down.png +0 -0
  50. package/src/public/images/arrow_up.png +0 -0
  51. package/src/public/images/book.jpg +0 -0
  52. package/src/public/images/dataflow.png +0 -0
  53. package/src/public/images/favicon.ico +0 -0
  54. package/src/public/images/forkme_right_orange_ff7600.png +0 -0
  55. package/src/public/images/mountebank.png +0 -0
  56. package/src/public/images/overview.gif +0 -0
  57. package/src/public/images/quote.png +0 -0
  58. package/src/public/images/tw-logo.png +0 -0
  59. package/src/public/scripts/jquery/jquery-3.6.1.min.js +2 -0
  60. package/src/public/scripts/urlHashHandler.js +31 -0
  61. package/src/public/stylesheets/application.css +424 -0
  62. package/src/public/stylesheets/ie.css +14 -0
  63. package/src/public/stylesheets/imposters.css +121 -0
  64. package/src/public/stylesheets/jqueryui/1.10.4/themes/smoothness/jquery-ui.css +1178 -0
  65. package/src/util/combinators.js +68 -0
  66. package/src/util/date.js +51 -0
  67. package/src/util/errors.js +55 -0
  68. package/src/util/helpers.js +131 -0
  69. package/src/util/inherit.js +28 -0
  70. package/src/util/ip.js +54 -0
  71. package/src/util/logger.js +83 -0
  72. package/src/util/middleware.js +256 -0
  73. package/src/util/scopedLogger.js +47 -0
  74. package/src/views/_footer.ejs +20 -0
  75. package/src/views/_header.ejs +113 -0
  76. package/src/views/_imposter.ejs +8 -0
  77. package/src/views/config.ejs +71 -0
  78. package/src/views/docs/api/behaviors/copy.ejs +427 -0
  79. package/src/views/docs/api/behaviors/decorate.ejs +182 -0
  80. package/src/views/docs/api/behaviors/lookup.ejs +220 -0
  81. package/src/views/docs/api/behaviors/shellTransform.ejs +153 -0
  82. package/src/views/docs/api/behaviors/wait.ejs +121 -0
  83. package/src/views/docs/api/behaviors.ejs +141 -0
  84. package/src/views/docs/api/contracts/addStub-description.ejs +10 -0
  85. package/src/views/docs/api/contracts/addStub.ejs +10 -0
  86. package/src/views/docs/api/contracts/config-description.ejs +32 -0
  87. package/src/views/docs/api/contracts/config.ejs +23 -0
  88. package/src/views/docs/api/contracts/home-description.ejs +18 -0
  89. package/src/views/docs/api/contracts/home.ejs +13 -0
  90. package/src/views/docs/api/contracts/imposter-description.ejs +439 -0
  91. package/src/views/docs/api/contracts/imposter.ejs +182 -0
  92. package/src/views/docs/api/contracts/imposters-description.ejs +13 -0
  93. package/src/views/docs/api/contracts/imposters.ejs +13 -0
  94. package/src/views/docs/api/contracts/logs-description.ejs +3 -0
  95. package/src/views/docs/api/contracts/logs.ejs +14 -0
  96. package/src/views/docs/api/contracts/stub-description.ejs +4 -0
  97. package/src/views/docs/api/contracts/stub.ejs +7 -0
  98. package/src/views/docs/api/contracts/stubs-description.ejs +4 -0
  99. package/src/views/docs/api/contracts/stubs.ejs +11 -0
  100. package/src/views/docs/api/contracts.ejs +133 -0
  101. package/src/views/docs/api/errors.ejs +64 -0
  102. package/src/views/docs/api/fault/connectionReset.ejs +31 -0
  103. package/src/views/docs/api/fault/randomDataThenClose.ejs +31 -0
  104. package/src/views/docs/api/faults.ejs +57 -0
  105. package/src/views/docs/api/injection.ejs +426 -0
  106. package/src/views/docs/api/json.ejs +205 -0
  107. package/src/views/docs/api/jsonpath.ejs +210 -0
  108. package/src/views/docs/api/mocks.ejs +130 -0
  109. package/src/views/docs/api/overview.ejs +968 -0
  110. package/src/views/docs/api/predicates/and.ejs +62 -0
  111. package/src/views/docs/api/predicates/contains.ejs +64 -0
  112. package/src/views/docs/api/predicates/deepEquals.ejs +114 -0
  113. package/src/views/docs/api/predicates/endsWith.ejs +66 -0
  114. package/src/views/docs/api/predicates/equals.ejs +125 -0
  115. package/src/views/docs/api/predicates/exists.ejs +118 -0
  116. package/src/views/docs/api/predicates/inject.ejs +67 -0
  117. package/src/views/docs/api/predicates/matches.ejs +66 -0
  118. package/src/views/docs/api/predicates/not.ejs +52 -0
  119. package/src/views/docs/api/predicates/or.ejs +79 -0
  120. package/src/views/docs/api/predicates/startsWith.ejs +62 -0
  121. package/src/views/docs/api/predicates.ejs +382 -0
  122. package/src/views/docs/api/proxies.ejs +191 -0
  123. package/src/views/docs/api/proxy/addDecorateBehavior.ejs +115 -0
  124. package/src/views/docs/api/proxy/addWaitBehavior.ejs +96 -0
  125. package/src/views/docs/api/proxy/injectHeaders.ejs +91 -0
  126. package/src/views/docs/api/proxy/predicateGenerators.ejs +600 -0
  127. package/src/views/docs/api/proxy/proxyModes.ejs +495 -0
  128. package/src/views/docs/api/stubs.ejs +391 -0
  129. package/src/views/docs/api/xpath.ejs +281 -0
  130. package/src/views/docs/cli/configFiles.ejs +133 -0
  131. package/src/views/docs/cli/customFormatters.ejs +53 -0
  132. package/src/views/docs/cli/help.ejs +6 -0
  133. package/src/views/docs/cli/replay.ejs +42 -0
  134. package/src/views/docs/cli/restart.ejs +10 -0
  135. package/src/views/docs/cli/save.ejs +68 -0
  136. package/src/views/docs/cli/start.ejs +234 -0
  137. package/src/views/docs/cli/stop.ejs +32 -0
  138. package/src/views/docs/commandLine.ejs +93 -0
  139. package/src/views/docs/communityExtensions.ejs +233 -0
  140. package/src/views/docs/gettingStarted.ejs +146 -0
  141. package/src/views/docs/mentalModel.ejs +51 -0
  142. package/src/views/docs/protocols/custom.ejs +231 -0
  143. package/src/views/docs/protocols/http.ejs +238 -0
  144. package/src/views/docs/protocols/https.ejs +246 -0
  145. package/src/views/docs/protocols/smtp.ejs +142 -0
  146. package/src/views/docs/protocols/tcp.ejs +431 -0
  147. package/src/views/docs/security.ejs +38 -0
  148. package/src/views/faqs.ejs +65 -0
  149. package/src/views/feed.ejs +33 -0
  150. package/src/views/imposter.ejs +22 -0
  151. package/src/views/imposters.ejs +33 -0
  152. package/src/views/index.ejs +89 -0
  153. package/src/views/license.ejs +30 -0
  154. package/src/views/logs.ejs +77 -0
  155. package/src/views/releases/v1.1.0.ejs +55 -0
  156. package/src/views/releases/v1.1.36.ejs +84 -0
  157. package/src/views/releases/v1.1.72.ejs +92 -0
  158. package/src/views/releases/v1.10.0.ejs +108 -0
  159. package/src/views/releases/v1.11.0.ejs +109 -0
  160. package/src/views/releases/v1.12.0.ejs +96 -0
  161. package/src/views/releases/v1.13.0.ejs +118 -0
  162. package/src/views/releases/v1.14.0.ejs +107 -0
  163. package/src/views/releases/v1.14.1.ejs +94 -0
  164. package/src/views/releases/v1.15.0.ejs +113 -0
  165. package/src/views/releases/v1.16.0.ejs +104 -0
  166. package/src/views/releases/v1.2.0.ejs +78 -0
  167. package/src/views/releases/v1.2.103.ejs +86 -0
  168. package/src/views/releases/v1.2.122.ejs +86 -0
  169. package/src/views/releases/v1.2.30.ejs +84 -0
  170. package/src/views/releases/v1.2.45.ejs +84 -0
  171. package/src/views/releases/v1.2.56.ejs +79 -0
  172. package/src/views/releases/v1.3.0.ejs +86 -0
  173. package/src/views/releases/v1.3.1.ejs +100 -0
  174. package/src/views/releases/v1.4.0.ejs +96 -0
  175. package/src/views/releases/v1.4.1.ejs +103 -0
  176. package/src/views/releases/v1.4.2.ejs +100 -0
  177. package/src/views/releases/v1.4.3.ejs +113 -0
  178. package/src/views/releases/v1.5.0.ejs +104 -0
  179. package/src/views/releases/v1.5.1.ejs +91 -0
  180. package/src/views/releases/v1.6.0.ejs +109 -0
  181. package/src/views/releases/v1.7.0.ejs +113 -0
  182. package/src/views/releases/v1.7.1.ejs +90 -0
  183. package/src/views/releases/v1.7.2.ejs +96 -0
  184. package/src/views/releases/v1.8.0.ejs +121 -0
  185. package/src/views/releases/v1.9.0.ejs +111 -0
  186. package/src/views/releases/v2.0.0.ejs +159 -0
  187. package/src/views/releases/v2.1.0.ejs +121 -0
  188. package/src/views/releases/v2.1.1.ejs +106 -0
  189. package/src/views/releases/v2.1.2.ejs +84 -0
  190. package/src/views/releases/v2.2.0.ejs +115 -0
  191. package/src/views/releases/v2.2.1.ejs +102 -0
  192. package/src/views/releases/v2.3.0.ejs +121 -0
  193. package/src/views/releases/v2.3.1.ejs +100 -0
  194. package/src/views/releases/v2.3.2.ejs +102 -0
  195. package/src/views/releases/v2.3.3.ejs +97 -0
  196. package/src/views/releases/v2.4.0.ejs +114 -0
  197. package/src/views/releases/v2.5.0.ejs +51 -0
  198. package/src/views/releases/v2.6.0.ejs +35 -0
  199. package/src/views/releases/v2.7.0.ejs +32 -0
  200. package/src/views/releases/v2.8.0.ejs +36 -0
  201. package/src/views/releases/v2.8.1.ejs +7 -0
  202. package/src/views/releases/v2.8.2.ejs +26 -0
  203. package/src/views/releases/v2.9.0.ejs +32 -0
  204. package/src/views/releases/v2.9.1.ejs +10 -0
  205. package/src/views/releases.ejs +26 -0
  206. package/src/views/sitemap.ejs +36 -0
  207. package/src/views/support.ejs +14 -0
@@ -0,0 +1,418 @@
1
+ 'use strict';
2
+
3
+ const helpers = require('../util/helpers.js'),
4
+ errors = require('../util/errors.js');
5
+
6
+ /**
7
+ * An abstraction for loading imposters from in-memory
8
+ * @module
9
+ */
10
+
11
+ function repeatsFor (response) {
12
+ return response.repeat || 1;
13
+ }
14
+
15
+ function repeatTransform (responses) {
16
+ const result = [];
17
+ let response, repeats;
18
+
19
+ for (let i = 0; i < responses.length; i += 1) {
20
+ response = responses[i];
21
+ repeats = repeatsFor(response);
22
+ for (let j = 0; j < repeats; j += 1) {
23
+ result.push(response);
24
+ }
25
+ }
26
+ return result;
27
+ }
28
+
29
+ function createResponse (responseConfig, stubIndexFn) {
30
+ const cloned = helpers.clone(responseConfig || { is: {} });
31
+
32
+ cloned.stubIndex = stubIndexFn ? stubIndexFn : () => Promise.resolve(0);
33
+
34
+ return cloned;
35
+ }
36
+
37
+ function wrap (stub = {}) {
38
+ const cloned = helpers.clone(stub),
39
+ statefulResponses = repeatTransform(cloned.responses || []);
40
+
41
+ /**
42
+ * Adds a new response to the stub (e.g. during proxying)
43
+ * @memberOf module:models/inMemoryImpostersRepository#
44
+ * @param {Object} response - the response to add
45
+ * @returns {Object} - the promise
46
+ */
47
+ cloned.addResponse = async response => {
48
+ cloned.responses = cloned.responses || [];
49
+ cloned.responses.push(response);
50
+ statefulResponses.push(response);
51
+ return response;
52
+ };
53
+
54
+ /**
55
+ * Selects the next response from the stub, including repeat behavior and circling back to the beginning
56
+ * @memberOf module:models/inMemoryImpostersRepository#
57
+ * @returns {Object} - the response
58
+ * @returns {Object} - the promise
59
+ */
60
+ cloned.nextResponse = async () => {
61
+ const responseConfig = statefulResponses.shift();
62
+
63
+ if (responseConfig) {
64
+ statefulResponses.push(responseConfig);
65
+ return createResponse(responseConfig, cloned.stubIndex);
66
+ }
67
+ else {
68
+ return createResponse();
69
+ }
70
+ };
71
+
72
+ /**
73
+ * Records a match for debugging purposes
74
+ * @memberOf module:models/inMemoryImpostersRepository#
75
+ * @param {Object} request - the request
76
+ * @param {Object} response - the response
77
+ * @param {Object} responseConfig - the config that generated the response
78
+ * @param {Number} processingTime - the time to match the predicate and generate the full response
79
+ * @returns {Object} - the promise
80
+ */
81
+ cloned.recordMatch = async (request, response, responseConfig, processingTime) => {
82
+ cloned.matches = cloned.matches || [];
83
+ cloned.matches.push({
84
+ timestamp: new Date().toJSON(),
85
+ request,
86
+ response,
87
+ responseConfig,
88
+ processingTime
89
+ });
90
+ };
91
+
92
+ return cloned;
93
+ }
94
+
95
+ /**
96
+ * Creates the stubs repository for a single imposter
97
+ * @returns {Object}
98
+ */
99
+ function createStubsRepository () {
100
+ const stubs = [];
101
+ let requests = [];
102
+
103
+ function reindex () {
104
+ // stubIndex() is used to find the right spot to insert recorded
105
+ // proxy responses. We reindex after every state change
106
+ stubs.forEach((stub, index) => {
107
+ stub.stubIndex = async () => index;
108
+ });
109
+ }
110
+
111
+ /**
112
+ * Returns the first stub whose predicates match the filter, or a default one if none match
113
+ * @memberOf module:models/inMemoryImpostersRepository#
114
+ * @param {Function} filter - the filter function
115
+ * @param {Number} startIndex - the index to to start searching
116
+ * @returns {Object}
117
+ */
118
+ async function first (filter, startIndex = 0) {
119
+ for (let i = startIndex; i < stubs.length; i += 1) {
120
+ if (filter(stubs[i].predicates || [])) {
121
+ return { success: true, stub: stubs[i] };
122
+ }
123
+ }
124
+ return { success: false, stub: wrap() };
125
+ }
126
+
127
+ /**
128
+ * Adds a new stub
129
+ * @memberOf module:models/inMemoryImpostersRepository#
130
+ * @param {Object} stub - the stub to add
131
+ * @returns {Object} - the promise
132
+ */
133
+ async function add (stub) {
134
+ stubs.push(wrap(stub));
135
+ reindex();
136
+ }
137
+
138
+ /**
139
+ * Inserts a new stub at the given index
140
+ * @memberOf module:models/inMemoryImpostersRepository#
141
+ * @param {Object} stub - the stub to insert
142
+ * @param {Number} index - the index to add the stub at
143
+ * @returns {Object} - the promise
144
+ */
145
+ async function insertAtIndex (stub, index) {
146
+ stubs.splice(index, 0, wrap(stub));
147
+ reindex();
148
+ }
149
+
150
+ /**
151
+ * Overwrites the list of stubs with a new list
152
+ * @memberOf module:models/inMemoryImpostersRepository#
153
+ * @param {Object} newStubs - the new list of stubs
154
+ * @returns {Object} - the promise
155
+ */
156
+ async function overwriteAll (newStubs) {
157
+ while (stubs.length > 0) {
158
+ stubs.pop();
159
+ }
160
+ newStubs.forEach(stub => add(stub));
161
+ reindex();
162
+ }
163
+
164
+ /**
165
+ * Overwrites the stub at the given index with the new stub
166
+ * @memberOf module:models/inMemoryImpostersRepository#
167
+ * @param {Object} newStub - the new stub
168
+ * @param {Number} index - the index of the old stuib
169
+ * @returns {Object} - the promise
170
+ */
171
+ async function overwriteAtIndex (newStub, index) {
172
+
173
+ if (typeof stubs[index] === 'undefined') {
174
+ throw errors.MissingResourceError(`no stub at index ${index}`);
175
+ }
176
+
177
+ stubs[index] = wrap(newStub);
178
+ reindex();
179
+ }
180
+
181
+ /**
182
+ * Deletes the stub at the given index
183
+ * @memberOf module:models/inMemoryImpostersRepository#
184
+ * @param {Number} index - the index of the stub to delete
185
+ * @returns {Object} - the promise
186
+ */
187
+ async function deleteAtIndex (index) {
188
+ if (typeof stubs[index] === 'undefined') {
189
+ throw errors.MissingResourceError(`no stub at index ${index}`);
190
+ }
191
+
192
+ stubs.splice(index, 1);
193
+ reindex();
194
+ }
195
+
196
+ /**
197
+ * Returns a JSON-convertible representation
198
+ * @memberOf module:models/inMemoryImpostersRepository#
199
+ * @param {Object} options - The formatting options
200
+ * @param {Boolean} options.debug - If true, includes debug information
201
+ * @returns {Object} - the promise resolving to the JSON object
202
+ */
203
+ async function toJSON (options = {}) {
204
+ const cloned = helpers.clone(stubs);
205
+
206
+ cloned.forEach(stub => {
207
+ if (!options.debug) {
208
+ delete stub.matches;
209
+ }
210
+ });
211
+
212
+ return cloned;
213
+ }
214
+
215
+ function isRecordedResponse (response) {
216
+ return response.is && typeof response.is._proxyResponseTime === 'number';
217
+ }
218
+
219
+ /**
220
+ * Removes the saved proxy responses
221
+ * @memberOf module:models/inMemoryImpostersRepository#
222
+ * @returns {Object} - Promise
223
+ */
224
+ async function deleteSavedProxyResponses () {
225
+ const allStubs = await toJSON();
226
+ allStubs.forEach(stub => {
227
+ stub.responses = stub.responses.filter(response => !isRecordedResponse(response));
228
+ });
229
+ const nonProxyStubs = allStubs.filter(stub => stub.responses.length > 0);
230
+ await overwriteAll(nonProxyStubs);
231
+ }
232
+
233
+ /**
234
+ * Adds a request for the imposter
235
+ * @memberOf module:models/inMemoryImpostersRepository#
236
+ * @param {Object} request - the request
237
+ * @returns {Object} - the promise
238
+ */
239
+ async function addRequest (request) {
240
+ const recordedRequest = helpers.clone(request);
241
+ recordedRequest.timestamp = new Date().toJSON();
242
+ requests.push(recordedRequest);
243
+ }
244
+
245
+ /**
246
+ * Returns the saved requests for the imposter
247
+ * @memberOf module:models/inMemoryImpostersRepository#
248
+ * @returns {Object} - the promise resolving to the array of requests
249
+ */
250
+ async function loadRequests () {
251
+ return requests;
252
+ }
253
+
254
+ /**
255
+ * Clears the saved requests list
256
+ * @memberOf module:models/inMemoryImpostersRepository#
257
+ * @param {Object} request - the request
258
+ * @returns {Object} - Promise
259
+ */
260
+ async function deleteSavedRequests () {
261
+ requests = [];
262
+ }
263
+
264
+ return {
265
+ count: () => stubs.length,
266
+ first,
267
+ add,
268
+ insertAtIndex,
269
+ overwriteAll,
270
+ overwriteAtIndex,
271
+ deleteAtIndex,
272
+ toJSON,
273
+ deleteSavedProxyResponses,
274
+ addRequest,
275
+ loadRequests,
276
+ deleteSavedRequests
277
+ };
278
+ }
279
+
280
+ /**
281
+ * Creates the repository
282
+ * @returns {Object}
283
+ */
284
+ function create () {
285
+ const imposters = {},
286
+ stubRepos = {};
287
+
288
+ /**
289
+ * Adds a new imposter
290
+ * @memberOf module:models/inMemoryImpostersRepository#
291
+ * @param {Object} imposter - the imposter to add
292
+ * @returns {Object} - the promise
293
+ */
294
+ async function add (imposter) {
295
+ if (!imposter.stubs) {
296
+ imposter.stubs = [];
297
+ }
298
+ imposters[String(imposter.port)] = imposter;
299
+
300
+ const promises = (imposter.creationRequest.stubs || []).map(stubsFor(imposter.port).add);
301
+ await Promise.all(promises);
302
+ return imposter;
303
+ }
304
+
305
+ /**
306
+ * Gets the imposter by id
307
+ * @memberOf module:models/inMemoryImpostersRepository#
308
+ * @param {Number} id - the id of the imposter (e.g. the port)
309
+ * @returns {Object} - the imposter
310
+ */
311
+ async function get (id) {
312
+ return imposters[String(id)] || null;
313
+ }
314
+
315
+ /**
316
+ * Gets all imposters
317
+ * @memberOf module:models/inMemoryImpostersRepository#
318
+ * @returns {Object} - all imposters keyed by port
319
+ */
320
+ async function all () {
321
+ return Promise.all(Object.keys(imposters).map(get));
322
+ }
323
+
324
+ /**
325
+ * Returns whether an imposter at the given id exists or not
326
+ * @memberOf module:models/inMemoryImpostersRepository#
327
+ * @param {Number} id - the id (e.g. the port)
328
+ * @returns {boolean}
329
+ */
330
+ async function exists (id) {
331
+ return typeof imposters[String(id)] !== 'undefined';
332
+ }
333
+
334
+ /**
335
+ * Deletes the imposter at the given id
336
+ * @memberOf module:models/inMemoryImpostersRepository#
337
+ * @param {Number} id - the id (e.g. the port)
338
+ * @returns {Object} - the deletion promise
339
+ */
340
+ async function del (id) {
341
+ const result = imposters[String(id)] || null;
342
+ delete imposters[String(id)];
343
+ delete stubRepos[String(id)];
344
+
345
+ if (result) {
346
+ await result.stop();
347
+ }
348
+ return result;
349
+ }
350
+
351
+ /**
352
+ * Deletes all imposters synchronously; used during shutdown
353
+ * @memberOf module:models/inMemoryImpostersRepository#
354
+ */
355
+ function stopAllSync () {
356
+ Object.keys(imposters).forEach(id => {
357
+ imposters[id].stop();
358
+ delete imposters[id];
359
+ delete stubRepos[id];
360
+ });
361
+ }
362
+
363
+ /**
364
+ * Deletes all imposters
365
+ * @memberOf module:models/inMemoryImpostersRepository#
366
+ * @returns {Object} - the deletion promise
367
+ */
368
+ async function deleteAll () {
369
+ const ids = Object.keys(imposters),
370
+ promises = ids.map(id => imposters[id].stop());
371
+
372
+ ids.forEach(id => {
373
+ delete imposters[id];
374
+ delete stubRepos[id];
375
+ });
376
+ await Promise.all(promises);
377
+ }
378
+
379
+ /**
380
+ * Returns the stub repository for the given id
381
+ * @memberOf module:models/inMemoryImpostersRepository#
382
+ * @param {Number} id - the imposter's id
383
+ * @returns {Object} - the stub repository
384
+ */
385
+ function stubsFor (id) {
386
+ // In practice, the stubsFor call occurs before the imposter is actually added...
387
+ if (!stubRepos[String(id)]) {
388
+ stubRepos[String(id)] = createStubsRepository();
389
+ }
390
+
391
+ return stubRepos[String(id)];
392
+ }
393
+
394
+ /**
395
+ * Called at startup to load saved imposters.
396
+ * Does nothing for in memory repository
397
+ * @memberOf module:models/inMemoryImpostersRepository#
398
+ * @returns {Object} - a promise
399
+ */
400
+ async function loadAll () {
401
+ return Promise.resolve();
402
+ }
403
+
404
+ return {
405
+ add,
406
+ get,
407
+ all,
408
+ exists,
409
+ del,
410
+ stopAllSync,
411
+ deleteAll,
412
+ stubsFor,
413
+ createStubsRepository,
414
+ loadAll
415
+ };
416
+ }
417
+
418
+ module.exports = { create };
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ const jsonPathPlus = require('jsonpath-plus'),
4
+ helpers = require('../util/helpers.js');
5
+
6
+ const { JSONPath } = jsonPathPlus;
7
+
8
+ /**
9
+ * Shared logic for xpath selector
10
+ * @module
11
+ */
12
+
13
+ /**
14
+ * Returns xpath value(s) from given xml
15
+ * @param {String} selector - The xpath selector
16
+ * @param {String} possibleJSON - the JSON string
17
+ * @param {Logger} logger - Optional, used to log JSON parsing errors
18
+ * @returns {Object}
19
+ */
20
+ function select (selector, possibleJSON, logger) {
21
+ const isObject = helpers.isObject;
22
+
23
+ try {
24
+ const json = isObject(possibleJSON) ? possibleJSON : JSON.parse(possibleJSON),
25
+ result = JSONPath(selector, json);
26
+ if (typeof result === 'string') {
27
+ return result;
28
+ }
29
+ else if (result.length === 0) {
30
+ return undefined;
31
+ }
32
+ else {
33
+ return result;
34
+ }
35
+ }
36
+ catch (e) {
37
+ if (logger) {
38
+ logger.warn(`Cannot parse as JSON: ${JSON.stringify(possibleJSON)}`);
39
+ }
40
+ return undefined;
41
+ }
42
+ }
43
+
44
+ module.exports = { select };
@@ -0,0 +1,107 @@
1
+ 'use strict';
2
+
3
+ const errors = require('../util/errors.js'),
4
+ util = require('util');
5
+
6
+ /**
7
+ * Helper functions to navigate the mountebank API for out of process implementations.
8
+ * Used to adapt the built-in (in-process) protocols to out of process.
9
+ * @module
10
+ */
11
+
12
+ function createLogger (loglevel) {
13
+ const result = {},
14
+ levels = ['debug', 'info', 'warn', 'error'];
15
+
16
+ levels.forEach((level, index) => {
17
+ if (index < levels.indexOf(loglevel)) {
18
+ result[level] = () => {};
19
+ }
20
+ else {
21
+ result[level] = function () {
22
+ const args = Array.prototype.slice.call(arguments),
23
+ message = util.format.apply(this, args);
24
+
25
+ console.log(`${level} ${message}`);
26
+ };
27
+ }
28
+ });
29
+ return result;
30
+ }
31
+
32
+ function postJSON (what, where) {
33
+ return new Promise((resolve, reject) => {
34
+ const parts = new URL(where),
35
+ driver = require(parts.protocol.replace(':', '')),
36
+ options = {
37
+ hostname: parts.hostname,
38
+ port: parts.port,
39
+ path: parts.pathname,
40
+ method: 'POST',
41
+ headers: { 'Content-Type': 'application/json' }
42
+ },
43
+ request = driver.request(options, response => {
44
+ const packets = [];
45
+
46
+ response.on('data', chunk => packets.push(chunk));
47
+
48
+ response.on('end', () => {
49
+ const buffer = Buffer.concat(packets),
50
+ body = buffer.toString('utf8');
51
+
52
+ if (response.statusCode !== 200) {
53
+ reject(errors.CommunicationError({
54
+ statusCode: response.statusCode,
55
+ body: body
56
+ }));
57
+ }
58
+ else {
59
+ resolve(JSON.parse(body));
60
+ }
61
+ });
62
+ });
63
+
64
+ request.on('error', reject);
65
+ request.write(JSON.stringify(what));
66
+ request.end();
67
+ });
68
+ }
69
+
70
+ function create (config) {
71
+ let callbackURL,
72
+ proxy;
73
+
74
+ function setPort (port) {
75
+ callbackURL = config.callbackURLTemplate.replace(':port', port);
76
+ }
77
+
78
+ function setProxy (value) {
79
+ proxy = value;
80
+ }
81
+
82
+ function logger () {
83
+ return createLogger(config.loglevel);
84
+ }
85
+
86
+ async function getProxyResponse (proxyConfig, request, proxyCallbackURL, requestDetails) {
87
+ const response = await proxy.to(proxyConfig.to, request, proxyConfig, requestDetails);
88
+ return postJSON({ proxyResponse: response }, proxyCallbackURL);
89
+ }
90
+
91
+ async function getResponse (request, requestDetails) {
92
+ const mbResponse = await postJSON({ request, requestDetails }, callbackURL);
93
+ if (mbResponse.proxy) {
94
+ return getProxyResponse(mbResponse.proxy, mbResponse.request, mbResponse.callbackURL, requestDetails);
95
+ }
96
+ else if (mbResponse.response) {
97
+ return mbResponse.response;
98
+ }
99
+ else {
100
+ return mbResponse;
101
+ }
102
+ }
103
+
104
+ return { getResponse, setPort, setProxy, logger };
105
+ }
106
+
107
+ module.exports = { create };