Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add test for check SSE reactive empty response data #1517

Merged
merged 1 commit into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package io.quarkus.ts.http.advanced.reactive;

import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.sse.OutboundSseEvent;
import jakarta.ws.rs.sse.Sse;
import jakarta.ws.rs.sse.SseEventSink;
import jakarta.ws.rs.sse.SseEventSource;

import org.eclipse.microprofile.config.ConfigProvider;

@Path("sse")
public class SseEventUpdateResource {
public static final String DATA_VALUE = "random data value";

@Context
michalvavrik marked this conversation as resolved.
Show resolved Hide resolved
Sse sse;

@GET
@Path("client-update")
@Produces(MediaType.TEXT_PLAIN)
public Response clientUpdate() throws InterruptedException {
String host = ConfigProvider.getConfig().getValue("quarkus.http.host", String.class);
int port = ConfigProvider.getConfig().getValue("quarkus.http.port", Integer.class);
List<String> receivedData = new CopyOnWriteArrayList<>();

WebTarget target = ClientBuilder.newClient().target("http://" + host + ":" + port + "/api/sse/server-update");
try (SseEventSource eventSource = SseEventSource.target(target).build()) {
eventSource.register(ev -> {
String event = "event: name=" + ev.getName() + " data={" + ev.readData() + "} and is empty: " + ev.isEmpty()
+ "\n";
receivedData.add(event);
}, thr -> {
String event = "Error: " + thr.getMessage() + "\n" + Arrays.toString(thr.getStackTrace());
receivedData.add(event);
});

CountDownLatch latch = new CountDownLatch(2);
eventSource.open();
latch.await(1, TimeUnit.SECONDS);
}
return Response.ok(String.join("\n", receivedData)).build();
}

@GET
@Path("server-update")
@Produces(MediaType.SERVER_SENT_EVENTS)
public void updates(@Context SseEventSink eventSink) {
eventSink.send(createEvent("NON EMPTY", DATA_VALUE));
eventSink.send(createEvent("EMPTY", ""));
}

private OutboundSseEvent createEvent(String name, String data) {
return sse.newEventBuilder()
.name(name)
.data(data)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ quarkus.keycloak.policy-enforcer.paths.client.path=/api/client/*
quarkus.keycloak.policy-enforcer.paths.client.enforcement-mode=DISABLED
quarkus.keycloak.policy-enforcer.paths.intercepted.path=/api/intercepted*
quarkus.keycloak.policy-enforcer.paths.intercepted.enforcement-mode=DISABLED
quarkus.keycloak.policy-enforcer.paths.sse.path=/api/sse/*
quarkus.keycloak.policy-enforcer.paths.sse.enforcement-mode=DISABLED
quarkus.oidc.client-id=test-application-client
quarkus.oidc.credentials.secret=test-application-client-secret
# tolerate 1 minute of clock skew between the Keycloak server and the application
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import static io.quarkus.ts.http.advanced.reactive.MultipleResponseSerializersResource.MULTIPLE_RESPONSE_SERIALIZERS_PATH;
import static io.quarkus.ts.http.advanced.reactive.NinetyNineBottlesOfBeerResource.QUARKUS_PLATFORM_VERSION_LESS_THAN_2_8_3;
import static io.quarkus.ts.http.advanced.reactive.NinetyNineBottlesOfBeerResource.QUARKUS_PLATFORM_VERSION_LESS_THAN_2_8_3_VAL;
import static io.quarkus.ts.http.advanced.reactive.SseEventUpdateResource.DATA_VALUE;
import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON;
import static jakarta.ws.rs.core.MediaType.APPLICATION_OCTET_STREAM;
import static jakarta.ws.rs.core.MediaType.APPLICATION_XML;
Expand Down Expand Up @@ -71,6 +72,7 @@
import io.quarkus.example.StreamingGrpc;
import io.quarkus.test.bootstrap.Protocol;
import io.quarkus.test.bootstrap.RestService;
import io.quarkus.test.scenarios.annotations.DisabledOnNative;
import io.quarkus.test.scenarios.annotations.EnabledOnQuarkusVersion;
import io.quarkus.ts.http.advanced.reactive.clients.HttpVersionClientService;
import io.quarkus.ts.http.advanced.reactive.clients.HttpVersionClientServiceAsync;
Expand Down Expand Up @@ -445,6 +447,17 @@ public void interceptedTest() {
Assertions.assertFalse(response.contains("Client"), "Client interceptor should not be invoked");
}

@DisplayName("SSE check for event responses values containing empty data")
@Test
@DisabledOnNative(reason = "https://github.com/quarkusio/quarkus/issues/36986")
void testSseResponseForEmptyData() {
getApp().given()
.get(ROOT_PATH + "/sse/client-update")
.then().statusCode(SC_OK)
.body(containsString(String.format("event: name=NON EMPTY data={%s} and is empty: false", DATA_VALUE)),
containsString("event: name=EMPTY data={} and is empty: true"));
}

private void assertAcceptedMediaTypeEqualsResponseBody(String acceptedMediaType) {
getApp()
.given()
Expand Down