diff --git a/bom/runtime/pom.xml b/bom/runtime/pom.xml
index fbd5f4c9aea33..96539bdc26c7d 100644
--- a/bom/runtime/pom.xml
+++ b/bom/runtime/pom.xml
@@ -30,7 +30,7 @@
1.0.1
1.3.1
1.0
- 1.3.3
+ 1.3.4
1.3.9
2.1.0
2.2.0
diff --git a/build-parent/pom.xml b/build-parent/pom.xml
index a949ab3fa9c5a..09dc121c2fc14 100644
--- a/build-parent/pom.xml
+++ b/build-parent/pom.xml
@@ -61,7 +61,7 @@
2.1.0
2.0.2
1.0
- 1.2.1
+ 1.3.4
1.1.2
1.3.1
1.0.1
diff --git a/extensions/rest-client/deployment/src/main/java/io/quarkus/restclient/deployment/RestClientProcessor.java b/extensions/rest-client/deployment/src/main/java/io/quarkus/restclient/deployment/RestClientProcessor.java
index 56edb24c7361c..bc06a876170a2 100644
--- a/extensions/rest-client/deployment/src/main/java/io/quarkus/restclient/deployment/RestClientProcessor.java
+++ b/extensions/rest-client/deployment/src/main/java/io/quarkus/restclient/deployment/RestClientProcessor.java
@@ -138,33 +138,9 @@ void processInterfaces(CombinedIndexBuildItem combinedIndexBuildItem,
Set returnTypes = new HashSet<>();
IndexView index = combinedIndexBuildItem.getIndex();
- for (AnnotationInstance annotation : index.getAnnotations(PATH)) {
- AnnotationTarget target = annotation.target();
- ClassInfo theInfo;
- if (target.kind() == AnnotationTarget.Kind.CLASS) {
- theInfo = target.asClass();
- } else if (target.kind() == AnnotationTarget.Kind.METHOD) {
- theInfo = target.asMethod().declaringClass();
- } else {
- continue;
- }
-
- if (!isRestClientInterface(index, theInfo)) {
- continue;
- }
- interfaces.put(theInfo.name(), theInfo);
-
- // Find Return types
- for (MethodInfo method : theInfo.methods()) {
- Type type = method.returnType();
- if (!type.name().toString().contains("java.lang")) {
- if (!returnTypes.contains(type)) {
- returnTypes.add(type);
- }
- }
- }
- }
+ findInterfaces(index, interfaces, returnTypes, REGISTER_REST_CLIENT);
+ findInterfaces(index, interfaces, returnTypes, PATH);
if (interfaces.isEmpty()) {
return;
@@ -207,16 +183,17 @@ public void register(RegistrationContext registrationContext) {
// The spec is not clear whether we should add superinterfaces too - let's keep aligned with SmallRye for now
configurator.addType(restClientName);
configurator.addQualifier(REST_CLIENT);
- final ScopeInfo scope = computeDefaultScope(config, entry);
+ final String configPrefix = computeConfigPrefix(restClientName.toString(), entry.getValue());
+ final ScopeInfo scope = computeDefaultScope(config, entry, configPrefix);
configurator.scope(scope);
configurator.creator(m -> {
// return new RestClientBase(proxyType, baseUri).create();
ResultHandle interfaceHandle = m.loadClass(restClientName.toString());
ResultHandle baseUriHandle = m.load(getAnnotationParameter(entry.getValue(), "baseUri"));
- ResultHandle configKeyHandle = m.load(getAnnotationParameter(entry.getValue(), "configKey"));
+ ResultHandle configPrefixHandle = m.load(configPrefix);
ResultHandle baseHandle = m.newInstance(
MethodDescriptor.ofConstructor(RestClientBase.class, Class.class, String.class, String.class),
- interfaceHandle, baseUriHandle, configKeyHandle);
+ interfaceHandle, baseUriHandle, configPrefixHandle);
ResultHandle ret = m.invokeVirtualMethod(
MethodDescriptor.ofMethod(RestClientBase.class, "create", Object.class), baseHandle);
m.returnValue(ret);
@@ -232,13 +209,62 @@ public void register(RegistrationContext registrationContext) {
restClientRecorder.setSslEnabled(sslNativeConfig.isEnabled());
}
- private ScopeInfo computeDefaultScope(Config config, Map.Entry entry) {
- DotName restClientName = entry.getKey();
+ private void findInterfaces(IndexView index, Map interfaces, Set returnTypes,
+ DotName annotationToFind) {
+ for (AnnotationInstance annotation : index.getAnnotations(annotationToFind)) {
+ AnnotationTarget target = annotation.target();
+ ClassInfo theInfo;
+ if (target.kind() == AnnotationTarget.Kind.CLASS) {
+ theInfo = target.asClass();
+ } else if (target.kind() == AnnotationTarget.Kind.METHOD) {
+ theInfo = target.asMethod().declaringClass();
+ } else {
+ continue;
+ }
+
+ if (!isRestClientInterface(index, theInfo)) {
+ continue;
+ }
+
+ interfaces.put(theInfo.name(), theInfo);
+
+ // Find Return types
+ processInterfaceReturnTypes(theInfo, returnTypes);
+ for (Type interfaceType : theInfo.interfaceTypes()) {
+ ClassInfo interfaceClassInfo = index.getClassByName(interfaceType.name());
+ if (interfaceClassInfo != null) {
+ processInterfaceReturnTypes(interfaceClassInfo, returnTypes);
+ }
+ }
+ }
+ }
+
+ private void processInterfaceReturnTypes(ClassInfo classInfo, Set returnTypes) {
+ for (MethodInfo method : classInfo.methods()) {
+ Type type = method.returnType();
+ if (!type.name().toString().contains("java.lang")) {
+ if (!returnTypes.contains(type)) {
+ returnTypes.add(type);
+ }
+ }
+ }
+ }
+
+ private String computeConfigPrefix(String interfaceName, ClassInfo classInfo) {
+ String propertyPrefixFromAnnotation = getAnnotationParameter(classInfo, "configKey");
+
+ if (propertyPrefixFromAnnotation != null && !propertyPrefixFromAnnotation.isEmpty()) {
+ return propertyPrefixFromAnnotation;
+ }
+
+ return interfaceName;
+ }
+
+ private ScopeInfo computeDefaultScope(Config config, Map.Entry entry, String configPrefix) {
// Initialize a default @Dependent scope as per the spec
ScopeInfo scopeInfo = BuiltinScope.DEPENDENT.getInfo();
- final String REST_SCOPE_FORMAT = "%s/" + RestClientBase.MP_REST + "/scope";
final Optional scopeConfig = config
- .getOptionalValue(String.format(REST_SCOPE_FORMAT, restClientName.toString()), String.class);
+ .getOptionalValue(String.format(RestClientBase.REST_SCOPE_FORMAT, configPrefix), String.class);
if (scopeConfig.isPresent()) {
final DotName scope = DotName.createSimple(scopeConfig.get());
final BuiltinScope builtinScope = BuiltinScope.from(scope);
@@ -247,7 +273,7 @@ private ScopeInfo computeDefaultScope(Config config, Map.Entry annotations = entry.getValue().annotations().keySet();
diff --git a/extensions/rest-client/runtime/src/main/java/io/quarkus/restclient/runtime/RestClientBase.java b/extensions/rest-client/runtime/src/main/java/io/quarkus/restclient/runtime/RestClientBase.java
index f41d9f2c76e7a..d0030473ce41b 100644
--- a/extensions/rest-client/runtime/src/main/java/io/quarkus/restclient/runtime/RestClientBase.java
+++ b/extensions/rest-client/runtime/src/main/java/io/quarkus/restclient/runtime/RestClientBase.java
@@ -1,8 +1,17 @@
package io.quarkus.restclient.runtime;
+import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Stream;
+
+import javax.net.ssl.HostnameVerifier;
import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigProvider;
@@ -13,54 +22,194 @@ public class RestClientBase {
public static final String MP_REST = "mp-rest";
public static final String REST_URL_FORMAT = "%s/" + MP_REST + "/url";
public static final String REST_URI_FORMAT = "%s/" + MP_REST + "/uri";
+ public static final String REST_CONNECT_TIMEOUT_FORMAT = "%s/" + MP_REST + "/connectTimeout";
+ public static final String REST_READ_TIMEOUT_FORMAT = "%s/" + MP_REST + "/readTimeout";
+ public static final String REST_SCOPE_FORMAT = "%s/" + MP_REST + "/scope";
+ public static final String REST_PROVIDERS = "%s/" + MP_REST + "/providers";
+ public static final String REST_TRUST_STORE = "%s/" + MP_REST + "/trustStore";
+ public static final String REST_TRUST_STORE_PASSWORD = "%s/" + MP_REST + "/trustStorePassword";
+ public static final String REST_TRUST_STORE_TYPE = "%s/" + MP_REST + "/trustStoreType";
+ public static final String REST_KEY_STORE = "%s/" + MP_REST + "/keyStore";
+ public static final String REST_KEY_STORE_PASSWORD = "%s/" + MP_REST + "/keyStorePassword";
+ public static final String REST_KEY_STORE_TYPE = "%s/" + MP_REST + "/keyStoreType";
+ public static final String REST_HOSTNAME_VERIFIER = "%s/" + MP_REST + "/hostnameVerifier";
private final Class> proxyType;
private final String baseUriFromAnnotation;
- private final String propertyPrefixFromAnnotation;
+ private final String propertyPrefix;
private final Config config;
- public RestClientBase(Class> proxyType, String baseUriFromAnnotation, String propertyPrefixFromAnnotation) {
+ public RestClientBase(Class> proxyType, String baseUriFromAnnotation, String propertyPrefix) {
this.proxyType = proxyType;
this.baseUriFromAnnotation = baseUriFromAnnotation;
- this.propertyPrefixFromAnnotation = propertyPrefixFromAnnotation;
this.config = ConfigProvider.getConfig();
+ this.propertyPrefix = propertyPrefix;
}
public Object create() {
RestClientBuilder builder = RestClientBuilder.newBuilder();
- String baseUrl = getBaseUrl();
+ configureBaseUrl(builder);
+ configureTimeouts(builder);
+ configureProviders(builder);
+ configureSsl(builder);
+
+ return builder.build(proxyType);
+ }
+
+ private void configureSsl(RestClientBuilder builder) {
+ Optional maybeTrustStore = getOptionalProperty(REST_TRUST_STORE, String.class);
+ maybeTrustStore.ifPresent(trustStore -> registerTrustStore(trustStore, builder));
+
+ Optional maybeKeyStore = getOptionalProperty(REST_KEY_STORE, String.class);
+ maybeKeyStore.ifPresent(keyStore -> registerKeyStore(keyStore, builder));
+
+ Optional maybeHostnameVerifier = getOptionalProperty(REST_HOSTNAME_VERIFIER, String.class);
+ maybeHostnameVerifier.ifPresent(verifier -> registerHostnameVerifier(verifier, builder));
+ }
+
+ private void registerHostnameVerifier(String verifier, RestClientBuilder builder) {
try {
- return builder.baseUrl(new URL(baseUrl)).build(proxyType);
- } catch (MalformedURLException e) {
- throw new IllegalArgumentException("The value of URL was invalid " + baseUrl, e);
- } catch (Exception e) {
- if ("com.oracle.svm.core.jdk.UnsupportedFeatureError".equals(e.getClass().getCanonicalName())) {
- throw new IllegalArgumentException(baseUrl
- + " requires SSL support but it is disabled. You probably have set quarkus.ssl.native to false.");
+ Class> verifierClass = Class.forName(verifier, true, Thread.currentThread().getContextClassLoader());
+ builder.hostnameVerifier((HostnameVerifier) verifierClass.newInstance());
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Could not find hostname verifier class" + verifier, e);
+ } catch (InstantiationException | IllegalAccessException e) {
+ throw new RuntimeException(
+ "Failed to instantiate hostname verifier class. Make sure it has a public, no-argument constructor", e);
+ } catch (ClassCastException e) {
+ throw new RuntimeException("The provided hostname verifier " + verifier + " is not an instance of HostnameVerifier",
+ e);
+ }
+ }
+
+ private void registerKeyStore(String keyStorePath, RestClientBuilder builder) {
+ Optional keyStorePassword = getOptionalProperty(REST_KEY_STORE_PASSWORD, String.class);
+ Optional keyStoreType = getOptionalProperty(REST_KEY_STORE_TYPE, String.class);
+
+ try {
+ KeyStore keyStore = KeyStore.getInstance(keyStoreType.orElse("JKS"));
+ String password = keyStorePassword
+ .orElseThrow(() -> new IllegalArgumentException("No password provided for keystore"));
+
+ try (InputStream input = locateStream(keyStorePath)) {
+ keyStore.load(input, password.toCharArray());
+ } catch (IOException | CertificateException | NoSuchAlgorithmException e) {
+ throw new IllegalArgumentException("Failed to initialize trust store from classpath resource " + keyStorePath,
+ e);
}
- throw e;
+
+ builder.keyStore(keyStore, password);
+ } catch (KeyStoreException e) {
+ throw new IllegalArgumentException("Failed to initialize trust store from " + keyStorePath, e);
+ }
+ }
+
+ private void registerTrustStore(String trustStorePath, RestClientBuilder builder) {
+ Optional maybeTrustStorePassword = getOptionalProperty(REST_TRUST_STORE_PASSWORD, String.class);
+ Optional maybeTrustStoreType = getOptionalProperty(REST_TRUST_STORE_TYPE, String.class);
+
+ try {
+ KeyStore trustStore = KeyStore.getInstance(maybeTrustStoreType.orElse("JKS"));
+ String password = maybeTrustStorePassword
+ .orElseThrow(() -> new IllegalArgumentException("No password provided for truststore"));
+
+ try (InputStream input = locateStream(trustStorePath)) {
+ trustStore.load(input, password.toCharArray());
+ } catch (IOException | CertificateException | NoSuchAlgorithmException e) {
+ throw new IllegalArgumentException("Failed to initialize trust store from classpath resource " + trustStorePath,
+ e);
+ }
+
+ builder.trustStore(trustStore);
+ } catch (KeyStoreException e) {
+ throw new IllegalArgumentException("Failed to initialize trust store from " + trustStorePath, e);
}
}
- private String getBaseUrl() {
- String prefix = proxyType.getName();
- if (propertyPrefixFromAnnotation != null && !propertyPrefixFromAnnotation.isEmpty()) {
- prefix = propertyPrefixFromAnnotation;
+ private InputStream locateStream(String path) throws FileNotFoundException {
+ if (path.startsWith("classpath:")) {
+ path = path.replaceFirst("classpath:", "");
+ InputStream resultStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
+ if (resultStream == null) {
+ resultStream = getClass().getResourceAsStream(path);
+ }
+ if (resultStream == null) {
+ throw new IllegalArgumentException(
+ "Classpath resource " + path + " not found for MicroProfile Rest Client SSL configuration");
+ }
+ return resultStream;
+ } else {
+ if (path.startsWith("file:")) {
+ path = path.replaceFirst("file:", "");
+ }
+ File certificateFile = new File(path);
+ if (!certificateFile.isFile()) {
+ throw new IllegalArgumentException(
+ "Certificate file: " + path + " not found for MicroProfile Rest Client SSL configuration");
+ }
+ return new FileInputStream(certificateFile);
}
- String propertyName = String.format(REST_URI_FORMAT, prefix);
- Optional propertyOptional = config.getOptionalValue(propertyName, String.class);
+ }
+
+ private void configureProviders(RestClientBuilder builder) {
+ Optional maybeProviders = getOptionalProperty(REST_PROVIDERS, String.class);
+ maybeProviders.ifPresent(providers -> registerProviders(builder, providers));
+ }
+
+ private void registerProviders(RestClientBuilder builder, String providersAsString) {
+ Stream.of(providersAsString.split(","))
+ .map(String::trim)
+ .map(this::providerClassForName)
+ .forEach(builder::register);
+ }
+
+ private Class> providerClassForName(String name) {
+ try {
+ return Class.forName(name, true, Thread.currentThread().getContextClassLoader());
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Could not find provider class: " + name);
+ }
+ }
+
+ private void configureTimeouts(RestClientBuilder builder) {
+ Optional connectTimeout = getOptionalProperty(REST_CONNECT_TIMEOUT_FORMAT, Long.class);
+ connectTimeout.ifPresent(timeout -> builder.connectTimeout(timeout, TimeUnit.MILLISECONDS));
+
+ Optional readTimeout = getOptionalProperty(REST_READ_TIMEOUT_FORMAT, Long.class);
+ readTimeout.ifPresent(timeout -> builder.readTimeout(timeout, TimeUnit.MILLISECONDS));
+ }
+
+ private void configureBaseUrl(RestClientBuilder builder) {
+ Optional propertyOptional = getOptionalProperty(REST_URI_FORMAT, String.class);
if (!propertyOptional.isPresent()) {
- propertyName = String.format(REST_URL_FORMAT, prefix);
- propertyOptional = config.getOptionalValue(propertyName, String.class);
+ propertyOptional = getOptionalProperty(REST_URL_FORMAT, String.class);
}
if (((baseUriFromAnnotation == null) || baseUriFromAnnotation.isEmpty())
&& !propertyOptional.isPresent()) {
throw new IllegalArgumentException(
String.format(
"Unable to determine the proper baseUrl/baseUri. Consider registering using @RegisterRestClient(baseUri=\"someuri\", configKey=\"orkey\"), or by adding '%s' to your Quarkus configuration",
- propertyName));
+ propertyPrefix));
}
- return propertyOptional.orElse(baseUriFromAnnotation);
+ String baseUrl = propertyOptional.orElse(baseUriFromAnnotation);
+
+ try {
+ builder.baseUrl(new URL(baseUrl));
+ } catch (MalformedURLException e) {
+ throw new IllegalArgumentException("The value of URL was invalid " + baseUrl, e);
+ } catch (Exception e) {
+ if ("com.oracle.svm.core.jdk.UnsupportedFeatureError".equals(e.getClass().getCanonicalName())) {
+ throw new IllegalArgumentException(baseUrl
+ + " requires SSL support but it is disabled. You probably have set quarkus.ssl.native to false.");
+ }
+ throw e;
+ }
+ }
+
+ private Optional getOptionalProperty(String propertyFormat, Class type) {
+ Optional interfaceNameValue = config.getOptionalValue(String.format(propertyFormat, proxyType.getName()), type);
+ return interfaceNameValue.isPresent() ? interfaceNameValue
+ : config.getOptionalValue(String.format(propertyFormat, propertyPrefix), type);
}
}
diff --git a/extensions/rest-client/runtime/src/main/java/io/quarkus/restclient/runtime/RestClientRecorder.java b/extensions/rest-client/runtime/src/main/java/io/quarkus/restclient/runtime/RestClientRecorder.java
index 2ecf17c874fbd..cd563e4aeaedb 100644
--- a/extensions/rest-client/runtime/src/main/java/io/quarkus/restclient/runtime/RestClientRecorder.java
+++ b/extensions/rest-client/runtime/src/main/java/io/quarkus/restclient/runtime/RestClientRecorder.java
@@ -49,19 +49,23 @@ public InjectorFactory getInjectorFactory() {
if (useBuiltIn) {
RegisterBuiltin.register(clientProviderFactory);
- registerProviders(clientProviderFactory, contributedProviders);
+ registerProviders(clientProviderFactory, contributedProviders, false);
} else {
- registerProviders(clientProviderFactory, providersToRegister);
+ providersToRegister.removeAll(contributedProviders);
+ registerProviders(clientProviderFactory, providersToRegister, true);
+ registerProviders(clientProviderFactory, contributedProviders, false);
}
RestClientBuilderImpl.setProviderFactory(clientProviderFactory);
}
- private static void registerProviders(ResteasyProviderFactory clientProviderFactory, Set providersToRegister) {
+ private static void registerProviders(ResteasyProviderFactory clientProviderFactory, Set providersToRegister,
+ Boolean isBuiltIn) {
for (String providerToRegister : providersToRegister) {
try {
clientProviderFactory
- .registerProvider(Thread.currentThread().getContextClassLoader().loadClass(providerToRegister.trim()));
+ .registerProvider(Thread.currentThread().getContextClassLoader().loadClass(providerToRegister.trim()),
+ isBuiltIn);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unable to find class for provider " + providerToRegister, e);
}
diff --git a/tcks/microprofile-fault-tolerance/tck-suite.xml b/tcks/microprofile-fault-tolerance/tck-suite.xml
index 0a7a3f2e8e779..09a6ff27adf7e 100644
--- a/tcks/microprofile-fault-tolerance/tck-suite.xml
+++ b/tcks/microprofile-fault-tolerance/tck-suite.xml
@@ -45,6 +45,11 @@
+
+
+
+
+
diff --git a/tcks/microprofile-metrics/rest/pom.xml b/tcks/microprofile-metrics/rest/pom.xml
index c38c376f1af44..4856f1dc87861 100644
--- a/tcks/microprofile-metrics/rest/pom.xml
+++ b/tcks/microprofile-metrics/rest/pom.xml
@@ -31,6 +31,9 @@
tier=integration
+
+ org.eclipse.microprofile.metrics.test.MpMetricTest
+
diff --git a/tcks/microprofile-rest-client/pom.xml b/tcks/microprofile-rest-client/pom.xml
index 44c7620865e07..cb3595da13e43 100644
--- a/tcks/microprofile-rest-client/pom.xml
+++ b/tcks/microprofile-rest-client/pom.xml
@@ -19,9 +19,6 @@
org.apache.maven.plugins
maven-surefire-plugin
-
- tck-suite.xml
-
false
@@ -32,6 +29,19 @@
org.eclipse.microprofile.rest.client:microprofile-rest-client-tck
+ false
+
+ **/*Test.java
+
+
+
+ org.eclipse.microprofile.rest.client.tck.WiremockArquillianTest
+ org.eclipse.microprofile.rest.client.tck.ssl.AbstractSslTest
+
+
+ org.eclipse.microprofile.rest.client.tck.cditests.HasConversationScopeTest
+ org.eclipse.microprofile.rest.client.tck.cditests.HasSessionScopeTest
+
@@ -62,6 +72,22 @@
io.quarkus
quarkus-rest-client
+
+ io.quarkus
+ quarkus-jsonp
+
+
+ org.jboss.resteasy
+ resteasy-json-p-provider
+
+
+ io.quarkus
+ quarkus-jsonb
+
+
+ org.jboss.resteasy
+ resteasy-json-binding-provider
+
org.eclipse.microprofile.rest.client
microprofile-rest-client-tck
diff --git a/tcks/microprofile-rest-client/src/test/java/io/quarkus/tck/restclient/RestClientTckExtension.java b/tcks/microprofile-rest-client/src/test/java/io/quarkus/tck/restclient/RestClientTckExtension.java
new file mode 100644
index 0000000000000..79e25e9423942
--- /dev/null
+++ b/tcks/microprofile-rest-client/src/test/java/io/quarkus/tck/restclient/RestClientTckExtension.java
@@ -0,0 +1,11 @@
+package io.quarkus.tck.restclient;
+
+import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor;
+import org.jboss.arquillian.core.spi.LoadableExtension;
+
+public class RestClientTckExtension implements LoadableExtension {
+ @Override
+ public void register(ExtensionBuilder builder) {
+ builder.service(ApplicationArchiveProcessor.class, SslArchiveProcessor.class);
+ }
+}
diff --git a/tcks/microprofile-rest-client/src/test/java/io/quarkus/tck/restclient/SkipProblematicTests.java b/tcks/microprofile-rest-client/src/test/java/io/quarkus/tck/restclient/SkipProblematicTests.java
deleted file mode 100644
index 754067d63a555..0000000000000
--- a/tcks/microprofile-rest-client/src/test/java/io/quarkus/tck/restclient/SkipProblematicTests.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package io.quarkus.tck.restclient;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.eclipse.microprofile.rest.client.tck.ClientHeaderParamTest;
-import org.eclipse.microprofile.rest.client.tck.InvokeWithJsonBProviderTest;
-import org.eclipse.microprofile.rest.client.tck.InvokeWithJsonPProviderTest;
-import org.eclipse.microprofile.rest.client.tck.asynctests.AsyncMethodTest;
-import org.testng.IAnnotationTransformer;
-import org.testng.IConfigurable;
-import org.testng.IConfigureCallBack;
-import org.testng.ITestNGMethod;
-import org.testng.ITestResult;
-import org.testng.annotations.ITestAnnotation;
-
-public class SkipProblematicTests implements IConfigurable, IAnnotationTransformer {
-
- private static final Set TESTS_THAT_THROW_CLASS_NOT_FOUND = new HashSet<>(Arrays.asList(
- InvokeWithJsonBProviderTest.class.getName(), InvokeWithJsonPProviderTest.class.getName(),
- ClientHeaderParamTest.class.getName()));
-
- private static final Set RACEY_TESTS = new HashSet<>(Arrays.asList(
- //testAsyncInvocationInterceptorProvider is racey, as there is no guarantee the
- //removeThreadId has been set by the time the test attempts to assert it, this is
- //because the removeContext action happens after the response is provided, so the
- //completion stage is complete before this method is called
- AsyncMethodTest.class.getName()));
-
- private static final Set SKIP;
-
- static {
- SKIP = new HashSet<>();
- SKIP.addAll(TESTS_THAT_THROW_CLASS_NOT_FOUND);
- SKIP.addAll(RACEY_TESTS);
- }
-
- // ensures that the methods annotated with @BeforeTest don't run (since this is where the exception is thrown)
- @Override
- public void run(IConfigureCallBack callBack, ITestResult testResult) {
- ITestNGMethod method = testResult.getMethod();
- if (SKIP.contains(method.getTestClass().getName())) {
- return;
- }
-
- callBack.runConfigurationMethod(testResult);
- }
-
- // ensures the actual tests method don't run
- @Override
- public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
- String className = testClass != null ? testClass.getName() : testMethod.getDeclaringClass().getName();
- if (SKIP.contains(className)) {
- annotation.setEnabled(false);
- }
- }
-}
diff --git a/tcks/microprofile-rest-client/src/test/java/io/quarkus/tck/restclient/SslArchiveProcessor.java b/tcks/microprofile-rest-client/src/test/java/io/quarkus/tck/restclient/SslArchiveProcessor.java
new file mode 100644
index 0000000000000..5b3b4462d0e23
--- /dev/null
+++ b/tcks/microprofile-rest-client/src/test/java/io/quarkus/tck/restclient/SslArchiveProcessor.java
@@ -0,0 +1,27 @@
+package io.quarkus.tck.restclient;
+
+import org.jboss.arquillian.container.test.spi.client.deployment.ApplicationArchiveProcessor;
+import org.jboss.arquillian.test.spi.TestClass;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+
+public class SslArchiveProcessor implements ApplicationArchiveProcessor {
+ @Override
+ public void process(Archive> applicationArchive, TestClass testClass) {
+ // Only apply the processor to SSL tests
+ if (testClass.getName().contains("SslHostnameVerifierTest") ||
+ testClass.getName().contains("SslMutualTest") ||
+ testClass.getName().contains("SslTrustStoreTest") ||
+ testClass.getName().contains("SslContextTest")) {
+
+ if (!(applicationArchive instanceof WebArchive)) {
+ return;
+ }
+
+ WebArchive war = applicationArchive.as(WebArchive.class);
+
+ war.addAsResource(new StringAsset("quarkus.ssl.native=true"), "application.properties");
+ }
+ }
+}
diff --git a/tcks/microprofile-rest-client/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension b/tcks/microprofile-rest-client/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension
new file mode 100644
index 0000000000000..9dc06350b2d4e
--- /dev/null
+++ b/tcks/microprofile-rest-client/src/test/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension
@@ -0,0 +1 @@
+io.quarkus.tck.restclient.RestClientTckExtension
\ No newline at end of file
diff --git a/tcks/microprofile-rest-client/tck-suite.xml b/tcks/microprofile-rest-client/tck-suite.xml
deleted file mode 100644
index 22fb79ea36b46..0000000000000
--- a/tcks/microprofile-rest-client/tck-suite.xml
+++ /dev/null
@@ -1,130 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusTestNgCallbacks.java b/test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusTestNgCallbacks.java
index 5f8bf4e77f7c5..5501a3211c719 100644
--- a/test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusTestNgCallbacks.java
+++ b/test-framework/arquillian/src/main/java/io/quarkus/arquillian/QuarkusTestNgCallbacks.java
@@ -9,8 +9,10 @@
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterMethod;
+import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeTest;
/**
* Note that we cannot use event.getExecutor().invoke() directly because the callbacks would be invoked upon the original test
@@ -57,6 +59,7 @@ static void invokeTestNgAfterMethods() throws IllegalAccessException, IllegalArg
if (testInstance != null) {
List afterMethods = new ArrayList<>();
collectCallbacks(testInstance.getClass(), afterMethods, AfterMethod.class);
+ collectCallbacks(testInstance.getClass(), afterMethods, AfterTest.class);
for (Method m : afterMethods) {
// we don't know the values for parameterized methods that TestNG allows, we just skip those
if (m.getParameterCount() == 0) {
@@ -72,6 +75,7 @@ static void invokeTestNgBeforeMethods() throws IllegalAccessException, IllegalAr
if (testInstance != null) {
List beforeMethods = new ArrayList<>();
collectCallbacks(testInstance.getClass(), beforeMethods, BeforeMethod.class);
+ collectCallbacks(testInstance.getClass(), beforeMethods, BeforeTest.class);
for (Method m : beforeMethods) {
// we don't know the values for parameterized methods that TestNG allows, we just skip those
if (m.getParameterCount() == 0) {