Skip to content

Commit

Permalink
Fix and enable DEV UI gRPC tests
Browse files Browse the repository at this point in the history
  • Loading branch information
michalvavrik authored and jedla97 committed Jun 7, 2024
1 parent e054a26 commit 04d03bb
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 279 deletions.
5 changes: 5 additions & 0 deletions http/http-advanced-reactive/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -98,5 +98,10 @@
<groupId>com.aayushatharva.brotli4j</groupId>
<artifactId>brotli4j</artifactId>
</dependency>
<dependency>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
@@ -1,89 +1,58 @@
package io.quarkus.ts.http.advanced.reactive;

import static org.awaitility.Awaitility.await;
import static io.quarkus.test.utils.AwaitilityUtils.untilAsserted;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.function.Consumer;

import org.apache.http.HttpStatus;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.microsoft.playwright.Browser;
import com.microsoft.playwright.Page;
import com.microsoft.playwright.Playwright;

import io.quarkus.example.GreeterGrpc;
import io.quarkus.example.HelloReply;
import io.quarkus.example.HelloRequest;
import io.quarkus.test.bootstrap.GrpcService;
import io.quarkus.test.bootstrap.Service;
import io.quarkus.test.logging.Log;
import io.quarkus.test.bootstrap.Protocol;
import io.quarkus.test.scenarios.QuarkusScenario;
import io.quarkus.test.services.DevModeQuarkusApplication;
import io.quarkus.ts.http.advanced.reactive.utils.GrpcWebSocketListener;
import io.restassured.response.Response;
import io.quarkus.test.services.URILike;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.WebSocket;

// TODO mvavrik: enable test and adjust it to new DEV UI
@Disabled("Disabled as DEV UI is work in progress currenlty")
@Tag("QUARKUS-1026")
@Tag("QUARKUS-1094")
@QuarkusScenario
public class DevModeGrpcIntegrationReactiveIT {

private static final String NAME = "QE";

private static final int UNARY_ID = 1;
private static final int SERVER_STREAM_ID = 2;
private static final int CLIENT_STREAM_ID = 3;
private static final int BIDIRECTIONAL_STREAM_ID = 4;
private static final int CLIENT_STREAM_NAMES_SUBMITTED_COUNT = 2;
private static final int SERVER_STREAM_MESSAGES_RETURNED_COUNT = 5;

private static final List<String> GRPC_SOCKET_MESSAGES = Arrays.asList(
"{\"serviceName\":\"helloworld.Greeter\",\"methodName\":\"SayHello\",\"id\":" + UNARY_ID
+ ",\"content\":\"{\\\"name\\\":\\\"Quarkus\\\"}\"}",
"{\"serviceName\":\"helloworld.Streaming\",\"methodName\":\"ServerStream\",\"id\":" + SERVER_STREAM_ID
+ ",\"content\":\"{\\\"name\\\":\\\"Five Times\\\"}\"}",
"{\"serviceName\":\"helloworld.Streaming\",\"methodName\":\"ClientStream\",\"id\":" + CLIENT_STREAM_ID
+ ",\"content\":\"{\\\"name\\\":\\\"NameOne\\\"}\"}",
"{\"serviceName\":\"helloworld.Streaming\",\"methodName\":\"ClientStream\",\"id\":" + CLIENT_STREAM_ID
+ ",\"content\":\"{\\\"name\\\":\\\"NameTwo\\\"}\"}",
"{\"id\":" + CLIENT_STREAM_ID + ",\"command\":\"DISCONNECT\"}",
"{\"serviceName\":\"helloworld.Streaming\",\"methodName\":\"BidirectionalStream\",\"id\":" + BIDIRECTIONAL_STREAM_ID
+ ",\"content\":\"{\\\"name\\\":\\\"John\\\"}\"}",
"{\"serviceName\":\"helloworld.Streaming\",\"methodName\":\"BidirectionalStream\",\"id\":" + BIDIRECTIONAL_STREAM_ID
+ ",\"content\":\"{\\\"name\\\":\\\"Max\\\"}\"}",
"{\"id\":" + BIDIRECTIONAL_STREAM_ID + ",\"command\":\"DISCONNECT\"}");
/**
* Expect streaming service and hello service definition from 'helloworld.proto'
* as well as full generated service names and communication method type (UNARY, CLIENT_STREAMING, ...).
*/
private static final String[] GRPC_SERVICE_VIEW_EXPECTED_CONTENT = {
"UNARY", "helloworld.Greeter", "io.quarkus.ts.http.advanced.reactive.GrpcService", "SayHello", "SERVER_STREAMING",
"io.quarkus.ts.http.advanced.reactive.GrpcStreamingService", "BIDI_STREAMING", "CLIENT_STREAMING", "ServerStream",
"BidirectionalStream", "ClientStream"
};

@DevModeQuarkusApplication(grpc = true)
static final GrpcService app = (GrpcService) new GrpcService()
static final GrpcService app = (GrpcService) new GrpcService() {
@Override
public URILike getGrpcHost() {
// TODO: make app.grpcChannel() support gRPC on same HTTP server
return super.getGrpcHost().withPort(app.getURI().getPort());
}
}
.withProperty("quarkus.oidc.enabled", "false")
.withProperty("quarkus.keycloak.policy-enforcer.enable", "false")
.withProperty("quarkus.keycloak.devservices.enabled", "false")
// Init webSocketListener and webSocket
.onPostStart(DevModeGrpcIntegrationReactiveIT::initDevUiGrpcWsClient);

static WebSocket webSocket;
static GrpcWebSocketListener webSocketListener;
.withProperty("quarkus.keycloak.devservices.enabled", "false");

@Test
public void testGrpcAsClient() throws ExecutionException, InterruptedException {
Expand All @@ -99,98 +68,33 @@ public void testGrpcViaRest() {
}

@Test
public void testGrpcDevUISocket() throws JsonProcessingException {
for (String message : GRPC_SOCKET_MESSAGES) {
webSocket.send(message);
}

await().atMost(60, TimeUnit.SECONDS).until(this::isGrpcStreamsCompleted);
checkGrpcDevUiOutput();
public void testGrpcDevUISocket() {
// TODO: reimplement as part of the https://github.com/quarkus-qe/quarkus-test-suite/issues/1832
}

@Test
public void testGrpcDevUIServicesView() {
List<Pattern> patterns = Arrays.asList(
Pattern.compile("helloworld\\.Streaming(?=.*SERVER_STREAMING ServerStream)" +
"(?=.*CLIENT_STREAMING ClientStream)(?=.*BIDI_STREAMING BidirectionalStream)"),
Pattern.compile("helloworld\\.Greeter(?=.*UNARY SayHello)"));
Response response = app.given().when().get("/q/dev/io.quarkus.quarkus-grpc/services")
.then().statusCode(HttpStatus.SC_OK).extract().response();
Document doc = Jsoup.parse(response.getBody().asString());
Element table = doc.select("table").get(0);

assertTrue(patterns.stream().allMatch(pattern -> pattern.matcher(table.text()).find()),
"DevUI gRPC services view s incomplete");
}

private void checkGrpcDevUiOutput() throws JsonProcessingException {
Map<Integer, List<String>> grpcOutputMap = webSocketListener.getServiceOutputMessagesMap();

List<String> messages;
for (int streamId : grpcOutputMap.keySet()) {
switch (streamId) {
case (UNARY_ID):
Log.info("Testing gRPC Unary service...");
messages = getMessagesByStreamId(streamId);
assertTrue(messages.contains("Hello Quarkus"), "Unary service FAILED");
break;
case (SERVER_STREAM_ID):
Log.info("Testing gRPC Server stream service...");
messages = getMessagesByStreamId(streamId);
int actualMessagesReturnedCount = Collections.frequency(messages, "Hello Five Times");
assertEquals(SERVER_STREAM_MESSAGES_RETURNED_COUNT, actualMessagesReturnedCount,
"Server Stream service FAILED");
break;
case (CLIENT_STREAM_ID):
Log.info("Testing gRPC Client stream service...");
messages = getMessagesByStreamId(streamId);
assertTrue(messages.contains("Total names submitted: " + CLIENT_STREAM_NAMES_SUBMITTED_COUNT),
"Client Stream service FAILED");
break;
case (BIDIRECTIONAL_STREAM_ID):
Log.info("Testing gRPC Bidirectional stream service...");
messages = getMessagesByStreamId(streamId);
assertTrue(messages.contains("Hello: John;"), "Bidirectional Stream service FAILED");
assertTrue(messages.contains("Hello: John;Max;"), "Bidirectional Stream service FAILED");
break;
default: // Do nothing
assertOnGrpcServicePage(page -> {
var grpcSvcView = page.waitForSelector("#page > qwc-grpc-services > vaadin-grid").innerText();
for (String text : GRPC_SERVICE_VIEW_EXPECTED_CONTENT) {
assertTrue(grpcSvcView.contains(text), "DevUI gRPC services view is incomplete: " + grpcSvcView);
}
}
});
}

private List<String> getMessagesByStreamId(int id) throws JsonProcessingException {
List<String> messages = new ArrayList<>();
ObjectMapper objectMapper = new ObjectMapper();
for (String payload : webSocketListener.getServiceOutputMessagesMap().get(id)) {
ObjectNode node = objectMapper.readValue(payload, ObjectNode.class);
JsonNode body;
if ((body = node.get("body")) != null) {
node = objectMapper.readValue(body.textValue(), ObjectNode.class);
}
JsonNode message;
if ((message = node.get("message")) != null) {
messages.add(message.textValue());
private static void assertOnGrpcServicePage(Consumer<Page> assertion) {
try (Playwright playwright = Playwright.create()) {
try (Browser browser = playwright.chromium().launch()) {
Page page = browser.newContext().newPage();
var grpcServicesViewUrl = app
.getURI(Protocol.HTTP)
.withPath("/q/dev-ui/io.quarkus.quarkus-grpc/services")
.toString();
page.navigate(grpcServicesViewUrl);

untilAsserted(() -> assertion.accept(page));
}
}
return messages;
}

private boolean isGrpcStreamsCompleted() {
final int expectedCompletedStreams = 4;
long completedStreams = webSocketListener.getServiceOutputMessagesMap()
.values().stream()
.filter(list -> list.get(list.size() - 1).contains("COMPLETED"))
.count();
return completedStreams == expectedCompletedStreams;
}

private static void initDevUiGrpcWsClient(Service service) {
webSocketListener = new GrpcWebSocketListener();
OkHttpClient client = new OkHttpClient();

Request request = new Request.Builder()
.url(app.getURI().withScheme("ws").withPath("/q/dev/io.quarkus.quarkus-grpc/grpc-test").toString())
.build();
webSocket = client.newWebSocket(request, webSocketListener);
}
}
4 changes: 2 additions & 2 deletions http/http-advanced/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<groupId>com.microsoft.playwright</groupId>
<artifactId>playwright</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
Loading

0 comments on commit 04d03bb

Please sign in to comment.