-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathRestateExtension.java
More file actions
138 lines (125 loc) · 5.35 KB
/
Copy pathRestateExtension.java
File metadata and controls
138 lines (125 loc) · 5.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright (c) 2023 - Restate Software, Inc., Restate GmbH
//
// This file is part of the Restate Java SDK,
// which is released under the MIT license.
//
// You can find a copy of the license in file LICENSE in the root
// directory of this repository or package, or at
// https://github.com/restatedev/sdk-java/blob/main/LICENSE
package dev.restate.sdk.testing;
import dev.restate.client.Client;
import dev.restate.sdk.endpoint.Endpoint;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.regex.Pattern;
import org.junit.jupiter.api.extension.*;
import org.junit.platform.commons.support.AnnotationSupport;
/**
* @see RestateTest
*/
public class RestateExtension implements BeforeAllCallback, ParameterResolver {
static final ExtensionContext.Namespace NAMESPACE =
ExtensionContext.Namespace.create(RestateExtension.class);
static final String RUNNER = "Runner";
@Override
public void beforeAll(ExtensionContext extensionContext) {
getOrCreateRunner(extensionContext).start();
}
@Override
@SuppressWarnings(
"deprecation") // RestateAdminClient/ApiClient are deprecated but still supported
public boolean supportsParameter(
ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
return (parameterContext.isAnnotated(RestateAdminClient.class)
&& dev.restate.admin.client.ApiClient.class.isAssignableFrom(
parameterContext.getParameter().getType()))
|| (parameterContext.isAnnotated(RestateClient.class)
&& Client.class.isAssignableFrom(parameterContext.getParameter().getType()))
|| (parameterContext.isAnnotated(RestateURL.class)
&& isStringOrUrlOrUri(parameterContext.getParameter().getType()))
|| (parameterContext.isAnnotated(RestateAdminURL.class)
&& isStringOrUrlOrUri(parameterContext.getParameter().getType()));
}
@Override
@SuppressWarnings(
"deprecation") // RestateAdminClient/ApiClient are deprecated but still supported
public Object resolveParameter(
ParameterContext parameterContext, ExtensionContext extensionContext)
throws ParameterResolutionException {
RestateRunner runner = getOrCreateRunner(extensionContext);
if (parameterContext.isAnnotated(RestateAdminClient.class)) {
return runner.getAdminClient();
} else if (parameterContext.isAnnotated(RestateClient.class)) {
URL url = runner.getIngressUrl();
return Client.connect(url.toString());
} else if (parameterContext.isAnnotated(RestateURL.class)) {
return convertUrl(parameterContext.getParameter().getType(), runner.getIngressUrl());
} else if (parameterContext.isAnnotated(RestateAdminURL.class)) {
return convertUrl(parameterContext.getParameter().getType(), runner.getAdminUrl());
}
throw new ParameterResolutionException("The parameter is not supported");
}
private static boolean isStringOrUrlOrUri(Class<?> type) {
return String.class.isAssignableFrom(type)
|| URL.class.isAssignableFrom(type)
|| URI.class.isAssignableFrom(type);
}
private static Object convertUrl(Class<?> type, URL url) {
if (type.equals(String.class)) {
return url.toString();
}
if (type.equals(URI.class)) {
try {
return url.toURI();
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
return url;
}
private RestateRunner getOrCreateRunner(ExtensionContext extensionContext) {
return extensionContext
.getStore(NAMESPACE)
.getOrComputeIfAbsent(
RUNNER, ignored -> initializeRestateRunner(extensionContext), RestateRunner.class);
}
private RestateRunner initializeRestateRunner(ExtensionContext extensionContext) {
// Discover services
List<Object> servicesToBind =
AnnotationSupport.findAnnotatedFieldValues(
extensionContext.getRequiredTestInstance(), BindService.class);
if (servicesToBind.isEmpty()) {
throw new IllegalStateException(
"The class "
+ extensionContext.getRequiredTestClass().getName()
+ " is annotated with @RestateTest, but there are no fields annotated with @BindService");
}
RestateTest testAnnotation =
AnnotationSupport.findAnnotation(extensionContext.getRequiredTestClass(), RestateTest.class)
.orElseThrow(
() ->
new IllegalStateException(
"Expecting @RestateTest annotation on the test class"));
// Build runner discovering services to bind
Endpoint.Builder endpointBuilder = Endpoint.builder();
servicesToBind.forEach(endpointBuilder::bind);
var runnerBuilder = RestateRunner.from(endpointBuilder.build());
runnerBuilder.withRestateContainerImage(testAnnotation.containerImage());
if (testAnnotation.environment() != null) {
for (String env : testAnnotation.environment()) {
String[] splitEnv = env.split(Pattern.quote("="), 2);
if (splitEnv.length != 2) {
throw new IllegalStateException(
"Environment variables should be passed in the form of NAME=VALUE. Found an invalid env: '"
+ env
+ "'");
}
runnerBuilder.withAdditionalEnv(splitEnv[0], splitEnv[1]);
}
}
return runnerBuilder.build();
}
}