@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,62 @@
1
+ <p>The <code>and</code> predicate matches if all of its sub-predicates match.</p>
2
+
3
+ <testScenario name='tcp and example'>
4
+ <step type='http'>
5
+ <pre><code>POST /imposters HTTP/1.1
6
+ Host: localhost:<%= port %>
7
+ Accept: application/json
8
+ Content-Type: application/json
9
+
10
+ {
11
+ "port": 4554,
12
+ "protocol": "tcp",
13
+ "mode": "text",
14
+ "stubs": [<strong class='highlight1'>
15
+ {
16
+ "responses": [{ "is": { "data": "matches" } }],
17
+ "predicates": [
18
+ {
19
+ "and": [
20
+ { "startsWith": { "data": "start" } },
21
+ { "endsWith": { "data": "end\n" } },
22
+ { "contains": { "data": "middle" } }
23
+ ]
24
+ }
25
+ ]
26
+ }</strong>
27
+ ]
28
+ }</code></pre>
29
+ </step>
30
+
31
+ <p>The first request matches all sub-predicates, triggering the stub response:</p>
32
+
33
+ <step type='exec'>
34
+ <pre><code>echo '<strong class='highlight1'>start middle end</strong>' | nc localhost 4554</code></pre>
35
+
36
+ <assertResponse>
37
+ <pre><code><strong class='highlight1'>matches</strong></code></pre>
38
+ </assertResponse>
39
+ </step>
40
+
41
+ <p>The stub matches two of the three sub-predicates, which is not enough to match
42
+ the <code>and</code> predicate.</p>
43
+
44
+ <p>The stub does not match none of the sub-predicates match...</p>
45
+
46
+ <step type='exec'>
47
+ <pre><code>echo '<strong class='highlight1'>start end</strong>' | nc localhost 4554</code></pre>
48
+
49
+ <p>No response is sent.</p>
50
+
51
+ <assertResponse>
52
+ <pre><code>
53
+ </code></pre>
54
+ </assertResponse>
55
+ </step>
56
+
57
+ <step type='http'>
58
+ <code class='hidden'>DELETE /imposters/4554 HTTP/1.1
59
+ Host: localhost:<%= port %>
60
+ Accept: application/json</code>
61
+ </step>
62
+ </testScenario>
@@ -0,0 +1,64 @@
1
+ <p>Let's create a binary TCP imposter with multiple stubs:</p>
2
+
3
+ <testScenario name='tcp contains example'>
4
+ <step type='http'>
5
+ <pre><code>POST /imposters HTTP/1.1
6
+ Host: localhost:<%= port %>
7
+ Accept: application/json
8
+ Content-Type: application/json
9
+
10
+ {
11
+ "port": 4547,
12
+ "protocol": "tcp",
13
+ "mode": "binary",
14
+ "stubs": [<strong class='highlight1'>
15
+ {
16
+ "responses": [{ "is": { "data": "Zmlyc3QgcmVzcG9uc2U=" } }],
17
+ "predicates": [{ "contains": { "data": "AgM=" } }]
18
+ }</strong>,<strong class='highlight2'>
19
+ {
20
+ "responses": [{ "is": { "data": "c2Vjb25kIHJlc3BvbnNl" } }],
21
+ "predicates": [{ "contains": { "data": "Bwg=" } }]
22
+ }</strong>,<strong class='highlight3'>
23
+ {
24
+ "responses": [{ "is": { "data": "dGhpcmQgcmVzcG9uc2U=" } }],
25
+ "predicates": [{ "contains": { "data": "Bwg=" } }]
26
+ }</strong>
27
+ ]
28
+ }</code></pre>
29
+ </step>
30
+
31
+ <p>We're sending a base64-encoded version of four bytes: 0x1, 0x2, 0x3,
32
+ and 0x4. Our first predicate is a base64 encoded version of 0x2 and 0x3.
33
+ The response is a base64-encoded version of the string "first response":</p>
34
+
35
+ <step type='exec'>
36
+ <pre><code>echo '<strong class='highlight1'>AQIDBA==</strong>' | base64 --decode | nc localhost 4547</code></pre>
37
+
38
+ <assertResponse>
39
+ <pre><code><strong class='highlight1'>first response</strong></code></pre>
40
+ </assertResponse>
41
+ </step>
42
+
43
+ <p>Next we'll send 0x5, 0x6, 0x7, and 0x8, matching on a predicate
44
+ encoding 0x7 and 0x8:</p>
45
+
46
+ <step type='exec'>
47
+ <pre><code>echo '<strong class='highlight2'>BQYHCA==</strong>' | base64 --decode | nc localhost 4547</code></pre>
48
+
49
+ <assertResponse>
50
+ <pre><code><strong class='highlight2'>second response</strong></code></pre>
51
+ </assertResponse>
52
+ </step>
53
+
54
+ <p>The third stub will never run, since it matches the same requests as the
55
+ second stub. mountebank always chooses the first stub that matches based on
56
+ the order you add them to the <code>stubs</code> array when creating the
57
+ imposter.</p>
58
+
59
+ <step type='http'>
60
+ <code class='hidden'>DELETE /imposters/4547 HTTP/1.1
61
+ Host: localhost:<%= port %>
62
+ Accept: application/json</code>
63
+ </step>
64
+ </testScenario>
@@ -0,0 +1,114 @@
1
+ <p>Let's create an HTTP imposter with multiple stubs:</p>
2
+
3
+ <testScenario name='http deepEquals example'>
4
+ <step type='http'>
5
+ <pre><code>POST /imposters HTTP/1.1
6
+ Host: localhost:<%= port %>
7
+ Accept: application/json
8
+ Content-Type: application/json
9
+
10
+ {
11
+ "port": 4556,
12
+ "protocol": "http",
13
+ "stubs": [<strong class='highlight1'>
14
+ {
15
+ "responses": [{ "is": { "body": "first" } }],
16
+ "predicates": [{
17
+ "deepEquals": {
18
+ "query": {}
19
+ }
20
+ }]
21
+ }</strong>,<strong class='highlight2'>
22
+ {
23
+ "responses": [{ "is": { "body": "second" } }],
24
+ "predicates": [{
25
+ "deepEquals": {
26
+ "query": {
27
+ "first": "1"
28
+ }
29
+ }
30
+ }]
31
+ }</strong>,<strong class='highlight3'>
32
+ {
33
+ "responses": [{ "is": { "body": "third" } }],
34
+ "predicates": [{
35
+ "deepEquals": {
36
+ "query": {
37
+ "first": "1",
38
+ "second": "2"
39
+ }
40
+ }
41
+ }]
42
+ }</strong>
43
+ ]
44
+ }</code></pre>
45
+ </step>
46
+
47
+ <p>The first predicate matches only a request without a querystring.</p>
48
+
49
+ <step type='http'>
50
+ <pre><code>GET /test HTTP/1.1
51
+ Host: localhost:4556</code></pre>
52
+
53
+ <assertResponse>
54
+ <pre><code>HTTP/1.1 200 OK
55
+ Connection: close
56
+ Date: <volatile>Thu, 09 Jan 2014 02:30:31 GMT</volatile>
57
+ Transfer-Encoding: chunked
58
+
59
+ <strong class='highlight1'>first</strong></code></pre>
60
+ </assertResponse>
61
+ </step>
62
+
63
+ <p>The second stub matches only if the exact querystring is sent.</p>
64
+
65
+ <step type='http'>
66
+ <pre><code>GET /test?<strong class='highlight2'>First=1</strong> HTTP/1.1
67
+ Host: localhost:4556</code></pre>
68
+
69
+ <assertResponse>
70
+ <pre><code>HTTP/1.1 200 OK
71
+ Connection: close
72
+ Date: <volatile>Thu, 09 Jan 2014 02:30:31 GMT</volatile>
73
+ Transfer-Encoding: chunked
74
+
75
+ <strong class='highlight2'>second</strong></code></pre>
76
+ </assertResponse>
77
+ </step>
78
+
79
+ <p>The third stub matches only if both query keys are sent.</p>
80
+
81
+ <step type='http'>
82
+ <pre><code>GET /test?<strong class='highlight3'>Second=2&amp;First=1</strong> HTTP/1.1
83
+ Host: localhost:4556</code></pre>
84
+
85
+ <assertResponse>
86
+ <pre><code>HTTP/1.1 200 OK
87
+ Connection: close
88
+ Date: <volatile>Thu, 09 Jan 2014 02:30:31 GMT</volatile>
89
+ Transfer-Encoding: chunked
90
+
91
+ <strong class='highlight3'>third</strong></code></pre>
92
+ </assertResponse>
93
+ </step>
94
+
95
+ <p>Any additional query parameters will trigger the default HTTP response.</p>
96
+
97
+ <step type='http'>
98
+ <pre><code>GET /test?Second=2&amp;First=1&amp;Third=3 HTTP/1.1
99
+ Host: localhost:4556</code></pre>
100
+
101
+ <assertResponse>
102
+ <pre><code>HTTP/1.1 200 OK
103
+ Connection: close
104
+ Date: <volatile>Thu, 09 Jan 2014 02:30:31 GMT</volatile>
105
+ Transfer-Encoding: chunked</code></pre>
106
+ </assertResponse>
107
+ </step>
108
+
109
+ <step type='http'>
110
+ <code class='hidden'>DELETE /imposters/4556 HTTP/1.1
111
+ Host: localhost:<%= port %>
112
+ Accept: application/json</code>
113
+ </step>
114
+ </testScenario>
@@ -0,0 +1,66 @@
1
+ <p>Let's create a binary-based imposter with multiple stubs:</p>
2
+
3
+ <testScenario name='tcp endsWith example'>
4
+ <step type='http'>
5
+ <pre><code>POST /imposters HTTP/1.1
6
+ Host: localhost:<%= port %>
7
+ Accept: application/json
8
+ Content-Type: application/json
9
+
10
+ {
11
+ "port": 4549,
12
+ "protocol": "tcp",
13
+ "mode": "binary",
14
+ "stubs": [<strong class='highlight1'>
15
+ {
16
+ "responses": [{ "is": { "data": "Zmlyc3QgcmVzcG9uc2U=" } }],
17
+ "predicates": [{ "endsWith": { "data": "AwQ=" } }]
18
+ }</strong>,<strong class='highlight2'>
19
+ {
20
+ "responses": [{ "is": { "data": "c2Vjb25kIHJlc3BvbnNl" } }],
21
+ "predicates": [{ "endsWith": { "data": "BQY=" } }]
22
+ }</strong>,<strong class='highlight3'>
23
+ {
24
+ "responses": [{ "is": { "data": "dGhpcmQgcmVzcG9uc2U=" } }],
25
+ "predicates": [{ "endsWith": { "data": "BQY=" } }]
26
+ }</strong>
27
+ ]
28
+ }</code></pre>
29
+ </step>
30
+
31
+ <p>We'll use the command line <code>base64</code> tool to decode the
32
+ request to binary before sending to the imposter. We're sending a
33
+ base64-encoded version of four bytes: 0x1, 0x2, 0x3, and 0x4. Our
34
+ first predicate is a base64 encoded version of 0x3 and 0x4. The
35
+ response is a base64-encoded version of the string "first response":</p>
36
+
37
+ <step type='exec'>
38
+ <pre><code>echo '<strong class='highlight1'>AQIDBA==</strong>' | base64 --decode | nc localhost 4549</code></pre>
39
+
40
+ <assertResponse>
41
+ <pre><code><strong class='highlight1'>first response</strong></code></pre>
42
+ </assertResponse>
43
+ </step>
44
+
45
+ <p>Next we'll send 0x1, 0x2, 0x4, 0x5, and 0x6, matching on a predicate
46
+ encoding 0x5 and 0x6:</p>
47
+
48
+ <step type='exec'>
49
+ <pre><code>echo '<strong class='highlight2'>AQIDBAUG</strong>' | base64 --decode | nc localhost 4549</code></pre>
50
+
51
+ <assertResponse>
52
+ <pre><code><strong class='highlight2'>second response</strong></code></pre>
53
+ </assertResponse>
54
+ </step>
55
+
56
+ <p>The third stub will never run, since it matches the same requests as the
57
+ second stub. mountebank always chooses the first stub that matches based on
58
+ the order you add them to the <code>stubs</code> array when creating the
59
+ imposter.</p>
60
+
61
+ <step type='http'>
62
+ <code class='hidden'>DELETE /imposters/4549 HTTP/1.1
63
+ Host: localhost:<%= port %>
64
+ Accept: application/json</code>
65
+ </step>
66
+ </testScenario>
@@ -0,0 +1,125 @@
1
+ <p>Let's create an HTTP imposter with multiple stubs:</p>
2
+
3
+ <testScenario name='http equals example'>
4
+ <step type='http'>
5
+ <pre><code>POST /imposters HTTP/1.1
6
+ Host: localhost:<%= port %>
7
+ Accept: application/json
8
+ Content-Type: application/json
9
+
10
+ {
11
+ "port": 4545,
12
+ "protocol": "http",
13
+ "stubs": [<strong class='highlight1'>
14
+ {
15
+ "responses": [{ "is": { "statusCode": 400 } }],
16
+ "predicates": [
17
+ {
18
+ "equals": {
19
+ "method": "POST",
20
+ "path": "/test",
21
+ "query": {
22
+ "first": "1",
23
+ "second": "2"
24
+ },
25
+ "headers": {
26
+ "Accept": "text/plain"
27
+ }
28
+ }
29
+ },
30
+ {
31
+ "equals": { "body": "hello, world" },
32
+ "caseSensitive": true,
33
+ "except": "!$"
34
+ }
35
+ ]
36
+ }</strong>,<strong class='highlight2'>
37
+ {
38
+ "responses": [{ "is": { "statusCode": 406 } }],
39
+ "predicates": [{ "equals": { "headers": { "Accept": "application/xml" } } }]
40
+ }</strong>,<strong class='highlight3'>
41
+ {
42
+ "responses": [{ "is": { "statusCode": 405 } }],
43
+ "predicates": [{ "equals": { "method": "PUT" } }]
44
+ }</strong>,<strong class='highlight4'>
45
+ {
46
+ "responses": [{ "is": { "statusCode": 500 } }],
47
+ "predicates": [{ "equals": { "method": "PUT" } }]
48
+ }</strong>
49
+ ]
50
+ }</code></pre>
51
+ </step>
52
+
53
+ <p>The first predicate is the most complex, and the request has to match all of the
54
+ specified request fields. We have the option of putting multiple fields under one
55
+ <code>equals</code> predicate or splitting each one into a separate predicate in the
56
+ array. In this example, all of the ones that share the default predicate parameters
57
+ are together. For those, neither the case of the keys nor the values will affect the
58
+ outcome. The <code>body</code> predicate is treated separately. The text will be
59
+ compared in a case-sensitive manner, after stripping away the regular expression
60
+ <code>!$</code> (an exclamation mark anchored to the end of the string).<p>
61
+
62
+ <p>The order of the query parameters and header fields does not matter.</p>
63
+
64
+ <step type='http'>
65
+ <pre><code><strong class='highlight1'>POST /test?Second=2&amp;First=1</strong> HTTP/1.1
66
+ Host: localhost:4545
67
+ <strong class='highlight1'>accept: text/plain</strong>
68
+
69
+ <strong class='highlight1'>hello, world!</strong></code></pre>
70
+
71
+ <assertResponse>
72
+ <pre><code>HTTP/1.1 <strong class='highlight1'>400</strong> Bad Request
73
+ Connection: close
74
+ Date: <volatile>Thu, 09 Jan 2014 02:30:31 GMT</volatile>
75
+ Transfer-Encoding: chunked</code></pre>
76
+ </assertResponse>
77
+ </step>
78
+
79
+ <p>The second stub matches if the header changes.</p>
80
+
81
+ <step type='http'>
82
+ <pre><code>POST /test?Second=2&amp;First=1 HTTP/1.1
83
+ Host: localhost:4545
84
+ <strong class='highlight2'>Accept: application/xml</strong>
85
+
86
+ "hello, world!"</code></pre>
87
+
88
+ <assertResponse>
89
+ <pre><code>HTTP/1.1 <strong class='highlight2'>406</strong> Not Acceptable
90
+ Connection: close
91
+ Date: <volatile>Thu, 09 Jan 2014 02:30:31 GMT</volatile>
92
+ Transfer-Encoding: chunked</code></pre>
93
+ </assertResponse>
94
+ </step>
95
+
96
+ <p>The third stub matches on a <code>PUT</code>.</p>
97
+
98
+ <step type='http'>
99
+ <pre><code><strong class='highlight3'>PUT</strong> /test?Second=2&amp;First=1 HTTP/1.1
100
+ Host: localhost:4545
101
+ Accept: application/json
102
+
103
+ "hello, world!"</code></pre>
104
+
105
+ <assertResponse>
106
+ <pre><code>
107
+ HTTP/1.1 <strong class='highlight3'>405</strong> Method Not Allowed
108
+ Connection: close
109
+ Date: <volatile>Thu, 09 Jan 2014 02:30:31 GMT</volatile>
110
+ Transfer-Encoding: chunked
111
+ </code></pre>
112
+ </assertResponse>
113
+ </step>
114
+
115
+ <p>The fourth stub will never run, since it matches the same requests as the
116
+ third stub. mountebank always chooses the first stub that matches based on
117
+ the order you add them to the <code>stubs</code> array when creating the
118
+ imposter.</p>
119
+
120
+ <step type='http'>
121
+ <code class='hidden'>DELETE /imposters/4545 HTTP/1.1
122
+ Host: localhost:<%= port %>
123
+ Accept: application/json</code>
124
+ </step>
125
+ </testScenario>
@@ -0,0 +1,118 @@
1
+ <p>The <code>exists</code> predicate is primarily for object data types, like
2
+ HTTP headers and query parameters. It works on string fields by simply returning
3
+ <code>true</code> if the <code>exists</code> value is <code>true</code> and the
4
+ string if non-empty. Setting the <code>exists</code> value to <code>false</code>
5
+ inverts the meaning.</p>
6
+
7
+ <testScenario name='http exists example'>
8
+ <step type='http'>
9
+ <pre><code>POST /imposters HTTP/1.1
10
+ Host: localhost:<%= port %>
11
+ Accept: application/json
12
+ Content-Type: application/json
13
+
14
+ {
15
+ "port": 4551,
16
+ "protocol": "http",
17
+ "stubs": [<strong class='highlight1'>
18
+ {
19
+ "responses": [{ "is": { "body": "first response" } }],
20
+ "predicates": [
21
+ {
22
+ "exists": {
23
+ "query": {
24
+ "q": true,
25
+ "search": false
26
+ },
27
+ "headers": {
28
+ "Accept": true,
29
+ "X-Rate-Limit": false
30
+ }
31
+ }
32
+ }
33
+ ]
34
+ }</strong>,<strong class='highlight2'>
35
+ {
36
+ "responses": [{ "is": { "body": "second response" } }],
37
+ "predicates": [
38
+ {
39
+ "exists": {
40
+ "method": true,
41
+ "body": false
42
+ }
43
+ }
44
+ ]
45
+ }</strong>,<strong class='highlight3'>
46
+ {
47
+ "responses": [{ "is": { "body": "third response" } }],
48
+ "predicates": [
49
+ {
50
+ "exists": { "body": true }
51
+ }
52
+ ]
53
+ }</strong>
54
+ ]
55
+ }</code></pre>
56
+ </step>
57
+
58
+ <p>The first stub matches if the querystring includes <code>q</code>, but not if it
59
+ includes <code>search</code>, and if the headers include <code>Accept</code>,
60
+ but not if they include <code>X-Rate-Limit</code>.</p>
61
+
62
+ <step type='http'>
63
+ <pre><code>GET /?<strong class='highlight1'>q</strong>=mountebank HTTP/1.1
64
+ Host: localhost:4551
65
+ <strong class='highlight1'>Accept</strong>: text/plain</code></pre>
66
+
67
+ <assertResponse>
68
+ <pre><code>HTTP/1.1 200 OK
69
+ Connection: close
70
+ Date: <volatile>Thu, 09 Jan 2014 02:30:31 GMT</volatile>
71
+ Transfer-Encoding: chunked
72
+
73
+ <strong class='highlight1'>first response</strong></code></pre>
74
+ </assertResponse>
75
+ </step>
76
+
77
+ <p>The second stub matches if the request <code>method</code> is a
78
+ non-empty string (always <code>true</code>), and if the <code>body</code>
79
+ is empty.</p>
80
+
81
+ <step type='http'>
82
+ <pre><code>GET / HTTP/1.1
83
+ Host: localhost:4551</code></pre>
84
+
85
+ <assertResponse>
86
+ <pre><code>HTTP/1.1 200 OK
87
+ Connection: close
88
+ Date: <volatile>Thu, 09 Jan 2014 02:30:31 GMT</volatile>
89
+ Transfer-Encoding: chunked
90
+
91
+ <strong class='highlight2'>second response</strong></code></pre>
92
+ </assertResponse>
93
+ </step>
94
+
95
+ <p>The last stub matches if the <code>body</code> is non-empty:</p>
96
+
97
+ <step type='http'>
98
+ <pre><code>POST / HTTP/1.1
99
+ Host: localhost:4551
100
+
101
+ <strong class='highlight3'>non-empty body</strong></code></pre>
102
+
103
+ <assertResponse>
104
+ <pre><code>HTTP/1.1 200 OK
105
+ Connection: close
106
+ Date: <volatile>Thu, 09 Jan 2014 02:30:31 GMT</volatile>
107
+ Transfer-Encoding: chunked
108
+
109
+ <strong class='highlight1'>third response</strong></code></pre>
110
+ </assertResponse>
111
+ </step>
112
+
113
+ <step type='http'>
114
+ <code class='hidden'>DELETE /imposters/4551 HTTP/1.1
115
+ Host: localhost:<%= port %>
116
+ Accept: application/json</code>
117
+ </step>
118
+ </testScenario>
@@ -0,0 +1,67 @@
1
+ <p>The <code>inject</code> predicate allows you to inject JavaScript to determine if
2
+ the predicate should match or not. The JavaScript should be a function that accepts
3
+ the request object (and optionally a logger) and returns true or false.
4
+ See the <a href='/docs/api/injection'>injection page</a> for details.</p>
5
+
6
+ <p>The execution will have access to a node.js environment. The following example uses
7
+ node's <code>Buffer</code> object to decode base64 to a byte array.</p>
8
+
9
+ <testScenario name='tcp inject example'>
10
+ <step type='http'>
11
+ <pre><code>POST /imposters HTTP/1.1
12
+ Host: localhost:<%= port %>
13
+ Accept: application/json
14
+ Content-Type: application/json
15
+
16
+ {
17
+ "port": 4555,
18
+ "protocol": "tcp",
19
+ "mode": "binary",
20
+ "stubs": [<strong class='highlight1'>
21
+ {
22
+ "responses": [{ "is": { "data": "Zmlyc3QgcmVzcG9uc2U=" } }],
23
+ "predicates": [{
24
+ "inject": "function (request, logger) { logger.info('Inside injection'); return Buffer.from(request.data, 'base64')[2] &gt; 100; }"
25
+ }]
26
+ }</strong>,<strong class='highlight2'>
27
+ {
28
+ "responses": [{ "is": { "data": "c2Vjb25kIHJlc3BvbnNl" } }],
29
+ "predicates": [{
30
+ "inject": "request => { return Buffer.from(request.data, 'base64')[2] &lt;= 100; }"
31
+ }]
32
+ }</strong>
33
+ ]
34
+ }</code></pre>
35
+ </step>
36
+
37
+ <p>The first stub matches if the third byte is greater than 100. The request we're
38
+ sending is an encoding <code>[99, 100, 101]:</code></p>
39
+
40
+ <step type='exec'>
41
+ <pre><code>echo '<strong class='highlight1'>Y2Rl</strong>' | base64 --decode | nc localhost 4555</code></pre>
42
+
43
+ <assertResponse>
44
+ <pre><code><strong class='highlight1'>first response</strong></code></pre>
45
+ </assertResponse>
46
+ </step>
47
+
48
+ <p>The logs will also show the injected log output. The second predicate has to
49
+ match a request originating from localhost with the third byte less than or equal
50
+ to 100. We're sending <code>[98, 99, 100]</code>:</p>
51
+
52
+ <step type='exec'>
53
+ <pre><code>echo '<strong class='highlight1'>YmNk</strong>' | base64 --decode | nc localhost 4555</code></pre>
54
+
55
+ <p>...giving the response:</p>
56
+
57
+ <assertResponse>
58
+ <pre><code>second response</code></pre>
59
+ </assertResponse>
60
+ </step>
61
+
62
+ <step type='http'>
63
+ <code class='hidden'>DELETE /imposters/4555 HTTP/1.1
64
+ Host: localhost:<%= port %>
65
+ Accept: application/json</code>
66
+ </step>
67
+ </testScenario>