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 coverage for issue 36402 #1508

Merged
merged 3 commits into from
Nov 8, 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,77 @@
package io.quarkus.ts.http.advanced;

import java.util.Arrays;
import java.util.concurrent.locks.LockSupport;

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.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 SseResource {
@Context
Sse sse;

@GET
@Path("/client")
public String sseClient() {
try {
return consumeSse();
}
// in case that https://github.com/quarkusio/quarkus/issues/36402 throws java.lang.RuntimeException: java.lang.ClassNotFoundException:
// catch it and return the error message
catch (RuntimeException exception) {
return exception.getMessage();
}
}

private String consumeSse() {
StringBuilder response = new StringBuilder();
int port = ConfigProvider.getConfig().getValue("quarkus.http.port", Integer.class);

/*
* Client connects to itself (to server endpoint running on same app),
* because for https://github.com/quarkusio/quarkus/issues/36402 to reproduce client must run on native app.
* Which cannot be done in test code itself.
* This method acts just as a client
*/
WebTarget target = ClientBuilder.newClient().target("http://localhost:" + port + "/api/sse/server");
SseEventSource updateSource = SseEventSource.target(target).build();
updateSource.register(ev -> {
response.append("event: ").append(ev.getName()).append(" ").append(ev.readData());
response.append("\n");

}, thr -> {
response.append("Error in SSE, message: ").append(thr.getMessage()).append("\n");
response.append(Arrays.toString(thr.getStackTrace()));
});
updateSource.open();

LockSupport.parkNanos(1_000_000_000L);
return response.toString();
}

@GET
@Path("/server")
@Produces(MediaType.SERVER_SENT_EVENTS)
public void sendSseEvents(@Context SseEventSink eventSink) {
eventSink.send(createEvent("test234", "test"));
}

private OutboundSseEvent createEvent(String name, String data) {
return sse.newEventBuilder()
.name(name)
.data(data)
.build();
}
}
2 changes: 2 additions & 0 deletions http/http-advanced/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ quarkus.keycloak.policy-enforcer.paths.version.enforcement-mode=DISABLED
# Application endpoints
quarkus.keycloak.policy-enforcer.paths.hello.path=/api/hello/*
quarkus.keycloak.policy-enforcer.paths.hello.enforcement-mode=DISABLED
quarkus.keycloak.policy-enforcer.paths.sse.path=/api/sse/*
quarkus.keycloak.policy-enforcer.paths.sse.enforcement-mode=DISABLED
quarkus.keycloak.policy-enforcer.paths.details.path=/api/details/*
quarkus.keycloak.policy-enforcer.paths.details.enforcement-mode=DISABLED
quarkus.keycloak.policy-enforcer.paths.grpc.path=/api/grpc/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import static org.hamcrest.Matchers.in;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

import java.net.URISyntaxException;
Expand Down Expand Up @@ -60,6 +62,7 @@ public abstract class BaseHttpAdvancedIT {
private static final String PASSWORD = "password";
private static final String KEY_STORE_PATH = "META-INF/resources/server.keystore";
private static final int ASSERT_TIMEOUT_SECONDS = 10;
private static final String SSE_ERROR_MESSAGE = "java.lang.ClassNotFoundException: Provider for jakarta.ws.rs.sse.SseEventSource.Builder cannot be found";

protected abstract RestService getApp();

Expand Down Expand Up @@ -242,6 +245,16 @@ public void keepRequestScopeValuesAfterEventPropagation() {
"Unexpected requestScope custom context value");
}

@Test
@Tag("https://github.com/quarkusio/quarkus/issues/36402")
public void sseConnectionTest() {
String response = getApp().given().get("/api/sse/client").thenReturn().body().asString();

assertFalse(response.contains(SSE_ERROR_MESSAGE),
"SSE failed, https://github.com/quarkusio/quarkus/issues/36402 not fixed");
assertTrue(response.contains("event: test234 test"), "SSE failed, unknown bug. Response: " + response);
}

protected Protocol getProtocol() {
return Protocol.HTTPS;
}
Expand Down