From 0c7e31bb3933116042c231d25433102eb868e896 Mon Sep 17 00:00:00 2001 From: Julien Lengrand-Lambert Date: Mon, 7 Jun 2021 21:20:49 +0200 Subject: [PATCH] Create repo --- .dockerignore | 1 + .gitignore | 29 +++ Dockerfile | 30 +++ Dockerfile.jlink | 25 +++ Dockerfile.native | 29 +++ README.md | 175 ++++++++++++++++++ app.yaml | 53 ++++++ helidon-quickstart-se.iml | 62 +++++++ jreleaser.yml | 23 +++ .../app/helidon-quickstart-se.jar.sha256 | 1 + out/jreleaser/checksums/checksums_sha256.txt | 1 + out/jreleaser/output.properties | 16 ++ out/jreleaser/release/CHANGELOG.md | 2 + pom.xml | 80 ++++++++ .../examples/quickstart/se/GreetService.java | 137 ++++++++++++++ .../helidon/examples/quickstart/se/Main.java | 86 +++++++++ .../examples/quickstart/se/package-info.java | 2 + .../META-INF/native-image/reflect-config.json | 1 + src/main/resources/application.yaml | 7 + src/main/resources/logging.properties | 19 ++ .../examples/quickstart/se/MainTest.java | 96 ++++++++++ 21 files changed, 875 insertions(+) create mode 100644 .dockerignore create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 Dockerfile.jlink create mode 100644 Dockerfile.native create mode 100644 README.md create mode 100644 app.yaml create mode 100644 helidon-quickstart-se.iml create mode 100644 jreleaser.yml create mode 100644 out/jreleaser/checksums/app/helidon-quickstart-se.jar.sha256 create mode 100644 out/jreleaser/checksums/checksums_sha256.txt create mode 100644 out/jreleaser/output.properties create mode 100644 out/jreleaser/release/CHANGELOG.md create mode 100644 pom.xml create mode 100644 src/main/java/io/helidon/examples/quickstart/se/GreetService.java create mode 100644 src/main/java/io/helidon/examples/quickstart/se/Main.java create mode 100644 src/main/java/io/helidon/examples/quickstart/se/package-info.java create mode 100644 src/main/resources/META-INF/native-image/reflect-config.json create mode 100644 src/main/resources/application.yaml create mode 100644 src/main/resources/logging.properties create mode 100644 src/test/java/io/helidon/examples/quickstart/se/MainTest.java diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..c8b241f --- /dev/null +++ b/.dockerignore @@ -0,0 +1 @@ +target/* \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..397690d --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +.idea +target +.classpath +.project +.settings \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..89f3f6f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,30 @@ + +# 1st stage, build the app +FROM maven:3.6-jdk-11 as build + +WORKDIR /helidon + +# Create a first layer to cache the "Maven World" in the local repository. +# Incremental docker builds will always resume after that, unless you update +# the pom +ADD pom.xml . +RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip + +# Do the Maven build! +# Incremental docker builds will resume here when you change sources +ADD src src +RUN mvn package -DskipTests + +RUN echo "done!" + +# 2nd stage, build the runtime image +FROM openjdk:11-jre-slim +WORKDIR /helidon + +# Copy the binary built in the 1st stage +COPY --from=build /helidon/target/helidon-quickstart-se.jar ./ +COPY --from=build /helidon/target/libs ./libs + +CMD ["java", "-jar", "helidon-quickstart-se.jar"] + +EXPOSE 8080 diff --git a/Dockerfile.jlink b/Dockerfile.jlink new file mode 100644 index 0000000..ad87dfc --- /dev/null +++ b/Dockerfile.jlink @@ -0,0 +1,25 @@ + +# 1st stage, build the app +FROM maven:3.6.3-jdk-11-slim as build + +WORKDIR /helidon + +# Create a first layer to cache the "Maven World" in the local repository. +# Incremental docker builds will always resume after that, unless you update +# the pom +ADD pom.xml . +RUN mvn package -Dmaven.test.skip -Declipselink.weave.skip + +# Do the Maven build to create the custom Java Runtime Image +# Incremental docker builds will resume here when you change sources +ADD src src +RUN mvn -Ddocker.build=true package -Pjlink-image -DskipTests +RUN echo "done!" + +# 2nd stage, build the final image with the JRI built in the 1st stage + +FROM debian:stretch-slim +WORKDIR /helidon +COPY --from=build /helidon/target/helidon-quickstart-se-jri ./ +ENTRYPOINT ["/bin/bash", "/helidon/bin/start"] +EXPOSE 8080 diff --git a/Dockerfile.native b/Dockerfile.native new file mode 100644 index 0000000..45b2646 --- /dev/null +++ b/Dockerfile.native @@ -0,0 +1,29 @@ + +# 1st stage, build the app +FROM helidon/jdk11-graalvm-maven:21.0.0 as build + +WORKDIR /helidon + +# Create a first layer to cache the "Maven World" in the local repository. +# Incremental docker builds will always resume after that, unless you update +# the pom +ADD pom.xml . +RUN mvn package -Pnative-image -Dnative.image.skip -Dmaven.test.skip -Declipselink.weave.skip + +# Do the Maven build! +# Incremental docker builds will resume here when you change sources +ADD src src +RUN mvn package -Pnative-image -Dnative.image.buildStatic -DskipTests + +RUN echo "done!" + +# 2nd stage, build the runtime image +FROM scratch +WORKDIR /helidon + +# Copy the binary built in the 1st stage +COPY --from=build /helidon/target/helidon-quickstart-se . + +ENTRYPOINT ["./helidon-quickstart-se"] + +EXPOSE 8080 diff --git a/README.md b/README.md new file mode 100644 index 0000000..edaf50a --- /dev/null +++ b/README.md @@ -0,0 +1,175 @@ +# Helidon Quickstart SE + +Sample Helidon SE project that includes multiple REST operations. + +## Build and run + +With JDK11+ +```bash +mvn package +java -jar target/helidon-quickstart-se.jar +``` + +## Exercise the application + +``` +curl -X GET http://localhost:8080/greet +{"message":"Hello World!"} + +curl -X GET http://localhost:8080/greet/Joe +{"message":"Hello Joe!"} + +curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Hola"}' http://localhost:8080/greet/greeting + +curl -X GET http://localhost:8080/greet/Jose +{"message":"Hola Jose!"} +``` + +## Try health and metrics + +``` +curl -s -X GET http://localhost:8080/health +{"outcome":"UP",... +. . . + +# Prometheus Format +curl -s -X GET http://localhost:8080/metrics +# TYPE base:gc_g1_young_generation_count gauge +. . . + +# JSON Format +curl -H 'Accept: application/json' -X GET http://localhost:8080/metrics +{"base":... +. . . + +``` + +## Build the Docker Image + +``` +docker build -t helidon-quickstart-se . +``` + +## Start the application with Docker + +``` +docker run --rm -p 8080:8080 helidon-quickstart-se:latest +``` + +Exercise the application as described above + +## Deploy the application to Kubernetes + +``` +kubectl cluster-info # Verify which cluster +kubectl get pods # Verify connectivity to cluster +kubectl create -f app.yaml # Deploy application +kubectl get pods # Wait for quickstart pod to be RUNNING +kubectl get service helidon-quickstart-se # Get service info +``` + +Note the PORTs. You can now exercise the application as you did before but use the second +port number (the NodePort) instead of 8080. + +After you’re done, cleanup. + +``` +kubectl delete -f app.yaml +``` + +## Build a native image with GraalVM + +GraalVM allows you to compile your programs ahead-of-time into a native + executable. See https://www.graalvm.org/docs/reference-manual/aot-compilation/ + for more information. + +You can build a native executable in 2 different ways: +* With a local installation of GraalVM +* Using Docker + +### Local build + +Download Graal VM at https://www.graalvm.org/downloads, the versions + currently supported for Helidon are `20.1.0` and above. + +``` +# Setup the environment +export GRAALVM_HOME=/path +# build the native executable +mvn package -Pnative-image +``` + +You can also put the Graal VM `bin` directory in your PATH, or pass + `-DgraalVMHome=/path` to the Maven command. + +See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-native-image + for more information. + +Start the application: + +``` +./target/helidon-quickstart-se +``` + +### Multi-stage Docker build + +Build the "native" Docker Image + +``` +docker build -t helidon-quickstart-se-native -f Dockerfile.native . +``` + +Start the application: + +``` +docker run --rm -p 8080:8080 helidon-quickstart-se-native:latest +``` + +## Build a Java Runtime Image using jlink + +You can build a custom Java Runtime Image (JRI) containing the application jars and the JDK modules +on which they depend. This image also: + +* Enables Class Data Sharing by default to reduce startup time. +* Contains a customized `start` script to simplify CDS usage and support debug and test modes. + +You can build a custom JRI in two different ways: +* Local +* Using Docker + + +### Local build + +``` +# build the JRI +mvn package -Pjlink-image +``` + +See https://github.com/oracle/helidon-build-tools/tree/master/helidon-maven-plugin#goal-jlink-image + for more information. + +Start the application: + +``` +./target/helidon-quickstart-se-jri/bin/start +``` + +### Multi-stage Docker build + +Build the JRI as a Docker Image + +``` +docker build -t helidon-quickstart-se-jri -f Dockerfile.jlink . +``` + +Start the application: + +``` +docker run --rm -p 8080:8080 helidon-quickstart-se-jri:latest +``` + +See the start script help: + +``` +docker run --rm helidon-quickstart-se-jri:latest --help +``` diff --git a/app.yaml b/app.yaml new file mode 100644 index 0000000..3249d3c --- /dev/null +++ b/app.yaml @@ -0,0 +1,53 @@ +# +# Copyright (c) 2018, 2019 Oracle and/or its affiliates. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +kind: Service +apiVersion: v1 +metadata: + name: helidon-quickstart-se + labels: + app: helidon-quickstart-se +spec: + type: NodePort + selector: + app: helidon-quickstart-se + ports: + - port: 8080 + targetPort: 8080 + name: http +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + name: helidon-quickstart-se +spec: + replicas: 1 + selector: + matchLabels: + app: helidon-quickstart-se + template: + metadata: + labels: + app: helidon-quickstart-se + version: v1 + spec: + containers: + - name: helidon-quickstart-se + image: helidon-quickstart-se + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 +--- diff --git a/helidon-quickstart-se.iml b/helidon-quickstart-se.iml new file mode 100644 index 0000000..4836172 --- /dev/null +++ b/helidon-quickstart-se.iml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/jreleaser.yml b/jreleaser.yml new file mode 100644 index 0000000..4c87930 --- /dev/null +++ b/jreleaser.yml @@ -0,0 +1,23 @@ +project: + name: helidon-quickstart-se + version: 1.0.0-SNAPSHOT + description: helidon-quickstart-se + longDescription: A simple helidon-quickstart-se quickstart + website: https://acme.com/app + authors: + - jlengrand + license: Apache-2 + java: + groupId: io.helidon.examples.quickstart.se + version: 8 + extraProperties: + inceptionYear: 2021 + +release: + github: + owner: jlengrand + +distributions: + app: + artifacts: + - path: target/helidon-quickstart-se.jar diff --git a/out/jreleaser/checksums/app/helidon-quickstart-se.jar.sha256 b/out/jreleaser/checksums/app/helidon-quickstart-se.jar.sha256 new file mode 100644 index 0000000..f4c0034 --- /dev/null +++ b/out/jreleaser/checksums/app/helidon-quickstart-se.jar.sha256 @@ -0,0 +1 @@ +18d8e2a55406eb15cfe3da97abfd49b041be168adad8dcd1cb619667b61a992b \ No newline at end of file diff --git a/out/jreleaser/checksums/checksums_sha256.txt b/out/jreleaser/checksums/checksums_sha256.txt new file mode 100644 index 0000000..eccee53 --- /dev/null +++ b/out/jreleaser/checksums/checksums_sha256.txt @@ -0,0 +1 @@ +18d8e2a55406eb15cfe3da97abfd49b041be168adad8dcd1cb619667b61a992b app/helidon-quickstart-se.jar diff --git a/out/jreleaser/output.properties b/out/jreleaser/output.properties new file mode 100644 index 0000000..750a4e6 --- /dev/null +++ b/out/jreleaser/output.properties @@ -0,0 +1,16 @@ +#JReleaser 0.4.0 +#Mon Jun 07 21:19:42 CEST 2021 +commitFullHash=ea792e845c2583781817fec4f7286cb0fa2bcce5 +commitShortHash=ea792e8 +javaVersion=11.0.10 +milestoneName=early-access +projectName=helidon-quickstart-se +projectSnapshot=true +projectVersion=1.0.0-SNAPSHOT +projectVersionMajor=1 +projectVersionMinor=0 +projectVersionPatch=0 +projectVersionTag=SNAPSHOT +releaseName=Release early-access +tagName=early-access +timestamp=2021-06-07T21\:19\:39.915208+02\:00 diff --git a/out/jreleaser/release/CHANGELOG.md b/out/jreleaser/release/CHANGELOG.md new file mode 100644 index 0000000..7687789 --- /dev/null +++ b/out/jreleaser/release/CHANGELOG.md @@ -0,0 +1,2 @@ +## Changelog + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..624b4ed --- /dev/null +++ b/pom.xml @@ -0,0 +1,80 @@ + + + 4.0.0 + + io.helidon.applications + helidon-se + 2.3.0 + + + io.helidon.examples + helidon-quickstart-se + 1.0-SNAPSHOT + myproject + + + io.helidon.examples.quickstart.se.Main + + + + + io.helidon.webserver + helidon-webserver + + + io.helidon.media + helidon-media-jsonp + + + io.helidon.config + helidon-config-yaml + + + io.helidon.health + helidon-health + + + io.helidon.health + helidon-health-checks + + + io.helidon.metrics + helidon-metrics + + + org.junit.jupiter + junit-jupiter-api + test + + + io.helidon.webclient + helidon-webclient + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-libs + + + + + io.helidon.build-tools + helidon-maven-plugin + + + third-party-license-report + + + + + + diff --git a/src/main/java/io/helidon/examples/quickstart/se/GreetService.java b/src/main/java/io/helidon/examples/quickstart/se/GreetService.java new file mode 100644 index 0000000..1dfa74d --- /dev/null +++ b/src/main/java/io/helidon/examples/quickstart/se/GreetService.java @@ -0,0 +1,137 @@ + +package io.helidon.examples.quickstart.se; + +import java.util.Collections; +import java.util.concurrent.atomic.AtomicReference; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.json.Json; +import javax.json.JsonBuilderFactory; +import javax.json.JsonException; +import javax.json.JsonObject; + +import io.helidon.common.http.Http; +import io.helidon.config.Config; +import io.helidon.webserver.Routing; +import io.helidon.webserver.ServerRequest; +import io.helidon.webserver.ServerResponse; +import io.helidon.webserver.Service; + +/** + * A simple service to greet you. Examples: + * + * Get default greeting message: + * curl -X GET http://localhost:8080/greet + * + * Get greeting message for Joe: + * curl -X GET http://localhost:8080/greet/Joe + * + * Change greeting + * curl -X PUT -H "Content-Type: application/json" -d '{"greeting" : "Howdy"}' http://localhost:8080/greet/greeting + * + * The message is returned as a JSON object + */ + +public class GreetService implements Service { + + /** + * The config value for the key {@code greeting}. + */ + private final AtomicReference greeting = new AtomicReference<>(); + + private static final JsonBuilderFactory JSON = Json.createBuilderFactory(Collections.emptyMap()); + + private static final Logger LOGGER = Logger.getLogger(GreetService.class.getName()); + + GreetService(Config config) { + greeting.set(config.get("app.greeting").asString().orElse("Ciao")); + } + + /** + * A service registers itself by updating the routing rules. + * @param rules the routing rules. + */ + @Override + public void update(Routing.Rules rules) { + rules + .get("/", this::getDefaultMessageHandler) + .get("/{name}", this::getMessageHandler) + .put("/greeting", this::updateGreetingHandler); + } + + /** + * Return a worldly greeting message. + * @param request the server request + * @param response the server response + */ + private void getDefaultMessageHandler(ServerRequest request, ServerResponse response) { + sendResponse(response, "World"); + } + + /** + * Return a greeting message using the name that was provided. + * @param request the server request + * @param response the server response + */ + private void getMessageHandler(ServerRequest request, ServerResponse response) { + String name = request.path().param("name"); + sendResponse(response, name); + } + + private void sendResponse(ServerResponse response, String name) { + String msg = String.format("%s %s!", greeting.get(), name); + + JsonObject returnObject = JSON.createObjectBuilder() + .add("message", msg) + .build(); + response.send(returnObject); + } + + private static T processErrors(Throwable ex, ServerRequest request, ServerResponse response) { + + if (ex.getCause() instanceof JsonException){ + + LOGGER.log(Level.FINE, "Invalid JSON", ex); + JsonObject jsonErrorObject = JSON.createObjectBuilder() + .add("error", "Invalid JSON") + .build(); + response.status(Http.Status.BAD_REQUEST_400).send(jsonErrorObject); + } else { + + LOGGER.log(Level.FINE, "Internal error", ex); + JsonObject jsonErrorObject = JSON.createObjectBuilder() + .add("error", "Internal error") + .build(); + response.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(jsonErrorObject); + } + + return null; + } + + private void updateGreetingFromJson(JsonObject jo, ServerResponse response) { + if (!jo.containsKey("greeting")) { + JsonObject jsonErrorObject = JSON.createObjectBuilder() + .add("error", "No greeting provided") + .build(); + response.status(Http.Status.BAD_REQUEST_400) + .send(jsonErrorObject); + return; + } + + greeting.set(jo.getString("greeting")); + response.status(Http.Status.NO_CONTENT_204).send(); + } + + /** + * Set the greeting to use in future messages. + * @param request the server request + * @param response the server response + */ + private void updateGreetingHandler(ServerRequest request, + ServerResponse response) { + request.content().as(JsonObject.class) + .thenAccept(jo -> updateGreetingFromJson(jo, response)) + .exceptionally(ex -> processErrors(ex, request, response)); + } +} \ No newline at end of file diff --git a/src/main/java/io/helidon/examples/quickstart/se/Main.java b/src/main/java/io/helidon/examples/quickstart/se/Main.java new file mode 100644 index 0000000..d64930b --- /dev/null +++ b/src/main/java/io/helidon/examples/quickstart/se/Main.java @@ -0,0 +1,86 @@ + +package io.helidon.examples.quickstart.se; + +import io.helidon.common.LogConfig; +import io.helidon.common.reactive.Single; +import io.helidon.config.Config; +import io.helidon.health.HealthSupport; +import io.helidon.health.checks.HealthChecks; +import io.helidon.media.jsonp.JsonpSupport; +import io.helidon.metrics.MetricsSupport; +import io.helidon.webserver.Routing; +import io.helidon.webserver.WebServer; + +/** + * The application main class. + */ +public final class Main { + + /** + * Cannot be instantiated. + */ + private Main() { + } + + /** + * Application main entry point. + * @param args command line arguments. + */ + public static void main(final String[] args) { + startServer(); + } + + /** + * Start the server. + * @return the created {@link WebServer} instance + */ + static Single startServer() { + + // load logging configuration + LogConfig.configureRuntime(); + + // By default this will pick up application.yaml from the classpath + Config config = Config.create(); + + WebServer server = WebServer.builder(createRouting(config)) + .config(config.get("server")) + .addMediaSupport(JsonpSupport.create()) + .build(); + + Single webserver = server.start(); + + // Try to start the server. If successful, print some info and arrange to + // print a message at shutdown. If unsuccessful, print the exception. + webserver.thenAccept(ws -> { + System.out.println("WEB server is up! http://localhost:" + ws.port() + "/greet"); + ws.whenShutdown().thenRun(() -> System.out.println("WEB server is DOWN. Good bye!")); + }) + .exceptionallyAccept(t -> { + System.err.println("Startup failed: " + t.getMessage()); + t.printStackTrace(System.err); + }); + + return webserver; + } + + /** + * Creates new {@link Routing}. + * + * @return routing configured with JSON support, a health check, and a service + * @param config configuration of this server + */ + private static Routing createRouting(Config config) { + + MetricsSupport metrics = MetricsSupport.create(); + GreetService greetService = new GreetService(config); + HealthSupport health = HealthSupport.builder() + .addLiveness(HealthChecks.healthChecks()) // Adds a convenient set of checks + .build(); + + return Routing.builder() + .register(health) // Health at "/health" + .register(metrics) // Metrics at "/metrics" + .register("/greet", greetService) + .build(); + } +} diff --git a/src/main/java/io/helidon/examples/quickstart/se/package-info.java b/src/main/java/io/helidon/examples/quickstart/se/package-info.java new file mode 100644 index 0000000..770cdae --- /dev/null +++ b/src/main/java/io/helidon/examples/quickstart/se/package-info.java @@ -0,0 +1,2 @@ + +package io.helidon.examples.quickstart.se; diff --git a/src/main/resources/META-INF/native-image/reflect-config.json b/src/main/resources/META-INF/native-image/reflect-config.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/src/main/resources/META-INF/native-image/reflect-config.json @@ -0,0 +1 @@ +[] diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml new file mode 100644 index 0000000..984387f --- /dev/null +++ b/src/main/resources/application.yaml @@ -0,0 +1,7 @@ + +app: + greeting: "Hello" + +server: + port: 8080 + host: 0.0.0.0 diff --git a/src/main/resources/logging.properties b/src/main/resources/logging.properties new file mode 100644 index 0000000..cd238eb --- /dev/null +++ b/src/main/resources/logging.properties @@ -0,0 +1,19 @@ + +# Example Logging Configuration File +# For more information see $JAVA_HOME/jre/lib/logging.properties + +# Send messages to the console +handlers=io.helidon.common.HelidonConsoleHandler + +# HelidonConsoleHandler uses a SimpleFormatter subclass that replaces "!thread!" with the current thread +java.util.logging.SimpleFormatter.format=%1$tY.%1$tm.%1$td %1$tH:%1$tM:%1$tS %4$s %3$s !thread!: %5$s%6$s%n + +# Global logging level. Can be overridden by specific loggers +.level=INFO + +# Component specific log levels +#io.helidon.webserver.level=INFO +#io.helidon.config.level=INFO +#io.helidon.security.level=INFO +#io.helidon.common.level=INFO +#io.netty.level=INFO diff --git a/src/test/java/io/helidon/examples/quickstart/se/MainTest.java b/src/test/java/io/helidon/examples/quickstart/se/MainTest.java new file mode 100644 index 0000000..b86112c --- /dev/null +++ b/src/test/java/io/helidon/examples/quickstart/se/MainTest.java @@ -0,0 +1,96 @@ + +package io.helidon.examples.quickstart.se; + +import java.util.Collections; +import java.util.concurrent.TimeUnit; + +import javax.json.Json; +import javax.json.JsonBuilderFactory; +import javax.json.JsonObject; + +import io.helidon.media.jsonp.JsonpSupport; +import io.helidon.webclient.WebClient; +import io.helidon.webclient.WebClientResponse; +import io.helidon.webserver.WebServer; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class MainTest { + + private static WebServer webServer; + private static WebClient webClient; + private static final JsonBuilderFactory JSON_BUILDER = Json.createBuilderFactory(Collections.emptyMap()); + private static final JsonObject TEST_JSON_OBJECT; + + static { + TEST_JSON_OBJECT = JSON_BUILDER.createObjectBuilder() + .add("greeting", "Hola") + .build(); + } + + @BeforeAll + public static void startTheServer() { + webServer = Main.startServer().await(); + + webClient = WebClient.builder() + .baseUri("http://localhost:" + webServer.port()) + .addMediaSupport(JsonpSupport.create()) + .build(); + } + + @AfterAll + public static void stopServer() throws Exception { + if (webServer != null) { + webServer.shutdown() + .toCompletableFuture() + .get(10, TimeUnit.SECONDS); + } + } + + @Test + public void testHelloWorld() { + JsonObject jsonObject; + WebClientResponse response; + + jsonObject = webClient.get() + .path("/greet") + .request(JsonObject.class) + .await(); + assertEquals("Hello World!", jsonObject.getString("message")); + + jsonObject = webClient.get() + .path("/greet/Joe") + .request(JsonObject.class) + .await(); + assertEquals("Hello Joe!", jsonObject.getString("message")); + + response = webClient.put() + .path("/greet/greeting") + .submit(TEST_JSON_OBJECT) + .await(); + assertEquals(204, response.status().code()); + + jsonObject = webClient.get() + .path("/greet/Joe") + .request(JsonObject.class) + .await(); + assertEquals("Hola Joe!", jsonObject.getString("message")); + + response = webClient.get() + .path("/health") + .request() + .await(); + assertEquals(200, response.status().code()); + + response = webClient.get() + .path("/metrics") + .request() + .await(); + assertEquals(200, response.status().code()); + } + +}