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

WebSocket client and testing update #5831

Merged
merged 3 commits into from
Jan 17, 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
7 changes: 6 additions & 1 deletion bom/pom.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright (c) 2017, 2022 Oracle and/or its affiliates.
Copyright (c) 2017, 2023 Oracle and/or its affiliates.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -1360,6 +1360,11 @@
<artifactId>helidon-nima-websocket-webserver</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.nima.websocket</groupId>
<artifactId>helidon-nima-websocket-client</artifactId>
<version>${helidon.version}</version>
</dependency>
<dependency>
<groupId>io.helidon.nima.testing.junit5</groupId>
<artifactId>helidon-nima-testing-junit5-webserver</artifactId>
Expand Down
46 changes: 46 additions & 0 deletions docs-internal/nima-testing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
Testing
----
There are two annotations that can be used to test Níma server.
`@ServerTest` is an integration test annotation, that starts server (opens ports) and provides client injection pre-configured for
the server port(s).
`@RoutingTest` is a unit test annotation, that does not start server and does not open ports, but provides direct client (with
same API as the usual network client) to test routing.

Extensions can exist that enhance the features for the module `helidon-nima-testing-junit5-webserver` to support additional
protocols. Known are listed here.

The following table lists supported types of parameters for `@SetUpRoute` annotated methods. Such methods MUST be static,
and may have any name. `@SetUpRoute` annotation has `value` with socket name (to customize setup for a different socket).

- Parameter type - supported class of a parameter
- Annotation - which annotation(s) support this parameter
- Modules - which Níma extension modules support this signature

| Parameter Type | Annotation | Modules | Notes |
|----------------------------|-------------------------------|-----------|---------------------------------------------------|
| `HttpRouting.Builder` | `@ServerTest`, `@RoutingTest` | | |
| `HttpRules` | `@ServerTest`, `@RoutingTest` | | Same as `HttpRouting.Builder`, only routing setup |
| `Router.RouterBuilder<?>` | `@ServerTest`, `@RoutingTest` | | |
| `SocketListener.Builder` | `@ServerTest` | | |
| `WebSocketRouting.Builder` | `@ServerTest`, `@RoutingTest` | websocket | |

In addition, a static method annotated with `@SetUpServer` can be defined for `@ServerTest`, that has a single parameter
of `WebServer.Builder`.

The following table lists injectable types (through constructor or method injection).

- Type - type that can be injected
- Socket? - if checked, you can use `@Socket` annotation to obtain value specific to that named socket
- Annotation - which annotation(s) support this injection
- Modules - which Níma extension modules support this injection
- Notes - additional details

| Type | Socket? | Annotation | Modules | Notes |
|--------------------|---------|----------------|-----------|-----------------------------------------------------------------------|
| `WebServer` | | `@ServerTest` | | Server instance (already started) |
| `URI` | x | `@ServerTest` | | URI pointing to a port of the webserver |
| `SocketHttpClient` | x | `@ServerTest` | | Client that allows sending of anything, to test bad request and such. |
| `Http1Client` | x | `@ServerTest` | | |
| `DirectClient` | x | `@RoutingTest` | | Implements `Http1Client` API |
| `WsClient` | x | `@ServerTest` | websocket | |
| `DirectWsClient` | x | `@RoutingTest` | websocket | Implements `WsClient` API |
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates.
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -30,7 +30,7 @@
import io.helidon.nima.webserver.http1.Http1Route;
import io.helidon.nima.websocket.WsListener;
import io.helidon.nima.websocket.WsSession;
import io.helidon.nima.websocket.webserver.WebSocketRouting;
import io.helidon.nima.websocket.webserver.WsRouting;

import io.grpc.stub.StreamObserver;

Expand Down Expand Up @@ -80,7 +80,7 @@ public static void main(String[] args) {
"StringService",
"Upper",
ProtocolsMain::grpcUpper))
.addRouting(WebSocketRouting.builder()
.addRouting(WsRouting.builder()
.endpoint("/tyrus/echo", ProtocolsMain::wsEcho))
.start();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@
package io.helidon.microprofile.tyrus;

import java.nio.ByteBuffer;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;

import io.helidon.common.buffers.BufferData;
import io.helidon.common.buffers.DataReader;
import io.helidon.nima.webserver.ConnectionContext;
import io.helidon.nima.webserver.spi.ServerConnection;
import io.helidon.nima.websocket.CloseCodes;
import io.helidon.nima.websocket.WsCloseCodes;
import io.helidon.nima.websocket.WsListener;
import io.helidon.nima.websocket.WsSession;

Expand Down Expand Up @@ -65,7 +66,7 @@ public void handle() {
listener.receive(this, buffer, true);
} catch (Exception e) {
listener.onError(this, e);
listener.onClose(this, CloseCodes.UNEXPECTED_CONDITION, e.getMessage());
listener.onClose(this, WsCloseCodes.UNEXPECTED_CONDITION, e.getMessage());
return;
}
}
Expand Down Expand Up @@ -97,10 +98,15 @@ public WsSession close(int code, String reason) {
}

@Override
public WsSession abort() {
public WsSession terminate() {
return this;
}

@Override
public Optional<String> subProtocol() {
return Optional.empty();
}

class TyrusListener implements WsListener {
private static final int MAX_RETRIES = 5;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import io.helidon.microprofile.server.RoutingPath;
import io.helidon.microprofile.tests.junit5.AddBean;
import io.helidon.microprofile.tests.junit5.HelidonTest;
import io.helidon.nima.websocket.CloseCodes;
import io.helidon.nima.websocket.WsCloseCodes;

import jakarta.enterprise.context.Dependent;
import jakarta.websocket.Endpoint;
Expand All @@ -51,7 +51,7 @@ public void testEchoProg() throws Exception {

await(ws.sendText(HELLO_WORLD, true));
assertThat(listener.awaitEcho(), is(HELLO_WORLD));
ws.sendClose(CloseCodes.NORMAL_CLOSE, "normal").get();
ws.sendClose(WsCloseCodes.NORMAL_CLOSE, "normal").get();
}

@Dependent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

import io.helidon.microprofile.tests.junit5.AddBean;
import io.helidon.microprofile.tests.junit5.HelidonTest;
import io.helidon.nima.websocket.CloseCodes;
import io.helidon.nima.websocket.WsCloseCodes;

import org.junit.jupiter.api.Test;

Expand All @@ -42,6 +42,6 @@ public void testEchoAnnot() throws Exception {

await(ws.sendText(HELLO_WORLD, true));
assertThat(listener.awaitEcho(), is(HELLO_WORLD));
ws.sendClose(CloseCodes.NORMAL_CLOSE, "normal").get();
ws.sendClose(WsCloseCodes.NORMAL_CLOSE, "normal").get();
}
}
5 changes: 3 additions & 2 deletions nima/testing/junit5/pom.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--

Copyright (c) 2022 Oracle and/or its affiliates.
Copyright (c) 2022, 2023 Oracle and/or its affiliates.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -19,7 +19,7 @@

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
Expand All @@ -37,6 +37,7 @@

<modules>
<module>webserver</module>
<module>websocket</module>
</modules>

</project>
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates.
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -23,6 +23,15 @@

import io.helidon.common.socket.PeerInfo;

record DirectPeerInfo(SocketAddress address, String host, int port, Optional<Principal> tlsPrincipal,
/**
* Peer information that can be used with {@link io.helidon.nima.testing.junit5.webserver.DirectSocket}.
*
* @param address socket address - socket address of the peer
* @param host host - for network, this is the used host of the peer
* @param port port - for network, this is the used port of the peer
* @param tlsPrincipal principal - for network obtained from SSL handshake or configuration (if used)
* @param tlsCertificates certificates - for network obtained from SSL handshake or configuration
*/
public record DirectPeerInfo(SocketAddress address, String host, int port, Optional<Principal> tlsPrincipal,
Optional<Certificate[]> tlsCertificates) implements PeerInfo {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Oracle and/or its affiliates.
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -20,7 +20,10 @@
import io.helidon.common.socket.HelidonSocket;
import io.helidon.common.socket.PeerInfo;

class DirectSocket implements HelidonSocket {
/**
* A socket not backed by any network, used for unit testing.
*/
public class DirectSocket implements HelidonSocket {
private final PeerInfo localPeer;
private final PeerInfo remotePeer;
private final boolean isSecure;
Expand All @@ -31,6 +34,18 @@ class DirectSocket implements HelidonSocket {
this.isSecure = isSecure;
}

/**
* Create a new socket with explicit peer information.
*
* @param localPeer local peer (local host and port)
* @param remotePeer remote peer (remote party host and port)
* @param isSecure whether the socket is secured (TLS)
* @return a new direct socket
*/
public static DirectSocket create(PeerInfo localPeer, PeerInfo remotePeer, boolean isSecure) {
return new DirectSocket(localPeer, remotePeer, isSecure);
}

@Override
public PeerInfo remotePeer() {
return remotePeer;
Expand Down
Loading