Skip to content

Commit 43b50ee

Browse files
authored
Added integration test examples (#26)
Added integration tests for two working examples using remote loading of stub mappings. The tests make it easier to understand how to use the extension. ## Submitter checklist - [ ] The PR request is well described and justified, including the body and the references - [ ] The PR title represents the desired changelog entry - [ ] The repository's code style is followed (see the contributing guide) - [ ] Test coverage that demonstrates that the change works as expected - [ ] For new features, there's necessary documentation in this pull request or in a subsequent PR to [wiremock.org](https://github.com/wiremock/wiremock.org)
1 parent 70e9a60 commit 43b50ee

File tree

4 files changed

+422
-0
lines changed

4 files changed

+422
-0
lines changed
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
package org.wiremock.extensions.state;
2+
3+
import com.github.tomakehurst.wiremock.WireMockServer;
4+
import com.github.tomakehurst.wiremock.client.WireMock;
5+
import com.github.tomakehurst.wiremock.core.Options;
6+
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
7+
import com.github.tomakehurst.wiremock.junit.Stubbing;
8+
import com.github.tomakehurst.wiremock.store.Store;
9+
import com.google.common.io.Resources;
10+
import io.restassured.http.ContentType;
11+
import org.apache.http.HttpStatus;
12+
import org.assertj.core.api.Assertions;
13+
import org.awaitility.core.ThrowingRunnable;
14+
import org.junit.jupiter.api.BeforeAll;
15+
import org.junit.jupiter.api.Test;
16+
import org.junit.jupiter.api.TestInstance;
17+
import org.junit.jupiter.api.parallel.Execution;
18+
import org.wiremock.extensions.state.internal.ContextManager;
19+
20+
import java.io.File;
21+
import java.net.URI;
22+
import java.time.Duration;
23+
import java.util.Locale;
24+
25+
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
26+
import static io.restassured.RestAssured.given;
27+
import static org.awaitility.Awaitility.await;
28+
import static org.hamcrest.MatcherAssert.assertThat;
29+
import static org.hamcrest.Matchers.equalTo;
30+
import static org.hamcrest.Matchers.is;
31+
import static org.junit.jupiter.api.parallel.ExecutionMode.SAME_THREAD;
32+
33+
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
34+
@Execution(SAME_THREAD)
35+
public class IntegrationTest {
36+
37+
static WireMockServer wireMockServer;
38+
static WireMock wmClient;
39+
static Stubbing wm;
40+
41+
private static final Store<String, Object> store = new CaffeineStore();
42+
static final ContextManager contextManager = new ContextManager(store);
43+
44+
45+
@BeforeAll
46+
public static void initWithTempDir() throws Exception {
47+
WireMockConfiguration options = wireMockConfig().withRootDirectory(Resources.getResource("remoteloader").getPath())
48+
.templatingEnabled(true).globalTemplating(true)
49+
.extensions(new StateExtension(store));
50+
System.out.println(
51+
"Configuring WireMockServer with root directory: " + options.filesRoot().getPath());
52+
if (options.portNumber() == Options.DEFAULT_PORT) {
53+
options.dynamicPort();
54+
}
55+
56+
wireMockServer = new WireMockServer(options);
57+
wireMockServer.start();
58+
WireMock.configureFor(wireMockServer.port());
59+
wm = wireMockServer;
60+
61+
Locale.setDefault(Locale.ENGLISH);
62+
wmClient = WireMock.create().port(wireMockServer.port()).build();
63+
}
64+
65+
@Test
66+
void testSimpleContext() throws Exception {
67+
String entityId = "IDDQD";
68+
String contextId = "dynamic-process-" + entityId;
69+
70+
given()
71+
.accept(ContentType.JSON)
72+
.body("<items><item>" + entityId + "</item></items>")
73+
.post(new URI(wireMockServer.baseUrl() + "/dynamic/process"))
74+
.then()
75+
.statusCode(HttpStatus.SC_CREATED);
76+
77+
awaitAndAssert(() -> Assertions.assertThat(contextManager.numUpdates(contextId)).isEqualTo(1));
78+
assertThat(store.get(contextId).isPresent(), is(true));
79+
80+
81+
given()
82+
.accept(ContentType.JSON)
83+
.get(new URI(wireMockServer.baseUrl() + "/dynamic/process/" + entityId))
84+
.then()
85+
.statusCode(HttpStatus.SC_OK)
86+
.body("result", equalTo(entityId));
87+
88+
awaitAndAssert(() -> Assertions.assertThat(contextManager.numUpdates(contextId)).isEqualTo(1));
89+
assertThat(store.get(contextId).isPresent(), is(true));
90+
91+
given()
92+
.accept(ContentType.JSON)
93+
.delete(new URI(wireMockServer.baseUrl() + "/dynamic/process/" + entityId))
94+
.then()
95+
.statusCode(HttpStatus.SC_OK);
96+
97+
awaitAndAssert(() -> Assertions.assertThat(contextManager.numUpdates(contextId)).isEqualTo(0));
98+
assertThat(store.get(contextId).isPresent(), is(false));
99+
}
100+
101+
@Test
102+
void testContextWithList() throws Exception {
103+
String queueId = "my-queue";
104+
String contextId = "queue-" + queueId;
105+
String itemId1 = "id1";
106+
String itemId2 = "anotherId";
107+
108+
String noDataValue = "no data";
109+
110+
// empty queue
111+
given()
112+
.get(new URI(wireMockServer.baseUrl() + "/queue/" + queueId))
113+
.then()
114+
.statusCode(HttpStatus.SC_OK)
115+
.body("item", equalTo(noDataValue));
116+
awaitAndAssert(() -> Assertions.assertThat(contextManager.numUpdates(contextId)).isEqualTo(0));
117+
118+
// nothing to ack = error
119+
given()
120+
.post(new URI(wireMockServer.baseUrl() + "/queue/" + queueId + "/ack"))
121+
.then()
122+
.statusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
123+
awaitAndAssert(() -> Assertions.assertThat(contextManager.numUpdates(contextId)).isEqualTo(0));
124+
125+
// put into queue
126+
given()
127+
.post(new URI(wireMockServer.baseUrl() + "/queue/" + queueId + "/" + itemId1))
128+
.then()
129+
.statusCode(HttpStatus.SC_OK);
130+
awaitAndAssert(() -> Assertions.assertThat(contextManager.numUpdates(contextId)).isEqualTo(1));
131+
132+
// get item1 from queue without ack
133+
given()
134+
.get(new URI(wireMockServer.baseUrl() + "/queue/" + queueId))
135+
.then()
136+
.statusCode(HttpStatus.SC_OK)
137+
.body("item", equalTo(itemId1));
138+
awaitAndAssert(() -> Assertions.assertThat(contextManager.numUpdates(contextId)).isEqualTo(1));
139+
140+
// put another item into queue
141+
given()
142+
.post(new URI(wireMockServer.baseUrl() + "/queue/" + queueId + "/" + itemId2))
143+
.then()
144+
.statusCode(HttpStatus.SC_OK);
145+
awaitAndAssert(() -> Assertions.assertThat(contextManager.numUpdates(contextId)).isEqualTo(2));
146+
147+
// get item1 from queue without ack
148+
given()
149+
.get(new URI(wireMockServer.baseUrl() + "/queue/" + queueId))
150+
.then()
151+
.statusCode(HttpStatus.SC_OK)
152+
.body("item", equalTo(itemId1));
153+
awaitAndAssert(() -> Assertions.assertThat(contextManager.numUpdates(contextId)).isEqualTo(2));
154+
155+
// ack item 1
156+
given()
157+
.post(new URI(wireMockServer.baseUrl() + "/queue/" + queueId + "/ack"))
158+
.then()
159+
.statusCode(HttpStatus.SC_OK);
160+
awaitAndAssert(() -> Assertions.assertThat(contextManager.numUpdates(contextId)).isEqualTo(3));
161+
162+
// get item2 from queue without ack
163+
given()
164+
.get(new URI(wireMockServer.baseUrl() + "/queue/" + queueId))
165+
.then()
166+
.statusCode(HttpStatus.SC_OK)
167+
.body("item", equalTo(itemId2));
168+
awaitAndAssert(() -> Assertions.assertThat(contextManager.numUpdates(contextId)).isEqualTo(3));
169+
170+
// ack item 2
171+
given()
172+
.post(new URI(wireMockServer.baseUrl() + "/queue/" + queueId + "/ack"))
173+
.then()
174+
.statusCode(HttpStatus.SC_OK);
175+
awaitAndAssert(() -> Assertions.assertThat(contextManager.numUpdates(contextId)).isEqualTo(4));
176+
177+
// nothing to ack = error
178+
given()
179+
.post(new URI(wireMockServer.baseUrl() + "/queue/" + queueId + "/ack"))
180+
.then()
181+
.statusCode(HttpStatus.SC_INTERNAL_SERVER_ERROR);
182+
awaitAndAssert(() -> Assertions.assertThat(contextManager.numUpdates(contextId)).isEqualTo(4));
183+
184+
// empty queue
185+
given()
186+
.get(new URI(wireMockServer.baseUrl() + "/queue/" + queueId))
187+
.then()
188+
.statusCode(HttpStatus.SC_OK)
189+
.body("item", equalTo(noDataValue));
190+
awaitAndAssert(() -> Assertions.assertThat(contextManager.numUpdates(contextId)).isEqualTo(4));
191+
}
192+
193+
private void awaitAndAssert(ThrowingRunnable assertion) {
194+
await()
195+
.pollInterval(Duration.ofMillis(10))
196+
.atMost(Duration.ofSeconds(5)).untilAsserted(assertion);
197+
}
198+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"result": "{{state context=(join 'dynamic-process' request.pathSegments.[2] '-') property='id'}}"
3+
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
{
2+
"mappings": [
3+
{
4+
"request": {
5+
"method": "GET",
6+
"urlPattern": "/queue/[^\/]++",
7+
"customMatcher": {
8+
"name": "state-matcher",
9+
"parameters": {
10+
"hasNotContext": "queue-{{request.pathSegments.[1]}}"
11+
}
12+
}
13+
},
14+
"response": {
15+
"status": 200,
16+
"headers": {
17+
"Content-Type": "application/json"
18+
},
19+
"jsonBody": {
20+
"item": "no data"
21+
}
22+
}
23+
},
24+
{
25+
"request": {
26+
"method": "GET",
27+
"urlPattern": "/queue/[^\/]++",
28+
"customMatcher": {
29+
"name": "state-matcher",
30+
"parameters": {
31+
"hasContext": "queue-{{request.pathSegments.[1]}}",
32+
"listSizeEqualTo": "0"
33+
}
34+
}
35+
},
36+
"response": {
37+
"status": 200,
38+
"headers": {
39+
"Content-Type": "application/json"
40+
},
41+
"jsonBody": {
42+
"item": "no data"
43+
}
44+
}
45+
},
46+
{
47+
"request": {
48+
"method": "POST",
49+
"urlPattern": "/queue/[^\/]++/[^\/]++"
50+
},
51+
"response": {
52+
"status": 200
53+
},
54+
"serveEventListeners": [
55+
{
56+
"name": "recordState",
57+
"parameters": {
58+
"context": "queue-{{request.pathSegments.[1]}}",
59+
"list": {
60+
"addFirst": {
61+
"id": "{{request.pathSegments.[2]}}"
62+
}
63+
}
64+
}
65+
}
66+
]
67+
},
68+
{
69+
"request": {
70+
"method": "GET",
71+
"urlPattern": "/queue/[^\/]++",
72+
"customMatcher": {
73+
"name": "state-matcher",
74+
"parameters": {
75+
"hasContext": "queue-{{request.pathSegments.[1]}}",
76+
"listSizeMoreThan": "0"
77+
}
78+
}
79+
},
80+
"response": {
81+
"status": 200,
82+
"headers": {
83+
"Content-Type": "application/json"
84+
},
85+
"jsonBody": {
86+
"item": "{{state context=(join 'queue' request.pathSegments.[1] '-') list='[-1].id'}}"
87+
}
88+
}
89+
},
90+
{
91+
"request": {
92+
"method": "POST",
93+
"urlPattern": "/queue/[^\/]++/ack",
94+
"customMatcher": {
95+
"name": "state-matcher",
96+
"parameters": {
97+
"hasNotContext": "queue-{{request.pathSegments.[1]}}"
98+
}
99+
}
100+
},
101+
"response": {
102+
"status": 500
103+
}
104+
},
105+
{
106+
"request": {
107+
"method": "POST",
108+
"urlPattern": "/queue/[^\/]++/ack",
109+
"customMatcher": {
110+
"name": "state-matcher",
111+
"parameters": {
112+
"hasContext": "queue-{{request.pathSegments.[1]}}",
113+
"listSizeEqualTo": "0"
114+
}
115+
}
116+
},
117+
"response": {
118+
"status": 500
119+
}
120+
},
121+
{
122+
"request": {
123+
"method": "POST",
124+
"urlPattern": "/queue/[^\/]++/ack",
125+
"customMatcher": {
126+
"name": "state-matcher",
127+
"parameters": {
128+
"hasContext": "queue-{{request.pathSegments.[1]}}",
129+
"listSizeMoreThan": "0"
130+
}
131+
}
132+
},
133+
"response": {
134+
"status": 200
135+
},
136+
"serveEventListeners": [
137+
{
138+
"name": "deleteState",
139+
"parameters": {
140+
"context": "queue-{{request.pathSegments.[1]}}",
141+
"list": {
142+
"deleteLast": true
143+
}
144+
}
145+
}
146+
]
147+
}
148+
]
149+
}

0 commit comments

Comments
 (0)