From 3cc3879580b2c9026db9d9f9f24ae626fe7d6e01 Mon Sep 17 00:00:00 2001
From: Ethan
Date: Wed, 5 Jun 2024 01:23:53 -0700
Subject: [PATCH 01/34] Updagting the studio page (#286)
Co-authored-by: Ethan Jones
---
studio/index.html | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/studio/index.html b/studio/index.html
index e7ccdb6e..b6747dd8 100644
--- a/studio/index.html
+++ b/studio/index.html
@@ -1,6 +1,6 @@
---
layout: default
-title: WireMock Studio
+title: WireMock Studio is now WireMock Cloud
description: WireMock Studio is a tool for building and running mock APIs on your desktop or in your cluster.
---
@@ -16,17 +16,15 @@
-
Studio
+
Cloud
-
is an IDE for your mock APIs.
-
is an IDE for your
-
mock APIs.
+
is an API productivity platform powered by WireMock.
- It provides management of multiple mock APIs, support for Swagger, OpenAPI, Postman and JWT, and a full web UI that's accessible to non-coders.
+ WireMock Studio has been replaced by WireMock Cloud. From Git sync to API prototyping to chaos testing and more, WireMock Cloud brings the power of mocking to every stage of building your application.
From 21ddc0da51b25355278fcb1c6864a5374185ef0c Mon Sep 17 00:00:00 2001
From: viktormelnychuk
Date: Thu, 6 Jun 2024 20:33:29 +0300
Subject: [PATCH 02/34] update docs
---
_docs/request-matching.md | 40 +++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/_docs/request-matching.md b/_docs/request-matching.md
index b781ce70..a0b2562d 100644
--- a/_docs/request-matching.md
+++ b/_docs/request-matching.md
@@ -987,6 +987,46 @@ The full list of comparison types used by default is as follows:
`CHILD_LOOKUP`
`ATTR_NAME_LOOKUP`
+#### Same child nodes with different content
+By default WireMock takes into account an order of identical child nodes. Meaning if actual request has different order of same node on same level than stub it won't be matched.
+This can be changed by passing additional argument to the `equalToXml` method
+
+Java:
+
+```java
+ .withRequestBody(equalToXml("" +
+ " 1" +
+ " 2" +
+ "",false,true))
+```
+```json
+{
+ "request": {
+ ...
+ "bodyPatterns" : [ {
+ "equalToXml" : "Hello",
+ "ignoreOrderOfSameNode": true
+ } ]
+ ...
+ },
+ ...
+}
+```
+This will make sure that stub above matches both of following requests:
+```xml
+
+ 2
+ 1
+
+```
+and
+```xml
+
+ 1
+ 2
+
+```
+If third argument is passed as `false` then first xml will not match the stub
### XPath
Deems a match if the attribute value is valid XML and matches the XPath expression supplied. An XML document will be considered to match if any elements are returned by the XPath evaluation. WireMock delegates to Java's in-built XPath engine (via XMLUnit), therefore up to (at least) Java 8 it supports XPath version 1.0.
From ca6fb47f73f00d2059f86779313d04935e79dee0 Mon Sep 17 00:00:00 2001
From: leeturner
Date: Wed, 12 Jun 2024 18:42:50 +0100
Subject: [PATCH 03/34] Clarify the version of wiremock for the new helpers
---
_docs/response-templating.md | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/_docs/response-templating.md b/_docs/response-templating.md
index c7a281c3..369ea322 100644
--- a/_docs/response-templating.md
+++ b/_docs/response-templating.md
@@ -343,9 +343,10 @@ Variable assignment and number helpers are available:
## Val helper
-The `val` helper can be used to access values or provide a default if the value is not present. It can also be used to
-assign a value to a variable much like the `assign` helper. The main difference between `val` and `assign` is that `val`
-will maintain the type of the date being assigned whereas `assign` will always assign a string.
+Released in WireMock version `3.6.0`, the `val` helper can be used to access values or provide a default if the value
+is not present. It can also be used to assign a value to a variable much like the `assign` helper. The main difference
+between `val` and `assign` is that `val` will maintain the type of the date being assigned whereas `assign` will always
+assign a string.
{% raw %}
@@ -744,9 +745,9 @@ Providing no parameters will result in an empty array.
{% endraw %}
## Array add & remove helpers
-The `arrayAdd` and `arrayRemove` helpers can be used to add or remove elements from an array based on a position value
-or the `start` or `end` keywords. If no position is specified, the element will be added or removed from the end of the
-array.
+As of WireMock version `3.6.0`, the `arrayAdd` and `arrayRemove` helpers can be used to add or remove elements from an
+array based on a position value or the `start` or `end` keywords. If no position is specified, the element will be
+added or removed from the end of the array.
{% raw %}
@@ -766,7 +767,8 @@ array.
## arrayJoin helper
-The `arrayJoin` helper will concatenate the values passed to it with the separator specified:
+Released in WireMock version `3.6.0`, the `arrayJoin` helper will concatenate the values passed to it with the
+separator specified:
{% raw %}
From 6b44a71de9b1fddf848638493565a93c3e488dc2 Mon Sep 17 00:00:00 2001
From: leeturner
Date: Mon, 17 Jun 2024 17:50:38 +0100
Subject: [PATCH 04/34] Add the new request.id to the docs
---
_docs/response-templating.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/_docs/response-templating.md b/_docs/response-templating.md
index 369ea322..df1095bd 100644
--- a/_docs/response-templating.md
+++ b/_docs/response-templating.md
@@ -181,6 +181,8 @@ wm.stubFor(get(urlPathMatching("/static/.*"))
The model of the request is supplied to the header and body templates. The following request attributes are available:
+`request.id` - The unique ID of each request (introduced in WireMock version x.x.x)
+
`request.url` - URL path and query
`request.path` - URL path. This can be referenced in full or it can be treated as an array of path segments (like below) e.g. `request.path.3`.
From 85375bd75e90e5585c366603d12ad3c758236b22 Mon Sep 17 00:00:00 2001
From: viktormelnychuk
Date: Wed, 19 Jun 2024 14:16:57 +0300
Subject: [PATCH 05/34] implement suggestion
---
_docs/request-matching.md | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/_docs/request-matching.md b/_docs/request-matching.md
index a0b2562d..1a346a58 100644
--- a/_docs/request-matching.md
+++ b/_docs/request-matching.md
@@ -988,8 +988,8 @@ The full list of comparison types used by default is as follows:
`ATTR_NAME_LOOKUP`
#### Same child nodes with different content
-By default WireMock takes into account an order of identical child nodes. Meaning if actual request has different order of same node on same level than stub it won't be matched.
-This can be changed by passing additional argument to the `equalToXml` method
+By default, WireMock takes into account an order of identical child nodes. Meaning if actual request has different order of same node on same level than stub it won't be matched.
+As of WireMock version `3.7.0`, this can be changed by passing additional argument to the `equalToXml` method
Java:
@@ -1004,7 +1004,7 @@ Java:
"request": {
...
"bodyPatterns" : [ {
- "equalToXml" : "Hello",
+ "equalToXml" : "12",
"ignoreOrderOfSameNode": true
} ]
...
From 19b06ca48ac1a1eec47d7302487deb4f2f48b2fe Mon Sep 17 00:00:00 2001
From: Ethan Jones
Date: Wed, 19 Jun 2024 12:14:22 -0400
Subject: [PATCH 06/34] Adding WM Live callout
---
assets/js/notifications.js | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git a/assets/js/notifications.js b/assets/js/notifications.js
index 35dccb97..09a1252d 100644
--- a/assets/js/notifications.js
+++ b/assets/js/notifications.js
@@ -1,7 +1,21 @@
var wiremock_notification_shown = localStorage.getItem(
"wiremock_notification_shown",
);
-var notifications = [];
+var notifications = [
+ {
+ content: {
+ title:
+ "Go beyond the basics of request matching with WireMock Live on July 18! " +
+ "Register now.",
+ },
+ layout: {
+ style: "wiremock_notification_with_link",
+ position: "top",
+ className: "info",
+ autoHide: false,
+ },
+ },
+];
if (wiremock_notification_shown == null) {
localStorage.setItem("wiremock_notification_shown", true);
From a780f85ed607fa9fdf5a11a345a97b21b4b45e77 Mon Sep 17 00:00:00 2001
From: leeturner
Date: Thu, 20 Jun 2024 09:44:21 +0100
Subject: [PATCH 07/34] Update the version number that this will be released in
---
_docs/response-templating.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/_docs/response-templating.md b/_docs/response-templating.md
index df1095bd..52c32fd6 100644
--- a/_docs/response-templating.md
+++ b/_docs/response-templating.md
@@ -181,7 +181,7 @@ wm.stubFor(get(urlPathMatching("/static/.*"))
The model of the request is supplied to the header and body templates. The following request attributes are available:
-`request.id` - The unique ID of each request (introduced in WireMock version x.x.x)
+`request.id` - The unique ID of each request (introduced in WireMock version `3.7.0`)
`request.url` - URL path and query
From df50329c202f4536eff3766d4390030285b54b29 Mon Sep 17 00:00:00 2001
From: leeturner
Date: Fri, 21 Jun 2024 15:32:21 +0100
Subject: [PATCH 08/34] Bumped WireMockk version to 3.7.0
---
_config.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/_config.yml b/_config.yml
index 30b074cc..e47b9b6e 100644
--- a/_config.yml
+++ b/_config.yml
@@ -234,7 +234,7 @@ compress_html:
ignore:
envs: development
-wiremock_version: 3.6.0
+wiremock_version: 3.7.0
wiremock_baseline: 3.x
pageEditPrefix: https://github.com/wiremock/wiremock.org/edit/main/
From bf9f7568fd4ee7b0f9fb4a396e959e9ae548d176 Mon Sep 17 00:00:00 2001
From: leeturner
Date: Thu, 27 Jun 2024 10:13:45 +0100
Subject: [PATCH 09/34] Update to the new wiremock oss logo
---
_includes/masthead.html | 20 +++++++++++---------
1 file changed, 11 insertions(+), 9 deletions(-)
diff --git a/_includes/masthead.html b/_includes/masthead.html
index 9577618d..65cb326c 100644
--- a/_includes/masthead.html
+++ b/_includes/masthead.html
@@ -1,15 +1,17 @@
- Stop faulty behavior from leaking into your production environments with OpenAPI validation on your mock API requests. Choose between hard and soft validation as needed. Learn more.
+ Using external data with WireMock Cloud mock servers lets you quickly bring updated test data without complex configuration, helping to guarantee your test sessions with our API mocks are realistic and simulate your application's production behavior. Learn more.
- Using external data with WireMock Cloud mock servers lets you quickly bring updated test data without complex configuration, helping to guarantee your test sessions with our API mocks are realistic and simulate your application's production behavior. Learn more.
+ Using external data with WireMock Cloud mock servers lets you quickly use updated test data without complex configuration, helping to guarantee your test sessions with our API mocks are realistic and simulate your application's production behavior. Learn more.
From 669d66ceca2d6c04ee686860ebdc21c61228c454 Mon Sep 17 00:00:00 2001
From: leeturner
Date: Thu, 4 Jul 2024 09:49:12 +0100
Subject: [PATCH 18/34] Update the WireMock openapi with the latest updates
from the main repo
---
assets/js/wiremock-admin-api.json | 327 +++++++++++++++++++++--
swagger/examples/health.yaml | 5 +
swagger/examples/record-spec.yaml | 2 +-
swagger/schemas/health.yaml | 25 ++
swagger/schemas/request-pattern.yaml | 38 +++
swagger/schemas/response-definition.yaml | 5 +
swagger/schemas/stub-mapping.yaml | 19 ++
swagger/wiremock-admin-api.yaml | 152 ++++++++++-
8 files changed, 549 insertions(+), 24 deletions(-)
create mode 100644 swagger/examples/health.yaml
create mode 100644 swagger/schemas/health.yaml
diff --git a/assets/js/wiremock-admin-api.json b/assets/js/wiremock-admin-api.json
index 929328a2..29cf743e 100644
--- a/assets/js/wiremock-admin-api.json
+++ b/assets/js/wiremock-admin-api.json
@@ -2,11 +2,12 @@
"openapi": "3.0.0",
"info": {
"title": "WireMock",
- "version": "2.35.0"
+ "version": "3.8.0",
+ "description": "WireMock offers a REST API for administration, troubleshooting and analysis purposes"
},
"externalDocs": {
"description": "WireMock user documentation",
- "url": "http://wiremock.org/docs/"
+ "url": "https://wiremock.org/docs/"
},
"servers": [
{
@@ -19,7 +20,7 @@
"description": "Operations on stub mappings",
"externalDocs": {
"description": "User documentation",
- "url": "http://wiremock.org/docs/stubbing/"
+ "url": "https://wiremock.org/docs/stubbing/"
}
},
{
@@ -27,7 +28,7 @@
"description": "Logged requests and responses received by the mock service",
"externalDocs": {
"description": "User documentation",
- "url": "http://wiremock.org/docs/verifying/"
+ "url": "https://wiremock.org/docs/verifying/"
}
},
{
@@ -35,7 +36,7 @@
"description": "Near misses allow querying of received requests or request patterns according to similarity",
"externalDocs": {
"description": "User documentation",
- "url": "http://wiremock.org/docs/verifying/#near-misses"
+ "url": "https://wiremock.org/docs/verifying/#near-misses"
}
},
{
@@ -43,7 +44,7 @@
"description": "Stub mapping record and snapshot functions",
"externalDocs": {
"description": "User documentation",
- "url": "http://wiremock.org/docs/record-playback/"
+ "url": "https://wiremock.org/docs/record-playback/"
}
},
{
@@ -51,9 +52,13 @@
"description": "Scenarios support modelling of stateful behaviour",
"externalDocs": {
"description": "User documentation",
- "url": "http://wiremock.org/docs/stateful-behaviour/"
+ "url": "https://wiremock.org/docs/stateful-behaviour/"
}
},
+ {
+ "name": "Files",
+ "description": "Manage the files used to support WireMock stubs"
+ },
{
"name": "System",
"description": "Global operations"
@@ -62,6 +67,7 @@
"paths": {
"/__admin/mappings": {
"get": {
+ "operationId": "getAllStubMappings",
"summary": "Get all stub mappings",
"tags": [
"Stub Mappings"
@@ -207,6 +213,13 @@
"type": "object",
"description": "Extra request headers to send when proxying to another host."
},
+ "removeProxyRequestHeaders": {
+ "type": "array",
+ "description": "Request headers to remove when proxying to another host.",
+ "items": {
+ "type": "string"
+ }
+ },
"body": {
"type": "string",
"description": "The response body as a string. Only one of body, base64Body, jsonBody or bodyFileName may be specified."
@@ -402,6 +415,7 @@
}
},
"post": {
+ "operationId": "createNewStubMapping",
"summary": "Create a new stub mapping",
"tags": [
"Stub Mappings"
@@ -519,6 +533,13 @@
"type": "object",
"description": "Extra request headers to send when proxying to another host."
},
+ "removeProxyRequestHeaders": {
+ "type": "array",
+ "description": "Request headers to remove when proxying to another host.",
+ "items": {
+ "type": "string"
+ }
+ },
"body": {
"type": "string",
"description": "The response body as a string. Only one of body, base64Body, jsonBody or bodyFileName may be specified."
@@ -778,6 +799,13 @@
"type": "object",
"description": "Extra request headers to send when proxying to another host."
},
+ "removeProxyRequestHeaders": {
+ "type": "array",
+ "description": "Request headers to remove when proxying to another host.",
+ "items": {
+ "type": "string"
+ }
+ },
"body": {
"type": "string",
"description": "The response body as a string. Only one of body, base64Body, jsonBody or bodyFileName may be specified."
@@ -932,6 +960,7 @@
}
},
"delete": {
+ "operationId": "deleteAllStubMappings",
"summary": "Delete all stub mappings",
"tags": [
"Stub Mappings"
@@ -945,6 +974,7 @@
},
"/__admin/mappings/reset": {
"post": {
+ "operationId": "resetStubMappings",
"summary": "Reset stub mappings",
"description": "Restores stub mappings to the defaults defined back in the backing store",
"tags": [
@@ -959,6 +989,7 @@
},
"/__admin/mappings/save": {
"post": {
+ "operationId": "persistStubMappings",
"summary": "Persist stub mappings",
"description": "Save all persistent stub mappings to the backing store",
"tags": [
@@ -973,6 +1004,7 @@
},
"/__admin/mappings/import": {
"post": {
+ "operationId": "importStubMappings",
"summary": "Import stub mappings",
"description": "Import given stub mappings to the backing store",
"tags": [
@@ -999,6 +1031,7 @@
}
],
"get": {
+ "operationId": "getStubMappingById",
"summary": "Get stub mapping by ID",
"tags": [
"Stub Mappings"
@@ -1118,6 +1151,13 @@
"type": "object",
"description": "Extra request headers to send when proxying to another host."
},
+ "removeProxyRequestHeaders": {
+ "type": "array",
+ "description": "Request headers to remove when proxying to another host.",
+ "items": {
+ "type": "string"
+ }
+ },
"body": {
"type": "string",
"description": "The response body as a string. Only one of body, base64Body, jsonBody or bodyFileName may be specified."
@@ -1275,6 +1315,7 @@
}
},
"put": {
+ "operationId": "updateStubMapping",
"summary": "Update a stub mapping",
"tags": [
"Stub Mappings"
@@ -1392,6 +1433,13 @@
"type": "object",
"description": "Extra request headers to send when proxying to another host."
},
+ "removeProxyRequestHeaders": {
+ "type": "array",
+ "description": "Request headers to remove when proxying to another host.",
+ "items": {
+ "type": "string"
+ }
+ },
"body": {
"type": "string",
"description": "The response body as a string. Only one of body, base64Body, jsonBody or bodyFileName may be specified."
@@ -1651,6 +1699,13 @@
"type": "object",
"description": "Extra request headers to send when proxying to another host."
},
+ "removeProxyRequestHeaders": {
+ "type": "array",
+ "description": "Request headers to remove when proxying to another host.",
+ "items": {
+ "type": "string"
+ }
+ },
"body": {
"type": "string",
"description": "The response body as a string. Only one of body, base64Body, jsonBody or bodyFileName may be specified."
@@ -1808,6 +1863,7 @@
}
},
"delete": {
+ "operationId": "deleteStubMapping",
"summary": "Delete a stub mapping",
"tags": [
"Stub Mappings"
@@ -1824,6 +1880,7 @@
},
"/__admin/mappings/find-by-metadata": {
"post": {
+ "operationId": "findStubMappingsByMetadata",
"description": "Find stubs by matching on their metadata",
"tags": [
"Stub Mappings"
@@ -2075,6 +2132,13 @@
"type": "object",
"description": "Extra request headers to send when proxying to another host."
},
+ "removeProxyRequestHeaders": {
+ "type": "array",
+ "description": "Request headers to remove when proxying to another host.",
+ "items": {
+ "type": "string"
+ }
+ },
"body": {
"type": "string",
"description": "The response body as a string. Only one of body, base64Body, jsonBody or bodyFileName may be specified."
@@ -2272,6 +2336,7 @@
},
"/__admin/mappings/remove-by-metadata": {
"post": {
+ "operationId": "removeStubMappingsByMetadata",
"summary": "Delete stub mappings matching metadata",
"tags": [
"Stub Mappings"
@@ -2412,6 +2477,7 @@
},
"/__admin/requests": {
"get": {
+ "operationId": "getAllRequestsInJournal",
"summary": "Get all requests in journal",
"tags": [
"Requests"
@@ -2533,6 +2599,7 @@
}
},
"delete": {
+ "operationId": "deleteAllRequestsInJournal",
"summary": "Delete all requests in journal",
"tags": [
"Requests"
@@ -2546,6 +2613,7 @@
},
"/__admin/requests/{requestId}": {
"get": {
+ "operationId": "getRequestById",
"summary": "Get request by ID",
"tags": [
"Requests"
@@ -2602,6 +2670,7 @@
}
},
"delete": {
+ "operationId": "deleteRequestById",
"summary": "Delete request by ID",
"tags": [
"Requests"
@@ -2627,6 +2696,7 @@
},
"/__admin/requests/reset": {
"post": {
+ "operationId": "emptyRequestJournal",
"deprecated": true,
"summary": "Empty the request journal",
"tags": [
@@ -2641,6 +2711,7 @@
},
"/__admin/requests/count": {
"post": {
+ "operationId": "countRequestsByCriteria",
"summary": "Count requests by criteria",
"description": "Count requests logged in the journal matching the specified criteria",
"tags": [
@@ -2758,6 +2829,7 @@
},
"/__admin/requests/remove": {
"post": {
+ "operationId": "removeRequestsByCriteria",
"summary": "Remove requests by criteria",
"description": "Removed requests logged in the journal matching the specified criteria",
"tags": [
@@ -2897,6 +2969,7 @@
},
"/__admin/requests/remove-by-metadata": {
"post": {
+ "operationId": "removeRequestsByMetadata",
"summary": "Delete requests mappings matching metadata",
"tags": [
"Requests"
@@ -3072,6 +3145,7 @@
},
"/__admin/requests/find": {
"post": {
+ "operationId": "findRequestsByCriteria",
"summary": "Find requests by criteria",
"description": "Retrieve details of requests logged in the journal matching the specified criteria",
"tags": [
@@ -3211,6 +3285,7 @@
},
"/__admin/requests/unmatched": {
"get": {
+ "operationId": "findUnmatchedRequests",
"summary": "Find unmatched requests",
"description": "Get details of logged requests that weren't matched by any stub mapping",
"tags": [
@@ -3260,6 +3335,7 @@
},
"/__admin/requests/unmatched/near-misses": {
"get": {
+ "operationId": "retrieveNearMissesForUnmatchedRequests",
"description": "Retrieve near-misses for all unmatched requests",
"tags": [
"Near Misses"
@@ -3354,6 +3430,7 @@
},
"/__admin/near-misses/request": {
"post": {
+ "operationId": "findNearMissesForRequest",
"summary": "Find near misses matching specific request",
"description": "Find at most 3 near misses for closest stub mappings to the specified request",
"tags": [
@@ -3512,6 +3589,7 @@
},
"/__admin/near-misses/request-pattern": {
"post": {
+ "operationId": "findNearMissesForRequestPattern",
"summary": "Find near misses matching request pattern",
"description": "Find at most 3 near misses for closest logged requests to the specified request pattern",
"tags": [
@@ -3697,6 +3775,7 @@
},
"/__admin/recordings/start": {
"post": {
+ "operationId": "startRecording",
"summary": "Start recording",
"description": "Begin recording stub mappings",
"tags": [
@@ -3947,14 +4026,14 @@
"targetBaseUrl": {
"type": "string",
"description": "Target URL when using the record and playback API",
- "example": "http://examples.wiremockapi.cloud/"
+ "example": "https://example.wiremock.org"
}
}
}
]
},
"example": {
- "targetBaseUrl": "http://examples.wiremockapi.cloud/",
+ "targetBaseUrl": "https://example.wiremock.org",
"filters": {
"urlPathPattern": "/api/.*",
"method": "GET"
@@ -3995,6 +4074,7 @@
},
"/__admin/recordings/stop": {
"post": {
+ "operationId": "stopRecording",
"summary": "Stop recording",
"description": "End recording of stub mappings",
"tags": [
@@ -4119,6 +4199,13 @@
"type": "object",
"description": "Extra request headers to send when proxying to another host."
},
+ "removeProxyRequestHeaders": {
+ "type": "array",
+ "description": "Request headers to remove when proxying to another host.",
+ "items": {
+ "type": "string"
+ }
+ },
"body": {
"type": "string",
"description": "The response body as a string. Only one of body, base64Body, jsonBody or bodyFileName may be specified."
@@ -4293,6 +4380,7 @@
},
"/__admin/recordings/status": {
"get": {
+ "operationId": "getRecordingStatus",
"summary": "Get recording status",
"tags": [
"Recordings"
@@ -4324,6 +4412,7 @@
},
"/__admin/recordings/snapshot": {
"post": {
+ "operationId": "takeRecordingSnapshot",
"summary": "Take a snapshot recording",
"tags": [
"Recordings"
@@ -4740,6 +4829,13 @@
"type": "object",
"description": "Extra request headers to send when proxying to another host."
},
+ "removeProxyRequestHeaders": {
+ "type": "array",
+ "description": "Request headers to remove when proxying to another host.",
+ "items": {
+ "type": "string"
+ }
+ },
"body": {
"type": "string",
"description": "The response body as a string. Only one of body, base64Body, jsonBody or bodyFileName may be specified."
@@ -4914,6 +5010,7 @@
},
"/__admin/scenarios": {
"get": {
+ "operationId": "getAllScenarios",
"summary": "Get all scenarios",
"tags": [
"Scenarios"
@@ -4973,6 +5070,7 @@
},
"/__admin/scenarios/reset": {
"post": {
+ "operationId": "resetAllScenarios",
"summary": "Reset the state of all scenarios",
"tags": [
"Scenarios"
@@ -4984,8 +5082,101 @@
}
}
},
+ "/__admin/files": {
+ "get": {
+ "operationId": "getAllFileNames",
+ "summary": "Get all file names",
+ "tags": [
+ "Files"
+ ],
+ "responses": {
+ "200": {
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "example": [
+ "file1.json",
+ "file2.json",
+ "file3.txt"
+ ]
+ }
+ }
+ },
+ "description": "All scenarios"
+ }
+ }
+ }
+ },
+ "/__admin/files/{fileId}": {
+ "parameters": [
+ {
+ "description": "The name of the file",
+ "in": "path",
+ "name": "fileId",
+ "required": true,
+ "example": "file1.json",
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "get": {
+ "operationId": "getFileById",
+ "summary": "Get file by ID",
+ "tags": [
+ "Files"
+ ],
+ "responses": {
+ "404": {
+ "description": "File not found"
+ },
+ "200": {
+ "description": "The contents of the file"
+ }
+ }
+ },
+ "put": {
+ "operationId": "updateFileById",
+ "summary": "Update or create a file",
+ "tags": [
+ "Files"
+ ],
+ "requestBody": {
+ "content": {
+ "application/octet-stream": {
+ "schema": {
+ "type": "string",
+ "format": "byte"
+ }
+ }
+ }
+ },
+ "responses": {
+ "200": {
+ "description": "OK - contents of the request body as a string"
+ }
+ }
+ },
+ "delete": {
+ "operationId": "deleteFileById",
+ "summary": "Delete a file if it exists",
+ "tags": [
+ "Files"
+ ],
+ "responses": {
+ "200": {
+ "description": "OK"
+ }
+ }
+ }
+ },
"/__admin/settings": {
"post": {
+ "operationId": "updateGlobalSettings",
"summary": "Update global settings",
"tags": [
"System"
@@ -5063,6 +5254,7 @@
},
"/__admin/reset": {
"post": {
+ "operationId": "resetMappingsAndJournal",
"summary": "Reset mappings and request journal",
"description": "Reset mappings to the default state and reset the request journal",
"tags": [
@@ -5075,15 +5267,106 @@
}
}
},
- "/__admin/shutdown": {
- "post": {
- "description": "Shutdown the WireMock server",
+ "/__admin/shutdown" : {
+ "post" : {
+ "operationId" : "shutdownServer",
+ "summary" : "Shutdown the WireMock server",
+ "description" : "Shutdown the WireMock server",
+ "tags" : [ "System" ],
+ "responses" : {
+ "200" : {
+ "description" : "Server will be shut down"
+ }
+ }
+ }
+ },
+ "/__admin/version": {
+ "get": {
+ "operationId": "getVersion",
+ "summary": "Return the version of the WireMock server",
+ "description": "Returns the version of the WireMock server",
"tags": [
"System"
],
"responses": {
"200": {
- "description": "Server will be shut down"
+ "description": "Successfully returned the version of the WireMock server",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "version": {
+ "type": "string",
+ "example": "3.8.0"
+ }
+ }
+ },
+ "example": {
+ "version": "3.8.0"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/__admin/health": {
+ "get": {
+ "operationId": "getHealth",
+ "summary": "Return the health of the WireMock server",
+ "description": "Returns the health of the WireMock server",
+ "tags": [
+ "System"
+ ],
+ "responses": {
+ "200": {
+ "description": "Successful health and uptime data",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "status": {
+ "type": "string",
+ "description": "The status of the server",
+ "example": "healthy",
+ "enum": [
+ "healthy",
+ "unhealthy"
+ ]
+ },
+ "message": {
+ "type": "string",
+ "description": "Longer message regarding the status of the server",
+ "example": "Wiremock is ok"
+ },
+ "version": {
+ "type": "string",
+ "description": "The WireMock version",
+ "example": "3.8.0"
+ },
+ "upTimeInSeconds": {
+ "type": "integer",
+ "description": "How long the server has been running",
+ "example": 14355
+ },
+ "timestamp": {
+ "type": "string",
+ "description": "The current timestamp",
+ "example": "2024-07-03T13:16:06.172362Z"
+ }
+ }
+ },
+ "example": {
+ "status": "healthy",
+ "message": "Wiremock is ok",
+ "version": "3.8.0",
+ "uptimeInSeconds": 14355,
+ "timestamp": "2024-07-03T13:16:06.172362Z"
+ }
+ }
+ }
}
}
}
@@ -5294,6 +5577,13 @@
"type": "object",
"description": "Extra request headers to send when proxying to another host."
},
+ "removeProxyRequestHeaders": {
+ "type": "array",
+ "description": "Request headers to remove when proxying to another host.",
+ "items": {
+ "type": "string"
+ }
+ },
"body": {
"type": "string",
"description": "The response body as a string. Only one of body, base64Body, jsonBody or bodyFileName may be specified."
@@ -5683,14 +5973,14 @@
"targetBaseUrl": {
"type": "string",
"description": "Target URL when using the record and playback API",
- "example": "http://examples.wiremockapi.cloud/"
+ "example": "https://example.wiremock.org"
}
}
}
]
},
"example": {
- "targetBaseUrl": "http://examples.wiremockapi.cloud/",
+ "targetBaseUrl": "https://example.wiremock.org",
"filters": {
"urlPathPattern": "/api/.*",
"method": "GET"
@@ -6131,6 +6421,13 @@
"type": "object",
"description": "Extra request headers to send when proxying to another host."
},
+ "removeProxyRequestHeaders": {
+ "type": "array",
+ "description": "Request headers to remove when proxying to another host.",
+ "items": {
+ "type": "string"
+ }
+ },
"body": {
"type": "string",
"description": "The response body as a string. Only one of body, base64Body, jsonBody or bodyFileName may be specified."
diff --git a/swagger/examples/health.yaml b/swagger/examples/health.yaml
new file mode 100644
index 00000000..4c74d40e
--- /dev/null
+++ b/swagger/examples/health.yaml
@@ -0,0 +1,5 @@
+status: "healthy"
+message: "Wiremock is ok"
+version: "3.8.0"
+uptimeInSeconds: 14355
+timestamp: "2024-07-03T13:16:06.172362Z"
\ No newline at end of file
diff --git a/swagger/examples/record-spec.yaml b/swagger/examples/record-spec.yaml
index 552de91f..660b9125 100644
--- a/swagger/examples/record-spec.yaml
+++ b/swagger/examples/record-spec.yaml
@@ -1,4 +1,4 @@
-targetBaseUrl: http://examples.wiremockapi.cloud/
+targetBaseUrl: http://example.mocklab.io
filters:
urlPathPattern: "/api/.*"
method: GET
diff --git a/swagger/schemas/health.yaml b/swagger/schemas/health.yaml
new file mode 100644
index 00000000..cd0eb57f
--- /dev/null
+++ b/swagger/schemas/health.yaml
@@ -0,0 +1,25 @@
+type: object
+properties:
+ status:
+ type: string
+ example: "healthy"
+ description: "The status of the server"
+ enum:
+ - healthy
+ - unhealthy
+ message:
+ type: string
+ description: "Longer message regarding the status of the server"
+ example: "Wiremock is ok"
+ version:
+ type: string
+ description: "The WireMock version"
+ example: "3.8.0"
+ uptimeInSeconds:
+ type: integer
+ description: "How long the server has been running"
+ example: 14355
+ timestamp:
+ type: string
+ description: "The current timestamp"
+ example: "2024-07-03T13:16:06.172362Z"
diff --git a/swagger/schemas/request-pattern.yaml b/swagger/schemas/request-pattern.yaml
index 628878f0..4035ff8e 100644
--- a/swagger/schemas/request-pattern.yaml
+++ b/swagger/schemas/request-pattern.yaml
@@ -8,6 +8,15 @@ example:
method: POST
url: /some/thing
properties:
+ scheme:
+ type: string
+ description: The URI scheme
+ host:
+ type: object
+ description: 'URI host pattern to match against in the "": "" form'
+ port:
+ type: integer
+ description: The HTTP port number
method:
type: string
description: The HTTP request method e.g. GET
@@ -48,3 +57,32 @@ properties:
description: 'Request body patterns to match against in the : { "": "" } form'
items:
type: object
+ customMatcher:
+ type: object
+ description: Custom request matcher to match against
+ properties:
+ name:
+ type: string
+ description: The matcher's name specified in the implementation of the matcher.
+ parameters:
+ type: object
+ multipartPatterns:
+ type: array
+ description: Multipart patterns to match against headers and body
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ matchingType:
+ type: string
+ default: ANY
+ enum:
+ - ALL
+ - ANY
+ headers:
+ type: object
+ bodyPatterns:
+ type: array
+ items:
+ type: object
diff --git a/swagger/schemas/response-definition.yaml b/swagger/schemas/response-definition.yaml
index e6a035f8..43bf4c58 100644
--- a/swagger/schemas/response-definition.yaml
+++ b/swagger/schemas/response-definition.yaml
@@ -13,6 +13,11 @@ allOf:
additionalProxyRequestHeaders:
type: object
description: Extra request headers to send when proxying to another host.
+ removeProxyRequestHeaders:
+ type: array
+ description: Request headers to remove when proxying to another host.
+ items:
+ type: string
body:
type: string
description: The response body as a string. Only one of body, base64Body, jsonBody or bodyFileName may be specified.
diff --git a/swagger/schemas/stub-mapping.yaml b/swagger/schemas/stub-mapping.yaml
index 16ed220f..176eafd9 100644
--- a/swagger/schemas/stub-mapping.yaml
+++ b/swagger/schemas/stub-mapping.yaml
@@ -32,6 +32,25 @@ properties:
postServeActions:
type: object
description: A map of the names of post serve action extensions to trigger and their parameters.
+ serveEventListeners:
+ type: array
+ description: The list of serve event listeners
+ items:
+ type: object
+ properties:
+ name:
+ type: string
+ requestPhases:
+ type: array
+ items:
+ type: string
+ enum:
+ - BEFORE_MATCH
+ - AFTER_MATCH
+ - BEFORE_RESPONSE_SENT
+ - AFTER_COMPLETE
+ parameters:
+ type: object
metadata:
type: object
description: Arbitrary metadata to be used for e.g. tagging, documentation. Can also be used to find and remove stubs.
diff --git a/swagger/wiremock-admin-api.yaml b/swagger/wiremock-admin-api.yaml
index a7d0a33b..f605ca3b 100644
--- a/swagger/wiremock-admin-api.yaml
+++ b/swagger/wiremock-admin-api.yaml
@@ -2,11 +2,12 @@ openapi: 3.0.0
info:
title: WireMock
- version: 2.35.0
+ version: 3.8.0
+ description: "WireMock offers a REST API for administration, troubleshooting and analysis purposes"
externalDocs:
description: WireMock user documentation
- url: http://wiremock.org/docs/
+ url: https://wiremock.org/docs/
servers:
- url: /
@@ -16,33 +17,36 @@ tags:
description: Operations on stub mappings
externalDocs:
description: User documentation
- url: http://wiremock.org/docs/stubbing/
+ url: https://wiremock.org/docs/stubbing/
- name: Requests
description: Logged requests and responses received by the mock service
externalDocs:
description: User documentation
- url: http://wiremock.org/docs/verifying/
+ url: https://wiremock.org/docs/verifying/
- name: Near Misses
description: Near misses allow querying of received requests or request patterns according to similarity
externalDocs:
description: User documentation
- url: http://wiremock.org/docs/verifying/#near-misses
+ url: https://wiremock.org/docs/verifying/#near-misses
- name: Recordings
description: Stub mapping record and snapshot functions
externalDocs:
description: User documentation
- url: http://wiremock.org/docs/record-playback/
+ url: https://wiremock.org/docs/record-playback/
- name: Scenarios
description: Scenarios support modelling of stateful behaviour
externalDocs:
description: User documentation
- url: http://wiremock.org/docs/stateful-behaviour/
+ url: https://wiremock.org/docs/stateful-behaviour/
+ - name: Files
+ description: Manage the files used to support WireMock stubs
- name: System
description: Global operations
paths:
/__admin/mappings:
get:
+ operationId: getAllStubMappings
summary: Get all stub mappings
tags:
- Stub Mappings
@@ -71,6 +75,7 @@ paths:
$ref: 'examples/stub-mappings.yaml'
description: All stub mappings
post:
+ operationId: createNewStubMapping
summary: Create a new stub mapping
tags:
- Stub Mappings
@@ -80,6 +85,7 @@ paths:
'201':
$ref: "#/components/responses/stubMapping"
delete:
+ operationId: deleteAllStubMappings
summary: Delete all stub mappings
tags:
- Stub Mappings
@@ -89,6 +95,7 @@ paths:
/__admin/mappings/reset:
post:
+ operationId: resetStubMappings
summary: Reset stub mappings
description: Restores stub mappings to the defaults defined back in the backing store
tags:
@@ -99,6 +106,7 @@ paths:
/__admin/mappings/save:
post:
+ operationId: persistStubMappings
summary: Persist stub mappings
description: Save all persistent stub mappings to the backing store
tags:
@@ -109,6 +117,7 @@ paths:
/__admin/mappings/import:
post:
+ operationId: importStubMappings
summary: Import stub mappings
description: Import given stub mappings to the backing store
tags:
@@ -127,6 +136,7 @@ paths:
schema:
type: string
get:
+ operationId: getStubMappingById
summary: Get stub mapping by ID
tags:
- Stub Mappings
@@ -136,6 +146,7 @@ paths:
'200':
$ref: "#/components/responses/stubMapping"
put:
+ operationId: updateStubMapping
summary: Update a stub mapping
tags:
- Stub Mappings
@@ -147,6 +158,7 @@ paths:
'200':
$ref: "#/components/responses/stubMapping"
delete:
+ operationId: deleteStubMapping
summary: Delete a stub mapping
tags:
- Stub Mappings
@@ -158,6 +170,7 @@ paths:
/__admin/mappings/find-by-metadata:
post:
+ operationId: findStubMappingsByMetadata
description: Find stubs by matching on their metadata
tags:
- Stub Mappings
@@ -181,6 +194,7 @@ paths:
/__admin/mappings/remove-by-metadata:
post:
+ operationId: removeStubMappingsByMetadata
summary: Delete stub mappings matching metadata
tags:
- Stub Mappings
@@ -197,6 +211,7 @@ paths:
/__admin/requests:
get:
+ operationId: getAllRequestsInJournal
summary: Get all requests in journal
tags:
- Requests
@@ -221,6 +236,7 @@ paths:
$ref: 'examples/serve-events.yaml'
description: List of received requests
delete:
+ operationId: deleteAllRequestsInJournal
summary: Delete all requests in journal
tags:
- Requests
@@ -230,6 +246,7 @@ paths:
/__admin/requests/{requestId}:
get:
+ operationId: getRequestById
summary: Get request by ID
tags:
- Requests
@@ -251,6 +268,7 @@ paths:
example:
$ref: "examples/request.yaml"
delete:
+ operationId: deleteRequestById
summary: Delete request by ID
tags:
- Requests
@@ -268,6 +286,7 @@ paths:
/__admin/requests/reset:
post:
+ operationId: emptyRequestJournal
deprecated: true
summary: Empty the request journal
tags:
@@ -278,6 +297,7 @@ paths:
/__admin/requests/count:
post:
+ operationId: countRequestsByCriteria
summary: Count requests by criteria
description: Count requests logged in the journal matching the specified criteria
tags:
@@ -298,6 +318,7 @@ paths:
/__admin/requests/remove:
post:
+ operationId: removeRequestsByCriteria
summary: Remove requests by criteria
description: Removed requests logged in the journal matching the specified criteria
tags:
@@ -312,8 +333,11 @@ paths:
example:
$ref: "examples/requests.yaml"
+
+
/__admin/requests/remove-by-metadata:
post:
+ operationId: removeRequestsByMetadata
summary: Delete requests mappings matching metadata
tags:
- Requests
@@ -334,6 +358,7 @@ paths:
/__admin/requests/find:
post:
+ operationId: findRequestsByCriteria
summary: Find requests by criteria
description: Retrieve details of requests logged in the journal matching the specified criteria
tags:
@@ -350,6 +375,7 @@ paths:
/__admin/requests/unmatched:
get:
+ operationId: findUnmatchedRequests
summary: Find unmatched requests
description: Get details of logged requests that weren't matched by any stub mapping
tags:
@@ -364,6 +390,7 @@ paths:
/__admin/requests/unmatched/near-misses:
get:
+ operationId: retrieveNearMissesForUnmatchedRequests
description: Retrieve near-misses for all unmatched requests
tags:
- Near Misses
@@ -373,6 +400,7 @@ paths:
/__admin/near-misses/request:
post:
+ operationId: findNearMissesForRequest
summary: Find near misses matching specific request
description: Find at most 3 near misses for closest stub mappings to the specified request
tags:
@@ -391,6 +419,7 @@ paths:
/__admin/near-misses/request-pattern:
post:
+ operationId: findNearMissesForRequestPattern
summary: Find near misses matching request pattern
description: Find at most 3 near misses for closest logged requests to the specified request pattern
tags:
@@ -403,6 +432,7 @@ paths:
/__admin/recordings/start:
post:
+ operationId: startRecording
summary: Start recording
description: Begin recording stub mappings
tags:
@@ -415,6 +445,7 @@ paths:
/__admin/recordings/stop:
post:
+ operationId: stopRecording
summary: Stop recording
description: End recording of stub mappings
tags:
@@ -431,6 +462,7 @@ paths:
/__admin/recordings/status:
get:
+ operationId: getRecordingStatus
summary: Get recording status
tags:
- Recordings
@@ -452,6 +484,7 @@ paths:
/__admin/recordings/snapshot:
post:
+ operationId: takeRecordingSnapshot
summary: Take a snapshot recording
tags:
- Recordings
@@ -469,6 +502,7 @@ paths:
/__admin/scenarios:
get:
+ operationId: getAllScenarios
summary: Get all scenarios
tags:
- Scenarios
@@ -487,6 +521,7 @@ paths:
/__admin/scenarios/reset:
post:
+ operationId: resetAllScenarios
summary: Reset the state of all scenarios
tags:
- Scenarios
@@ -494,8 +529,69 @@ paths:
'200':
description: Successfully reset
+
+ /__admin/files:
+ get:
+ operationId: getAllFileNames
+ summary: Get all file names
+ tags:
+ - Files
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: string
+ example: ["file1.json", "file2.json", "file3.txt"]
+ description: All scenarios
+
+ /__admin/files/{fileId}:
+ parameters:
+ - description: The name of the file
+ in: path
+ name: fileId
+ required: true
+ example: file1.json
+ schema:
+ type: string
+ get:
+ operationId: getFileById
+ summary: Get file by ID
+ tags:
+ - Files
+ responses:
+ '404':
+ description: File not found
+ '200':
+ description: The contents of the file
+ put:
+ operationId: updateFileById
+ summary: Update or create a file
+ tags:
+ - Files
+ requestBody:
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: byte
+ responses:
+ '200':
+ description: OK - contents of the request body as a string
+ delete:
+ operationId: deleteFileById
+ summary: Delete a file if it exists
+ tags:
+ - Files
+ responses:
+ '200':
+ description: OK
+
/__admin/settings:
post:
+ operationId: updateGlobalSettings
summary: Update global settings
tags:
- System
@@ -518,6 +614,7 @@ paths:
/__admin/reset:
post:
+ operationId: resetMappingsAndJournal
summary: Reset mappings and request journal
description: Reset mappings to the default state and reset the request journal
tags:
@@ -528,12 +625,51 @@ paths:
/__admin/shutdown:
post:
+ operationId: shutdownServer
+ summary: Shutdown the WireMock server
description: Shutdown the WireMock server
tags:
- System
responses:
'200':
description: Server will be shut down
+
+
+ /__admin/version:
+ get:
+ operationId: getVersion
+ summary: Return the version of the WireMock server
+ description: Returns the version of the WireMock server
+ tags:
+ - System
+ responses:
+ '200':
+ description: Successfully returned the version of the WireMock server
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ version:
+ type: string
+ example: "3.8.0"
+
+ /__admin/health:
+ get:
+ operationId: getHealth
+ summary: Return the health of the WireMock server
+ description: Returns the health of the WireMock server
+ tags:
+ - System
+ responses:
+ '200':
+ description: Successful health and uptime data
+ content:
+ application/json:
+ schema:
+ $ref: 'schemas/health.yaml'
+ example:
+ $ref: 'examples/health.yaml'
components:
requestBodies:
@@ -569,7 +705,7 @@ components:
targetBaseUrl:
type: string
description: Target URL when using the record and playback API
- example: http://examples.wiremockapi.cloud/
+ example: https://example.wiremock.org
example:
$ref: "examples/record-spec.yaml"
From 22e6e2224d3615333e06edd5d668b4080e64203a Mon Sep 17 00:00:00 2001
From: leeturner
Date: Thu, 4 Jul 2024 09:54:09 +0100
Subject: [PATCH 19/34] Fix old url
---
swagger/examples/record-spec.yaml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/swagger/examples/record-spec.yaml b/swagger/examples/record-spec.yaml
index 660b9125..f8164291 100644
--- a/swagger/examples/record-spec.yaml
+++ b/swagger/examples/record-spec.yaml
@@ -1,4 +1,4 @@
-targetBaseUrl: http://example.mocklab.io
+targetBaseUrl: https://examples.wiremockapi.cloud/
filters:
urlPathPattern: "/api/.*"
method: GET
From 45ec231f4965fd775c8cda1549b5c150147399c5 Mon Sep 17 00:00:00 2001
From: leeturner
Date: Fri, 5 Jul 2024 11:15:40 +0100
Subject: [PATCH 20/34] Update the external resources page with new items
---
external-resources/index.html | 416 ++++++++++++++--------------------
1 file changed, 173 insertions(+), 243 deletions(-)
diff --git a/external-resources/index.html b/external-resources/index.html
index 8ae46985..fb918bcf 100644
--- a/external-resources/index.html
+++ b/external-resources/index.html
@@ -15,263 +15,193 @@
Community Resources
-
- Code, articles and videos related to WireMock from around the web.
-
Spring Contract Verifier (previously called Accurest) is a consumer driven contracts tool that generates WireMock stub mappings as examples for client testing.
- Sam Edwards has been hugely helpful in getting WireMock onto the Android platform and helping others do so. Here is his blog post explaining how to write an Espresso test using WireMock as your app's back-end:
-
- Chris Batey did an excellent talk at Skillsmatter in London about building fault tolerant microservices. He showed some practical failure testing strategies using WireMock and Saboteur he'd used for real while working at Sky:
-
- Daniel Bryant's excellent QCon presentation “The Seven Deadly Sins of Microservices” covers the full gamut of microservice anti-patterns seen in the wild, with some sound advice on how to fix them. WireMock and Saboteur get an honourable mention in the testing discussion:
-
-
- The folks at Intuit have built a very impressive and ambitious testing setup, using WireMock to isolate individual services. Here's a talk they did at AWS:Reinvent:
-
+
A response transformer for injecting data from the request body into the response from Open Table.
- Michael Bailey was the first person to publicly demonstrate the possibility of running WireMock on Android. Here's his presentation at Google's GTAC conference on the testing setup used by his team at Amex:
-
- Tom and Rob Elliot gave a join talk at Skillsmatter about patterns for readable and scalable tests with WireMock, and an approach for unit testing a CDN:
-