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

Implement binary protocol between client and server #297

Open
wants to merge 2 commits into
base: 2.5.x
Choose a base branch
from
Open
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
10 changes: 10 additions & 0 deletions config/accepted-api-changes.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,15 @@
"type": "io.micronaut.testresources.client.DefaultTestResourcesClient",
"member": "Constructor io.micronaut.testresources.client.DefaultTestResourcesClient(io.micronaut.http.client.HttpClient,java.lang.String)",
"reason": "This type is internal API"
},
{
"type": "io.micronaut.testresources.client.TestResourcesClient",
"member": "Implemented interface io.micronaut.testresources.core.TestResourcesResolver",
"reason": "With the custom codec the client can no longer directly implement the interface"
},
{
"type": "io.micronaut.testresources.client.TestResourcesClient",
"member": "Implemented interface io.micronaut.core.order.Ordered",
"reason": "Was supplied by the test resources resolver"
}
]
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def localstackModules = [

include 'test-resources-bom'
include 'test-resources-build-tools'
include 'test-resources-codec'
include 'test-resources-core'
include 'test-resources-client'
include 'test-resources-elasticsearch'
Expand Down
5 changes: 2 additions & 3 deletions test-resources-client/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ and provide their value on demand.
"""

dependencies {
api(mn.micronaut.json.core)
api(project(':micronaut-test-resources-core'))

testRuntimeOnly(mn.micronaut.http.server.netty)
api(project(":micronaut-test-resources-codec"))
testImplementation(mn.micronaut.http.server.netty)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@
import io.micronaut.core.annotation.Internal;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.type.Argument;
import io.micronaut.json.JsonMapper;
import io.micronaut.testresources.codec.Result;
import io.micronaut.testresources.codec.TestResourcesCodec;
import io.micronaut.testresources.codec.TestResourcesMediaType;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
Expand Down Expand Up @@ -52,7 +57,6 @@ public class DefaultTestResourcesClient implements TestResourcesClient {
private static final Argument<String> STRING = Argument.STRING;
private static final Argument<Boolean> BOOLEAN = Argument.BOOLEAN;

private final JsonMapper jsonMapper;
private final String baseUri;
private final HttpClient client;

Expand All @@ -66,47 +70,46 @@ public DefaultTestResourcesClient(String baseUri, String accessToken, int client
.connectTimeout(clientTimeout)
.build();
this.accessToken = accessToken;
this.jsonMapper = JsonMapper.createDefault();
}

@Override
public List<String> getResolvableProperties(Map<String, Collection<String>> propertyEntries,
Map<String, Object> testResourcesConfig) {
public Result<List<String>> getResolvableProperties(Map<String, Collection<String>> propertyEntries,
Map<String, Object> testResourcesConfig) {
Map<String, Object> properties = new HashMap<>();
properties.put("propertyEntries", propertyEntries);
properties.put("testResourcesConfig", testResourcesConfig);
return request(RESOLVABLE_PROPERTIES_URI, LIST_OF_STRING,
return Result.of(request(RESOLVABLE_PROPERTIES_URI, LIST_OF_STRING,
r -> POST(r, properties)
);
));
}

@Override
public Optional<String> resolve(String name, Map<String, Object> properties, Map<String, Object> testResourcesConfig) {
public Optional<Result<String>> resolve(String name, Map<String, Object> properties, Map<String, Object> testResourcesConfig) {
Map<String, Object> params = new HashMap<>();
params.put("name", name);
params.put("properties", properties);
params.put("testResourcesConfig", testResourcesConfig);
return Optional.ofNullable(request(RESOLVE_URI, STRING, r -> POST(r, params)));
return Result.asOptional(request(RESOLVE_URI, STRING, r -> POST(r, params)));
}

@Override
public List<String> getRequiredProperties(String expression) {
return request(REQUIRED_PROPERTIES_URI + "/" + expression, LIST_OF_STRING, this::GET);
public Result<List<String>> getRequiredProperties(String expression) {
return Result.of(request(REQUIRED_PROPERTIES_URI + "/" + expression, LIST_OF_STRING, this::GET));
}

@Override
public List<String> getRequiredPropertyEntries() {
return request(REQUIRED_PROPERTY_ENTRIES_URI, LIST_OF_STRING, this::GET);
public Result<List<String>> getRequiredPropertyEntries() {
return Result.of(request(REQUIRED_PROPERTY_ENTRIES_URI, LIST_OF_STRING, this::GET));
}

@Override
public boolean closeAll() {
return request(CLOSE_ALL_URI, BOOLEAN, this::GET);
public Result<Boolean> closeAll() {
return Result.of(request(CLOSE_ALL_URI, BOOLEAN, this::GET));
}

@Override
public boolean closeScope(@Nullable String id) {
return request(CLOSE_URI + "/" + id, BOOLEAN, this::GET);
public Result<Boolean> closeScope(@Nullable String id) {
return Result.of(request(CLOSE_URI + "/" + id, BOOLEAN, this::GET));
}

@SuppressWarnings({"java:S100", "checkstyle:MethodName"})
Expand All @@ -124,20 +127,17 @@ private <T> T request(String path, Argument<T> type, Consumer<? super HttpReques
.uri(uri(path))
.timeout(clientTimeout);
request = request.header("User-Agent", "Micronaut Test Resources Client")
.header("Content-Type", "application/json")
.header("Accept", "application/json");
.header("Content-Type", TestResourcesMediaType.TEST_RESOURCES_BINARY)
.header("Accept", TestResourcesMediaType.TEST_RESOURCES_BINARY);
if (accessToken != null) {
request = request.header(ACCESS_TOKEN, accessToken);
}
config.accept(request);
try {
var response = client.send(request.build(), HttpResponse.BodyHandlers.ofString());
var response = client.send(request.build(), HttpResponse.BodyHandlers.ofInputStream());
var body = response.body();
if (response.statusCode() == 200) {
if (STRING.equalsType(type)) {
return (T) body;
}
return jsonMapper.readValue(body, type);
return TestResourcesCodec.readObject(new DataInputStream(body));
}
return null;
} catch (IOException e) {
Expand All @@ -158,7 +158,9 @@ private URI uri(String path) {

private byte[] writeValueAsBytes(Object o) {
try {
return jsonMapper.writeValueAsBytes(o);
var baos = new ByteArrayOutputStream();
TestResourcesCodec.writeObject(o, new DataOutputStream(baos));
return baos.toByteArray();
} catch (IOException e) {
throw new TestResourcesException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
package io.micronaut.testresources.client;

import io.micronaut.core.annotation.Nullable;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.Post;
import io.micronaut.testresources.core.TestResourcesResolver;
import io.micronaut.testresources.codec.Result;

import java.util.Collection;
import java.util.Collections;
Expand All @@ -30,38 +28,27 @@
* A client responsible for connecting to a test resources
* server.
*/
public interface TestResourcesClient extends TestResourcesResolver {
public interface TestResourcesClient {
String SERVER_URI = "server.uri";
String ACCESS_TOKEN = "server.access.token";
String CLIENT_READ_TIMEOUT = "server.client.read.timeout";

@Get("/list")
default List<String> getResolvableProperties() {
default Result<List<String>> getResolvableProperties() {
return getResolvableProperties(Collections.emptyMap(), Collections.emptyMap());
}

@Override
@Post("/list")
List<String> getResolvableProperties(Map<String, Collection<String>> propertyEntries, Map<String, Object> testResourcesConfig);
Result<List<String>> getResolvableProperties(Map<String, Collection<String>> propertyEntries, Map<String, Object> testResourcesConfig);

@Override
@Post("/resolve")
Optional<String> resolve(String name, Map<String, Object> properties, Map<String, Object> testResourcesConfig);
Optional<Result<String>> resolve(String name, Map<String, Object> properties, Map<String, Object> testResourcesConfig);

@Override
@Get("/requirements/expr/{expression}")
List<String> getRequiredProperties(String expression);
Result<List<String>> getRequiredProperties(String expression);

@Override
@Get("/requirements/entries")
List<String> getRequiredPropertyEntries();
Result<List<String>> getRequiredPropertyEntries();

/**
* Closes all test resources.
*/
@Get("/close/all")
boolean closeAll();
Result<Boolean> closeAll();

@Get("/close/{id}")
boolean closeScope(@Nullable String id);
Result<Boolean> closeScope(@Nullable String id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.convert.ConversionService;
import io.micronaut.core.value.PropertyResolver;
import io.micronaut.testresources.codec.Result;
import io.micronaut.testresources.core.LazyTestResourcesExpressionResolver;
import io.micronaut.testresources.core.TestResourcesResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URL;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -60,33 +60,33 @@ private static class NoOpClient implements TestResourcesClient {
static final TestResourcesClient INSTANCE = new NoOpClient();

@Override
public List<String> getResolvableProperties(Map<String, Collection<String>> propertyEntries, Map<String, Object> testResourcesConfig) {
return Collections.emptyList();
public Result<List<String>> getResolvableProperties(Map<String, Collection<String>> propertyEntries, Map<String, Object> testResourcesConfig) {
return Result.emptyList();
}

@Override
public Optional<String> resolve(String name, Map<String, Object> properties, Map<String, Object> testResourcesConfig) {
public Optional<Result<String>> resolve(String name, Map<String, Object> properties, Map<String, Object> testResourcesConfig) {
return Optional.empty();
}

@Override
public List<String> getRequiredProperties(String expression) {
return Collections.emptyList();
public Result<List<String>> getRequiredProperties(String expression) {
return Result.emptyList();
}

@Override
public List<String> getRequiredPropertyEntries() {
return Collections.emptyList();
public Result<List<String>> getRequiredPropertyEntries() {
return Result.emptyList();
}

@Override
public boolean closeAll() {
return true;
public Result<Boolean> closeAll() {
return Result.TRUE;
}

@Override
public boolean closeScope(@Nullable String id) {
return true;
public Result<Boolean> closeScope(@Nullable String id) {
return Result.FALSE;
}
}

Expand All @@ -100,7 +100,27 @@ public <T> Optional<T> resolve(PropertyResolver propertyResolver,
Class<T> requiredType) {
if (propertyResolver instanceof Environment) {
TestResourcesClient client = clients.computeIfAbsent((Environment) propertyResolver, TestResourcesClientPropertyExpressionResolver::createClient);
Map<String, Object> props = resolveRequiredProperties(expression, propertyResolver, client);
Map<String, Object> props = resolveRequiredProperties(expression, propertyResolver, new TestResourcesResolver() {
@Override
public List<String> getResolvableProperties(Map<String, Collection<String>> propertyEntries, Map<String, Object> testResourcesConfig) {
return client.getResolvableProperties(propertyEntries, testResourcesConfig).value();
}

@Override
public Optional<String> resolve(String propertyName, Map<String, Object> properties, Map<String, Object> testResourcesConfig) {
return client.resolve(propertyName, properties, testResourcesConfig).map(Result::value);
}

@Override
public List<String> getRequiredProperties(String expression) {
return client.getRequiredProperties(expression).value();
}

@Override
public List<String> getRequiredPropertyEntries() {
return client.getRequiredPropertyEntries().value();
}
});
Map<String, Object> properties = propertyResolver.getProperties(TestResourcesResolver.TEST_RESOURCES_PROPERTY);
Optional<String> resolved = callClient(expression, client, props, properties);
if (resolved.isPresent()) {
Expand All @@ -115,7 +135,7 @@ public <T> Optional<T> resolve(PropertyResolver propertyResolver,
}

private static Optional<String> callClient(String expression, TestResourcesClient client, Map<String, Object> props, Map<String, Object> properties) {
return client.resolve(expression, props, properties);
return client.resolve(expression, props, properties).map(Result::value);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package io.micronaut.testresources.client;

import io.micronaut.core.io.ResourceLoader;
import io.micronaut.testresources.codec.Result;
import io.micronaut.testresources.core.LazyTestResourcesPropertySourceLoader;
import io.micronaut.testresources.core.PropertyExpressionProducer;

Expand Down Expand Up @@ -51,13 +52,15 @@ private static class ClientTestResourcesResolver implements PropertyExpressionPr
public List<String> getPropertyEntries() {
return findClient(null)
.map(TestResourcesClient::getRequiredPropertyEntries)
.map(Result::value)
.orElse(Collections.emptyList());
}

@Override
public List<String> produceKeys(ResourceLoader resourceLoader, Map<String, Collection<String>> propertyEntries, Map<String, Object> testResourcesConfig) {
return findClient(resourceLoader)
.map(client -> client.getResolvableProperties(propertyEntries, testResourcesConfig))
.map(Result::value)
.orElse(Collections.emptyList());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,44 +1,45 @@
package io.micronaut.testresources.client

import io.micronaut.context.annotation.Requires
import io.micronaut.http.annotation.Consumes
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
import io.micronaut.http.annotation.Post
import io.micronaut.testresources.core.TestResourcesResolver
import io.micronaut.http.annotation.Produces
import io.micronaut.testresources.codec.Result
import io.micronaut.testresources.codec.TestResourcesMediaType

@Controller("/")
@Requires(property = 'server', notEquals = 'false')
class TestServer implements TestResourcesResolver {
@Produces(TestResourcesMediaType.TEST_RESOURCES_BINARY)
@Consumes(TestResourcesMediaType.TEST_RESOURCES_BINARY)
class TestServer {

@Override
@Post("/list")
List<String> getResolvableProperties(Map<String, Collection<String>> propertyEntries, Map<String, Object> testResourcesConfig) {
["dummy1", "dummy2", "missing"]
Result<List<String>> getResolvableProperties(Map<String, Collection<String>> propertyEntries, Map<String, Object> testResourcesConfig) {
Result.of(["dummy1", "dummy2", "missing"])
}

@Override
@Get("/requirements/expr/{expression}")
List<String> getRequiredProperties(String expression) {
[]
Result<List<String>> getRequiredProperties(String expression) {
Result.of([])
}

@Override
@Get("/requirements/entries")
List<String> getRequiredPropertyEntries() {
[]
Result<List<String>> getRequiredPropertyEntries() {
Result.of([])
}

@Override
@Post('/resolve')
Optional<String> resolve(String name, Map<String, Object> properties, Map<String, Object> testResourcesConfig) {
Optional<Result<String>> resolve(String name, Map<String, Object> properties, Map<String, Object> testResourcesConfig) {
if ("missing" == name) {
return Optional.empty()
}
Optional.of("value for $name".toString())
Result.asOptional("value for $name".toString())
}

@Get("/close/all")
void closeAll() {

Result<Boolean> closeAll() {
Result.TRUE
}
}
Loading