@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.
- package/LICENSE +21 -0
- package/README.md +94 -0
- package/bin/mb +136 -0
- package/package.json +71 -0
- package/releases.json +52 -0
- package/src/cli/api.js +112 -0
- package/src/cli/cli.js +420 -0
- package/src/controllers/configController.js +64 -0
- package/src/controllers/feedController.js +115 -0
- package/src/controllers/homeController.js +58 -0
- package/src/controllers/imposterController.js +328 -0
- package/src/controllers/impostersController.js +215 -0
- package/src/controllers/logsController.js +52 -0
- package/src/models/behaviors.js +553 -0
- package/src/models/behaviorsValidator.js +186 -0
- package/src/models/compatibility.js +133 -0
- package/src/models/dryRunValidator.js +261 -0
- package/src/models/filesystemBackedImpostersRepository.js +908 -0
- package/src/models/http/baseHttpServer.js +207 -0
- package/src/models/http/headersMap.js +87 -0
- package/src/models/http/httpProxy.js +230 -0
- package/src/models/http/httpRequest.js +82 -0
- package/src/models/http/httpServer.js +18 -0
- package/src/models/http/index.js +18 -0
- package/src/models/https/cert/mb-cert.pem +20 -0
- package/src/models/https/cert/mb-csr.pem +16 -0
- package/src/models/https/cert/mb-key.pem +27 -0
- package/src/models/https/httpsServer.js +42 -0
- package/src/models/https/index.js +18 -0
- package/src/models/imposter.js +243 -0
- package/src/models/imposterPrinter.js +120 -0
- package/src/models/impostersRepository.js +49 -0
- package/src/models/inMemoryImpostersRepository.js +418 -0
- package/src/models/jsonpath.js +44 -0
- package/src/models/mbConnection.js +107 -0
- package/src/models/predicates.js +438 -0
- package/src/models/protocols.js +242 -0
- package/src/models/responseResolver.js +398 -0
- package/src/models/smtp/index.js +16 -0
- package/src/models/smtp/smtpRequest.js +60 -0
- package/src/models/smtp/smtpServer.js +109 -0
- package/src/models/tcp/index.js +18 -0
- package/src/models/tcp/tcpProxy.js +110 -0
- package/src/models/tcp/tcpRequest.js +23 -0
- package/src/models/tcp/tcpServer.js +156 -0
- package/src/models/tcp/tcpValidator.js +19 -0
- package/src/models/xpath.js +95 -0
- package/src/mountebank.js +245 -0
- package/src/public/images/arrow_down.png +0 -0
- package/src/public/images/arrow_up.png +0 -0
- package/src/public/images/book.jpg +0 -0
- package/src/public/images/dataflow.png +0 -0
- package/src/public/images/favicon.ico +0 -0
- package/src/public/images/forkme_right_orange_ff7600.png +0 -0
- package/src/public/images/mountebank.png +0 -0
- package/src/public/images/overview.gif +0 -0
- package/src/public/images/quote.png +0 -0
- package/src/public/images/tw-logo.png +0 -0
- package/src/public/scripts/jquery/jquery-3.6.1.min.js +2 -0
- package/src/public/scripts/urlHashHandler.js +31 -0
- package/src/public/stylesheets/application.css +424 -0
- package/src/public/stylesheets/ie.css +14 -0
- package/src/public/stylesheets/imposters.css +121 -0
- package/src/public/stylesheets/jqueryui/1.10.4/themes/smoothness/jquery-ui.css +1178 -0
- package/src/util/combinators.js +68 -0
- package/src/util/date.js +51 -0
- package/src/util/errors.js +55 -0
- package/src/util/helpers.js +131 -0
- package/src/util/inherit.js +28 -0
- package/src/util/ip.js +54 -0
- package/src/util/logger.js +83 -0
- package/src/util/middleware.js +256 -0
- package/src/util/scopedLogger.js +47 -0
- package/src/views/_footer.ejs +20 -0
- package/src/views/_header.ejs +113 -0
- package/src/views/_imposter.ejs +8 -0
- package/src/views/config.ejs +71 -0
- package/src/views/docs/api/behaviors/copy.ejs +427 -0
- package/src/views/docs/api/behaviors/decorate.ejs +182 -0
- package/src/views/docs/api/behaviors/lookup.ejs +220 -0
- package/src/views/docs/api/behaviors/shellTransform.ejs +153 -0
- package/src/views/docs/api/behaviors/wait.ejs +121 -0
- package/src/views/docs/api/behaviors.ejs +141 -0
- package/src/views/docs/api/contracts/addStub-description.ejs +10 -0
- package/src/views/docs/api/contracts/addStub.ejs +10 -0
- package/src/views/docs/api/contracts/config-description.ejs +32 -0
- package/src/views/docs/api/contracts/config.ejs +23 -0
- package/src/views/docs/api/contracts/home-description.ejs +18 -0
- package/src/views/docs/api/contracts/home.ejs +13 -0
- package/src/views/docs/api/contracts/imposter-description.ejs +439 -0
- package/src/views/docs/api/contracts/imposter.ejs +182 -0
- package/src/views/docs/api/contracts/imposters-description.ejs +13 -0
- package/src/views/docs/api/contracts/imposters.ejs +13 -0
- package/src/views/docs/api/contracts/logs-description.ejs +3 -0
- package/src/views/docs/api/contracts/logs.ejs +14 -0
- package/src/views/docs/api/contracts/stub-description.ejs +4 -0
- package/src/views/docs/api/contracts/stub.ejs +7 -0
- package/src/views/docs/api/contracts/stubs-description.ejs +4 -0
- package/src/views/docs/api/contracts/stubs.ejs +11 -0
- package/src/views/docs/api/contracts.ejs +133 -0
- package/src/views/docs/api/errors.ejs +64 -0
- package/src/views/docs/api/fault/connectionReset.ejs +31 -0
- package/src/views/docs/api/fault/randomDataThenClose.ejs +31 -0
- package/src/views/docs/api/faults.ejs +57 -0
- package/src/views/docs/api/injection.ejs +426 -0
- package/src/views/docs/api/json.ejs +205 -0
- package/src/views/docs/api/jsonpath.ejs +210 -0
- package/src/views/docs/api/mocks.ejs +130 -0
- package/src/views/docs/api/overview.ejs +968 -0
- package/src/views/docs/api/predicates/and.ejs +62 -0
- package/src/views/docs/api/predicates/contains.ejs +64 -0
- package/src/views/docs/api/predicates/deepEquals.ejs +114 -0
- package/src/views/docs/api/predicates/endsWith.ejs +66 -0
- package/src/views/docs/api/predicates/equals.ejs +125 -0
- package/src/views/docs/api/predicates/exists.ejs +118 -0
- package/src/views/docs/api/predicates/inject.ejs +67 -0
- package/src/views/docs/api/predicates/matches.ejs +66 -0
- package/src/views/docs/api/predicates/not.ejs +52 -0
- package/src/views/docs/api/predicates/or.ejs +79 -0
- package/src/views/docs/api/predicates/startsWith.ejs +62 -0
- package/src/views/docs/api/predicates.ejs +382 -0
- package/src/views/docs/api/proxies.ejs +191 -0
- package/src/views/docs/api/proxy/addDecorateBehavior.ejs +115 -0
- package/src/views/docs/api/proxy/addWaitBehavior.ejs +96 -0
- package/src/views/docs/api/proxy/injectHeaders.ejs +91 -0
- package/src/views/docs/api/proxy/predicateGenerators.ejs +600 -0
- package/src/views/docs/api/proxy/proxyModes.ejs +495 -0
- package/src/views/docs/api/stubs.ejs +391 -0
- package/src/views/docs/api/xpath.ejs +281 -0
- package/src/views/docs/cli/configFiles.ejs +133 -0
- package/src/views/docs/cli/customFormatters.ejs +53 -0
- package/src/views/docs/cli/help.ejs +6 -0
- package/src/views/docs/cli/replay.ejs +42 -0
- package/src/views/docs/cli/restart.ejs +10 -0
- package/src/views/docs/cli/save.ejs +68 -0
- package/src/views/docs/cli/start.ejs +234 -0
- package/src/views/docs/cli/stop.ejs +32 -0
- package/src/views/docs/commandLine.ejs +93 -0
- package/src/views/docs/communityExtensions.ejs +233 -0
- package/src/views/docs/gettingStarted.ejs +146 -0
- package/src/views/docs/mentalModel.ejs +51 -0
- package/src/views/docs/protocols/custom.ejs +231 -0
- package/src/views/docs/protocols/http.ejs +238 -0
- package/src/views/docs/protocols/https.ejs +246 -0
- package/src/views/docs/protocols/smtp.ejs +142 -0
- package/src/views/docs/protocols/tcp.ejs +431 -0
- package/src/views/docs/security.ejs +38 -0
- package/src/views/faqs.ejs +65 -0
- package/src/views/feed.ejs +33 -0
- package/src/views/imposter.ejs +22 -0
- package/src/views/imposters.ejs +33 -0
- package/src/views/index.ejs +89 -0
- package/src/views/license.ejs +30 -0
- package/src/views/logs.ejs +77 -0
- package/src/views/releases/v1.1.0.ejs +55 -0
- package/src/views/releases/v1.1.36.ejs +84 -0
- package/src/views/releases/v1.1.72.ejs +92 -0
- package/src/views/releases/v1.10.0.ejs +108 -0
- package/src/views/releases/v1.11.0.ejs +109 -0
- package/src/views/releases/v1.12.0.ejs +96 -0
- package/src/views/releases/v1.13.0.ejs +118 -0
- package/src/views/releases/v1.14.0.ejs +107 -0
- package/src/views/releases/v1.14.1.ejs +94 -0
- package/src/views/releases/v1.15.0.ejs +113 -0
- package/src/views/releases/v1.16.0.ejs +104 -0
- package/src/views/releases/v1.2.0.ejs +78 -0
- package/src/views/releases/v1.2.103.ejs +86 -0
- package/src/views/releases/v1.2.122.ejs +86 -0
- package/src/views/releases/v1.2.30.ejs +84 -0
- package/src/views/releases/v1.2.45.ejs +84 -0
- package/src/views/releases/v1.2.56.ejs +79 -0
- package/src/views/releases/v1.3.0.ejs +86 -0
- package/src/views/releases/v1.3.1.ejs +100 -0
- package/src/views/releases/v1.4.0.ejs +96 -0
- package/src/views/releases/v1.4.1.ejs +103 -0
- package/src/views/releases/v1.4.2.ejs +100 -0
- package/src/views/releases/v1.4.3.ejs +113 -0
- package/src/views/releases/v1.5.0.ejs +104 -0
- package/src/views/releases/v1.5.1.ejs +91 -0
- package/src/views/releases/v1.6.0.ejs +109 -0
- package/src/views/releases/v1.7.0.ejs +113 -0
- package/src/views/releases/v1.7.1.ejs +90 -0
- package/src/views/releases/v1.7.2.ejs +96 -0
- package/src/views/releases/v1.8.0.ejs +121 -0
- package/src/views/releases/v1.9.0.ejs +111 -0
- package/src/views/releases/v2.0.0.ejs +159 -0
- package/src/views/releases/v2.1.0.ejs +121 -0
- package/src/views/releases/v2.1.1.ejs +106 -0
- package/src/views/releases/v2.1.2.ejs +84 -0
- package/src/views/releases/v2.2.0.ejs +115 -0
- package/src/views/releases/v2.2.1.ejs +102 -0
- package/src/views/releases/v2.3.0.ejs +121 -0
- package/src/views/releases/v2.3.1.ejs +100 -0
- package/src/views/releases/v2.3.2.ejs +102 -0
- package/src/views/releases/v2.3.3.ejs +97 -0
- package/src/views/releases/v2.4.0.ejs +114 -0
- package/src/views/releases/v2.5.0.ejs +51 -0
- package/src/views/releases/v2.6.0.ejs +35 -0
- package/src/views/releases/v2.7.0.ejs +32 -0
- package/src/views/releases/v2.8.0.ejs +36 -0
- package/src/views/releases/v2.8.1.ejs +7 -0
- package/src/views/releases/v2.8.2.ejs +26 -0
- package/src/views/releases/v2.9.0.ejs +32 -0
- package/src/views/releases/v2.9.1.ejs +10 -0
- package/src/views/releases.ejs +26 -0
- package/src/views/sitemap.ejs +36 -0
- 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&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&First=1&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&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&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&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] > 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] <= 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>
|