Skip to content

Commit

Permalink
Native smoke test for webclient (#2112)
Browse files Browse the repository at this point in the history
* Native smoke test for webclient

Signed-off-by: Daniel Kec <daniel.kec@oracle.com>
  • Loading branch information
danielkec authored Aug 10, 2020
1 parent cbb88d8 commit 6ecabe4
Show file tree
Hide file tree
Showing 7 changed files with 396 additions and 0 deletions.
3 changes: 3 additions & 0 deletions tests/integration/native-image/se-1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,7 @@ curl -i http://localhost:7076/health

# Should return 200 code and JSON response with metrics
curl -i -H "Accept: application/json" http://localhost:7076/metrics

# Should return ALL TESTS PASSED! after passing all webclient tests
curl -i http://localhost:7076/wc/test
```
16 changes: 16 additions & 0 deletions tests/integration/native-image/se-1/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@
<groupId>io.helidon.media</groupId>
<artifactId>helidon-media-jsonp</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.media</groupId>
<artifactId>helidon-media-jsonb</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.config</groupId>
<artifactId>helidon-config-yaml</artifactId>
Expand All @@ -92,6 +96,18 @@
<groupId>io.helidon.metrics</groupId>
<artifactId>helidon-metrics</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.webclient</groupId>
<artifactId>helidon-webclient</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.webclient</groupId>
<artifactId>helidon-webclient-metrics</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.webclient</groupId>
<artifactId>helidon-webclient-tracing</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.security.integration</groupId>
<artifactId>helidon-security-integration-webserver</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2020 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.
* 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.
*
*/

package io.helidon.tests.integration.nativeimage.se1;

import io.helidon.common.Reflected;

@Reflected
public class Animal {
private TYPE type;
private String name;

public Animal() {
}

public Animal(final TYPE type, final String name) {
this.type = type;
this.name = name;
}

public TYPE getType() {
return type;
}

public void setType(final TYPE type) {
this.type = type;
}

public String getName() {
return name;
}

public void setName(final String name) {
this.name = name;
}

public enum TYPE {
BIRD, DOG, CAT
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Copyright (c) 2020 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.
* 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.
*
*/

package io.helidon.tests.integration.nativeimage.se1;

import java.io.ByteArrayInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.StringReader;
import java.nio.ByteBuffer;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.Flow;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Logger;
import java.util.zip.GZIPInputStream;

import javax.json.Json;
import javax.json.JsonPointer;
import javax.json.JsonString;
import javax.json.JsonValue;

import io.helidon.common.GenericType;
import io.helidon.common.http.DataChunk;
import io.helidon.common.reactive.Multi;
import io.helidon.common.reactive.Single;
import io.helidon.media.common.MessageBodyReaderContext;
import io.helidon.media.common.MessageBodyStreamReader;
import io.helidon.webserver.Routing;
import io.helidon.webserver.ServerRequest;
import io.helidon.webserver.ServerResponse;
import io.helidon.webserver.Service;

public class MockZipkinService implements Service {

private static final Logger LOGGER = Logger.getLogger(MockZipkinService.class.getName());

final static JsonPointer TAGS_POINTER = Json.createPointer("/tags");
final static JsonPointer COMPONENT_POINTER = Json.createPointer("/tags/component");

private final Set<String> filteredComponents;
private final AtomicReference<CompletableFuture<JsonValue>> next = new AtomicReference<>(new CompletableFuture<>());

/**
* Create mock of the Zipkin listening on /api/v2/spans.
*
* @param filteredComponents listen only for traces with component tag having one of specified values
*/
MockZipkinService(Set<String> filteredComponents) {
this.filteredComponents = filteredComponents;
}

@Override
public void update(final Routing.Rules rules) {
rules.post("/api/v2/spans", this::mockZipkin);
}

/**
* Return completion being completed when next trace call arrives.
*
* @return completion being completed when next trace call arrives
*/
CompletionStage<JsonValue> next() {
return next.get();
}

private void mockZipkin(final ServerRequest request, final ServerResponse response) {
request.queryParams().all("serviceName").forEach(s -> System.out.println(">>>" + s));
request.content()
.registerReader(new MessageBodyStreamReader<JsonValue>() {
@Override
public PredicateResult accept(final GenericType<?> type, final MessageBodyReaderContext context) {
return PredicateResult.COMPATIBLE;
}

@Override
@SuppressWarnings("unchecked")
public <U extends JsonValue> Flow.Publisher<U> read(final Flow.Publisher<DataChunk> publisher, final GenericType<U> type, final MessageBodyReaderContext context) {
return (Flow.Publisher<U>) Multi.create(publisher)
.map(d -> ByteBuffer.wrap(d.bytes()))
.reduce((buf, buf2) ->
ByteBuffer.allocate(buf.capacity() + buf2.capacity())
.put(buf.array())
.put(buf2.array()))
.flatMap(b -> {
try (ByteArrayInputStream bais = new ByteArrayInputStream(b.array());
GZIPInputStream gzipInputStream = new GZIPInputStream(bais)) {
return Single.just(Json.createReader(new StringReader(new String(gzipInputStream.readAllBytes())))
.readArray());
} catch (EOFException e) {
//ignore
return Multi.empty();
} catch (IOException e) {
throw new RuntimeException(e);
}
})
.flatMap(a -> Multi.create(a.stream()));
}
})
.asStream(JsonValue.class)
.map(JsonValue::asJsonObject)
.filter(json ->
TAGS_POINTER.containsValue(json)
&& COMPONENT_POINTER.containsValue(json)
&& filteredComponents.stream()
.anyMatch(s -> s.equals(((JsonString) COMPONENT_POINTER.getValue(json)).getString()))
)
.onError(Throwable::printStackTrace)
.onError(t -> response.status(500).send(t))
.onComplete(response::send)
.peek(json -> LOGGER.info(json.toString()))
.forEach(e -> next.getAndSet(new CompletableFuture<>()).complete(e));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@

import java.io.IOException;
import java.nio.file.Paths;
import java.util.Set;
import java.util.logging.LogManager;

import io.helidon.config.Config;
import io.helidon.config.FileSystemWatcher;
import io.helidon.health.HealthSupport;
import io.helidon.health.checks.HealthChecks;
import io.helidon.media.jsonb.JsonbSupport;
import io.helidon.media.jsonp.JsonpSupport;
import io.helidon.metrics.MetricsSupport;
import io.helidon.security.integration.webserver.WebSecurity;
Expand All @@ -40,6 +42,7 @@
* Main class of this integration test.
*/
public final class Se1Main {

/**
* Cannot be instantiated.
*/
Expand Down Expand Up @@ -75,6 +78,7 @@ static WebServer startServer() throws IOException {
.config(config.get("server"))
.tracer(TracerBuilder.create(config.get("tracing")).build())
.addMediaSupport(JsonpSupport.create())
.addMediaSupport(JsonbSupport.create())
.printFeatureDetails(true)
.build();

Expand Down Expand Up @@ -119,6 +123,8 @@ private static Routing createRouting(Config config) {

MetricsSupport metrics = MetricsSupport.create();
GreetService greetService = new GreetService(config);
MockZipkinService zipkinService = new MockZipkinService(Set.of("helidon-webclient"));
WebClientService webClientService = new WebClientService(config, zipkinService);
HealthSupport health = HealthSupport.builder()
.addLiveness(HealthChecks.healthChecks()) // Adds a convenient set of checks
.addLiveness(() -> HealthCheckResponse.named("custom") // a custom health check
Expand All @@ -135,6 +141,8 @@ private static Routing createRouting(Config config) {
.register(health) // Health at "/health"
.register(metrics) // Metrics at "/metrics"
.register("/greet", greetService)
.register("/wc", webClientService)
.register("/zipkin", zipkinService)
.build();
}

Expand Down
Loading

0 comments on commit 6ecabe4

Please sign in to comment.