Skip to content

Commit b0df31b

Browse files
committed
Make RedirectTest more robust
1 parent 356cfac commit b0df31b

File tree

2 files changed

+155
-116
lines changed

2 files changed

+155
-116
lines changed

integration-tests/client-server/src/main/java/io/quarkiverse/cxf/it/redirect/retransmitcache/RetransmitCacheServiceImpl.java

Lines changed: 43 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.nio.file.Path;
88
import java.util.Properties;
99
import java.util.concurrent.Future;
10+
import java.util.concurrent.atomic.AtomicReference;
1011
import java.util.stream.Stream;
1112

1213
import jakarta.jws.WebService;
@@ -53,57 +54,58 @@ public static String toString(final Properties props) {
5354
}
5455

5556
public static Properties listTempFiles(int expectedFileCount, String retransmitCacheDir) {
56-
final String prefix = "qcxf-TempStore-" + ProcessHandle.current().pid() + "-";
57+
final int timeout = 3000;
58+
final long deadline = System.currentTimeMillis() + timeout;
5759
final Properties props = new Properties();
5860
final Path dir = Path.of(retransmitCacheDir);
59-
Log.infof("Listing %s/%s", expectedFileCount, prefix);
61+
Log.infof("Expecting %d files in %s", expectedFileCount, retransmitCacheDir);
6062
if (expectedFileCount == 0) {
6163
sleep(500);
6264
}
63-
try {
64-
while (!Files.isDirectory(dir) && Files.list(dir).count() != expectedFileCount) {
65-
sleep(50);
66-
}
67-
} catch (IOException e) {
68-
throw new RuntimeException(e);
69-
}
70-
71-
if (Files.isDirectory(dir)) {
72-
try (Stream<Path> dirFiles = Files.list(dir)) {
73-
dirFiles
74-
.filter(p -> {
75-
String fn = p.getFileName().toString();
76-
77-
return fn.startsWith(prefix) // io.quarkiverse.cxf.vertx.http.client.TempStore
78-
|| // org.apache.cxf.io.CachedOutputStream.createFileOutputStream()
79-
(fn.startsWith("cos") && fn.endsWith("tmp"));
80-
81-
})
82-
.forEach(path -> {
83-
Log.infof("Found temp file %s", path);
84-
String content;
85-
86-
/* We have to wait a bit till the event loop finishes writing to the file */
87-
while (true) {
88-
try {
89-
content = Files.readString(path, StandardCharsets.UTF_8);
90-
} catch (IOException e) {
91-
throw new RuntimeException("Could not read " + path, e);
92-
}
93-
if (content.endsWith("</payload></ns2:retransmitCache></soap:Body></soap:Envelope>")) {
94-
break;
65+
final AtomicReference<Exception> lastException = new AtomicReference<>();
66+
do {
67+
if (Files.isDirectory(dir)) {
68+
try (Stream<Path> dirFiles = Files.list(dir)) {
69+
dirFiles
70+
.filter(RetransmitCacheServiceImpl::isRetransmitFile)
71+
.forEach(path -> {
72+
Log.infof("Found temp file %s", path);
73+
String content;
74+
75+
/* We have to wait a bit till the event loop finishes writing to the file */
76+
while (true) {
77+
try {
78+
content = Files.readString(path, StandardCharsets.UTF_8);
79+
if (content.endsWith("</payload></ns2:retransmitCache></soap:Body></soap:Envelope>")) {
80+
break;
81+
}
82+
} catch (IOException e) {
83+
lastException.set(e);
84+
}
85+
sleep(50);
9586
}
96-
sleep(50);
97-
}
98-
props.setProperty(path.toString(), content);
99-
});
100-
} catch (IOException e) {
101-
throw new RuntimeException("Could not list " + expectedFileCount, e);
87+
props.setProperty(path.toString(), content);
88+
});
89+
} catch (IOException e) {
90+
lastException.set(e);
91+
}
10292
}
103-
}
93+
if (System.currentTimeMillis() > deadline) {
94+
throw new IllegalStateException("" + expectedFileCount + " expected files in " + retransmitCacheDir
95+
+ " did not appear within " + timeout + " ms; found: " + props.keySet(), lastException.get());
96+
}
97+
} while (props.size() < expectedFileCount);
98+
10499
return props;
105100
}
106101

102+
public static boolean isRetransmitFile(Path p) {
103+
final String fn = p.getFileName().toString();
104+
return fn.startsWith("qcxf-TempStore-") // io.quarkiverse.cxf.vertx.http.client.TempStore
105+
|| // org.apache.cxf.io.CachedOutputStream.createFileOutputStream()
106+
(fn.startsWith("cos") && fn.endsWith("tmp"));
107+
}
108+
107109
private static void sleep(long delay) {
108110
try {
109111
Thread.sleep(delay);

integration-tests/client-server/src/test/java/io/quarkiverse/cxf/it/redirect/RedirectTest.java

Lines changed: 112 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,18 @@
1010

1111
import org.assertj.core.api.Assertions;
1212
import org.assertj.core.api.Assumptions;
13+
import org.assertj.core.api.Condition;
1314
import org.hamcrest.CoreMatchers;
1415
import org.hamcrest.Matchers;
1516
import org.jboss.logging.Logger;
1617
import org.junit.jupiter.api.BeforeEach;
18+
import org.junit.jupiter.api.Test;
1719
import org.junit.jupiter.params.ParameterizedTest;
1820
import org.junit.jupiter.params.provider.ValueSource;
1921

2022
import io.quarkiverse.cxf.HTTPConduitImpl;
2123
import io.quarkiverse.cxf.it.large.slow.LargeSlowServiceImpl;
24+
import io.quarkiverse.cxf.it.redirect.retransmitcache.RetransmitCacheServiceImpl;
2225
import io.quarkus.runtime.configuration.MemorySizeConverter;
2326
import io.quarkus.test.common.QuarkusTestResource;
2427
import io.quarkus.test.junit.QuarkusTest;
@@ -188,99 +191,132 @@ static ValidatableResponse getResponse(String endpoint, int sizeBytes) {
188191
.then();
189192
}
190193

191-
@ParameterizedTest
192-
@ValueSource(strings = { //
193-
"retransmitCacheSync", //
194-
"retransmitCacheAsyncBlocking" //
195-
})
196-
void retransmitCache(String endpoint) throws IOException {
194+
/*
195+
* 1k is smaller than 500K we set in quarkus.cxf.retransmit-cache.threshold
196+
* Hence the file should not be cached on disk
197+
*/
198+
@Test
199+
void retransmitCacheSync1k() throws IOException {
200+
retransmitCache("retransmitCacheSync", "1k", 0);
201+
}
202+
203+
@Test
204+
void retransmitCacheAsyncBlocking1k() throws IOException {
205+
retransmitCache("retransmitCacheAsyncBlocking", "1k", 0);
206+
}
207+
208+
/*
209+
* 9M is greater than the 500K we set in quarkus.cxf.retransmit-cache.threshold
210+
* Hence the file should not be cached on disk
211+
*/
212+
@Test
213+
void retransmitCacheSync9m() throws IOException {
214+
retransmitCache("retransmitCacheSync", "9m", 1);
215+
}
216+
217+
@Test
218+
void retransmitCacheAsyncBlocking9m() throws IOException {
219+
retransmitCache("retransmitCacheAsyncBlocking", "9m", 1);
220+
}
221+
222+
/*
223+
* Let server return 500
224+
*/
225+
@Test
226+
void retransmitCacheSync500() throws IOException {
227+
retransmitCache500("retransmitCacheSync");
228+
}
197229

230+
@Test
231+
void retransmitCacheAsyncBlocking500() throws IOException {
232+
retransmitCache500("retransmitCacheAsyncBlocking");
233+
}
234+
235+
private static void retransmitCache500(String endpoint) throws IOException {
198236
if (endpoint.contains("Async")) {
199237
/* URLConnectionHTTPConduitFactory does not support async */
200238
Assumptions.assumeThat(HTTPConduitImpl.findDefaultHTTPConduitImpl())
201239
.isNotEqualTo(HTTPConduitImpl.URLConnectionHTTPConduitFactory);
202240
}
203241

204242
final MemorySizeConverter converter = new MemorySizeConverter();
205-
{
206-
/*
207-
* 1k is smaller than 500K we set in quarkus.cxf.retransmit-cache.threshold
208-
* Hence the file should not be cached on disk
209-
*/
210-
final int payloadLen = (int) converter.convert("1K").asLongValue();
211-
final Properties props = retransmitCache(payloadLen, 0, endpoint);
212-
Assertions.assertThat(props.size()).isEqualTo(1);
213-
}
214243

215-
{
216-
/*
217-
* 9M is greater than the 500K we set in quarkus.cxf.retransmit-cache.threshold
218-
* Hence the file should not be cached on disk
219-
*/
220-
final int payloadLen = (int) converter.convert("9M").asLongValue();
221-
final Properties props = retransmitCache(payloadLen, 1, endpoint);
222-
Assertions.assertThat(props.size()).isEqualTo(2);
223-
224-
for (Entry<Object, Object> en : props.entrySet()) {
225-
String path = (String) en.getKey();
226-
if (path.contains("qcxf-TempStore-")) {
227-
Assertions.assertThat(Path.of(path)).doesNotExist();
228-
Assertions.assertThat((String) en.getValue())
229-
.startsWith("<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
230-
+ "<soap:Body><ns2:retransmitCache xmlns:ns2=\"https://quarkiverse.github.io/quarkiverse-docs/quarkus-cxf/test\">"
231-
+ "<expectedFileCount>");
232-
Assertions.assertThat((String) en.getValue())
233-
.endsWith("</payload></ns2:retransmitCache></soap:Body></soap:Envelope>");
234-
Assertions.assertThat((String) en.getValue())
235-
.contains("<payload>" + LargeSlowServiceImpl.largeString(payloadLen) + "</payload>");
236-
}
244+
final int payloadLen = (int) converter.convert("501K").asLongValue();
245+
final String reqId = UUID.randomUUID().toString();
246+
RestAssured.given()
247+
.header(RedirectRest.EXPECTED_FILE_COUNT_HEADER, "1")
248+
.header(RedirectRest.REQUEST_ID_HEADER, reqId)
249+
.header(RedirectRest.STATUS_CODE_HEADER, "500")
250+
.body(LargeSlowServiceImpl.largeString(payloadLen))
251+
.post("/RedirectRest/" + endpoint)
252+
.then()
253+
.statusCode(500);
254+
255+
final String propString = RestAssured.given()
256+
.get("/RedirectRest/retransmitCache-tempFiles/" + reqId)
257+
.then()
258+
.statusCode(200)
259+
.extract().body().asString();
260+
261+
Properties props = new Properties();
262+
props.load(new StringReader(propString));
263+
264+
Assertions.assertThat(props.size()).isEqualTo(1);
265+
for (Entry<Object, Object> en : props.entrySet()) {
266+
final String path = (String) en.getKey();
267+
final Path p = Path.of(path);
268+
if (path.contains("qcxf-TempStore-")) {
269+
Assertions.assertThat(p).doesNotExist();
237270
}
271+
Assertions.assertThat(p).satisfies(new Condition<Path>(RetransmitCacheServiceImpl::isRetransmitFile,
272+
"a retransmit file matching 'qcxf-TempStore-*' or 'cos*tmp'", "fairy"));
273+
assertContent((String) en.getValue(), payloadLen);
274+
}
275+
276+
}
277+
278+
private static void retransmitCache(String endpoint, String payloadSize, int expectedFileCount) throws IOException {
238279

280+
if (endpoint.contains("Async")) {
281+
/* URLConnectionHTTPConduitFactory does not support async */
282+
Assumptions.assumeThat(HTTPConduitImpl.findDefaultHTTPConduitImpl())
283+
.isNotEqualTo(HTTPConduitImpl.URLConnectionHTTPConduitFactory);
239284
}
240-
{
241-
/*
242-
* Let server return 500
243-
*/
244-
final int payloadLen = (int) converter.convert("501K").asLongValue();
245-
final String reqId = UUID.randomUUID().toString();
246-
RestAssured.given()
247-
.header(RedirectRest.EXPECTED_FILE_COUNT_HEADER, "1")
248-
.header(RedirectRest.REQUEST_ID_HEADER, reqId)
249-
.header(RedirectRest.STATUS_CODE_HEADER, "500")
250-
.body(LargeSlowServiceImpl.largeString(payloadLen))
251-
.post("/RedirectRest/" + endpoint)
252-
.then()
253-
.statusCode(500);
254285

255-
final String propString = RestAssured.given()
256-
.get("/RedirectRest/retransmitCache-tempFiles/" + reqId)
257-
.then()
258-
.statusCode(200)
259-
.extract().body().asString();
260-
261-
Properties props = new Properties();
262-
props.load(new StringReader(propString));
263-
264-
Assertions.assertThat(props.size()).isEqualTo(1);
265-
for (Entry<Object, Object> en : props.entrySet()) {
266-
String path = (String) en.getKey();
267-
if (path.contains("qcxf-TempStore-")) {
268-
Assertions.assertThat(Path.of(path)).doesNotExist();
269-
Assertions.assertThat((String) en.getValue())
270-
.startsWith("<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
271-
+ "<soap:Body><ns2:retransmitCache xmlns:ns2=\"https://quarkiverse.github.io/quarkiverse-docs/quarkus-cxf/test\">"
272-
+ "<expectedFileCount>");
273-
Assertions.assertThat((String) en.getValue())
274-
.endsWith("</payload></ns2:retransmitCache></soap:Body></soap:Envelope>");
275-
Assertions.assertThat((String) en.getValue())
276-
.contains("<payload>" + LargeSlowServiceImpl.largeString(payloadLen) + "</payload>");
286+
final MemorySizeConverter converter = new MemorySizeConverter();
287+
{
288+
final int payloadLen = (int) converter.convert(payloadSize).asLongValue();
289+
final Properties props = retransmitCache(payloadLen, 0, endpoint);
290+
Assertions.assertThat(props.size()).isEqualTo(expectedFileCount);
291+
292+
if (expectedFileCount >= 1) {
293+
for (Entry<Object, Object> en : props.entrySet()) {
294+
final String path = (String) en.getKey();
295+
Path p = Path.of(path);
296+
if (path.contains("qcxf-TempStore-")) {
297+
Assertions.assertThat(p).doesNotExist();
298+
}
299+
Assertions.assertThat(p).satisfies(new Condition<Path>(RetransmitCacheServiceImpl::isRetransmitFile,
300+
"a retransmit file matching 'qcxf-TempStore-*' or 'cos*tmp'", "fairy"));
301+
assertContent((String) en.getValue(), payloadLen);
277302
}
278303
}
279-
280304
}
281305
}
282306

283-
private Properties retransmitCache(final int payloadLen, int expectedFileCount, String syncAsync) throws IOException {
307+
private static void assertContent(String content, int payloadLen) {
308+
Assertions.assertThat(content)
309+
.startsWith("<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">"
310+
+ "<soap:Body><ns2:retransmitCache xmlns:ns2=\"https://quarkiverse.github.io/quarkiverse-docs/quarkus-cxf/test\">"
311+
+ "<expectedFileCount>");
312+
Assertions.assertThat(content)
313+
.endsWith("</payload></ns2:retransmitCache></soap:Body></soap:Envelope>");
314+
Assertions.assertThat(content)
315+
.contains("<payload>" + LargeSlowServiceImpl.largeString(payloadLen) + "</payload>");
316+
}
317+
318+
private static Properties retransmitCache(final int payloadLen, int expectedFileCount, String syncAsync)
319+
throws IOException {
284320
String body = RestAssured.given()
285321
.header(RedirectRest.EXPECTED_FILE_COUNT_HEADER, String.valueOf(expectedFileCount))
286322
.body(LargeSlowServiceImpl.largeString(payloadLen))
@@ -292,6 +328,7 @@ private Properties retransmitCache(final int payloadLen, int expectedFileCount,
292328
final Properties props = new Properties();
293329
props.load(new StringReader(body));
294330
Assertions.assertThat(props.get("payload.length")).isEqualTo(String.valueOf(payloadLen));
331+
props.remove("payload.length");
295332
return props;
296333
}
297334

0 commit comments

Comments
 (0)