diff --git a/deployment/pom.xml b/deployment/pom.xml index 503f1064..8ca68813 100644 --- a/deployment/pom.xml +++ b/deployment/pom.xml @@ -81,6 +81,15 @@ io.quarkus quarkus-smallrye-health-deployment + + io.quarkus + quarkus-devservices-common + + + org.testcontainers + cassandra + 1.17.6 + org.junit.jupiter junit-jupiter-api diff --git a/deployment/src/main/java/com/datastax/oss/quarkus/deployment/api/CassandraClientBuildTimeConfig.java b/deployment/src/main/java/com/datastax/oss/quarkus/deployment/api/CassandraClientBuildTimeConfig.java index d907f5a3..63498753 100644 --- a/deployment/src/main/java/com/datastax/oss/quarkus/deployment/api/CassandraClientBuildTimeConfig.java +++ b/deployment/src/main/java/com/datastax/oss/quarkus/deployment/api/CassandraClientBuildTimeConfig.java @@ -101,4 +101,11 @@ public class CassandraClientBuildTimeConfig { /** The classes of {@link SchemaChangeListener} implementations to register. */ @ConfigItem(name = "schema-change-listeners") public Optional> schemaChangeListeners; + + /** + * Configuration for DevServices. DevServices allows Quarkus to automatically start a Cassandra in + * dev and test mode. + */ + @ConfigItem(name = "devservices") + public CassandraDevServicesBuildTimeConfig devservices; } diff --git a/deployment/src/main/java/com/datastax/oss/quarkus/deployment/api/CassandraDevServicesBuildTimeConfig.java b/deployment/src/main/java/com/datastax/oss/quarkus/deployment/api/CassandraDevServicesBuildTimeConfig.java new file mode 100644 index 00000000..070da48a --- /dev/null +++ b/deployment/src/main/java/com/datastax/oss/quarkus/deployment/api/CassandraDevServicesBuildTimeConfig.java @@ -0,0 +1,77 @@ +/* + * Copyright DataStax, Inc. + * + * 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 com.datastax.oss.quarkus.deployment.api; + +import io.quarkus.runtime.annotations.ConfigGroup; +import io.quarkus.runtime.annotations.ConfigItem; +import java.util.Optional; +import java.util.OptionalInt; + +/** This class provides dev services configuration for Cassandra. */ +@ConfigGroup +public class CassandraDevServicesBuildTimeConfig { + + /** + * If Dev Services for Cassandra has been explicitly enabled or disabled. Dev Services are + * generally enabled by default, unless there is an existing configuration present. For Cassandra, + * Dev Services starts an instance unless {@code quarkus.cassnadra.contact-points} has been + * configured. + */ + @ConfigItem public Optional enabled = Optional.empty(); + + /** + * Optional fixed port the dev service will listen to. + * + *

If not defined, the port will be chosen randomly. + */ + @ConfigItem public OptionalInt port; + + /** The image to use. */ + @ConfigItem(defaultValue = "cassandra:latest") + public String imageName; + + /** + * Indicates if the Cassandra instance managed by Quarkus Dev Services is shared. When shared, + * Quarkus looks for running containers using label-based service discovery. If a matching + * container is found, it is used, and so a second one is not started. Otherwise, Dev Services for + * Cassandra starts a new container. + * + *

The discovery uses the {@code quarkus-dev-service-cassandra} label. The value is configured + * using the {@code service-name} property. + * + *

Container sharing is only used in dev mode. + */ + @ConfigItem(defaultValue = "true") + public boolean shared; + + /** + * The value of the {@code quarkus-dev-service-cassandra} label attached to the started container. + * This property is used when {@code shared} is set to {@code true}. In this case, before starting + * a container, Dev Services for Cassandra looks for a container with the {@code + * quarkus-dev-service-cassandra} label set to the configured value. If found, it will use this + * container instead of starting a new one. Otherwise, it starts a new container with the {@code + * quarkus-dev-service-cassandra} label set to the specified value. + * + *

This property is used when you need multiple shared Cassandra. + */ + @ConfigItem(defaultValue = "cassandra") + public String serviceName; + + /** Init script (starting with creation of keyspace(s)) for Cassandra */ + @ConfigItem(name = "init-script") + public Optional initScript; +} diff --git a/deployment/src/main/java/com/datastax/oss/quarkus/deployment/api/CassandraDevServicesProcessor.java b/deployment/src/main/java/com/datastax/oss/quarkus/deployment/api/CassandraDevServicesProcessor.java new file mode 100644 index 00000000..4c726358 --- /dev/null +++ b/deployment/src/main/java/com/datastax/oss/quarkus/deployment/api/CassandraDevServicesProcessor.java @@ -0,0 +1,304 @@ +/* + * Copyright DataStax, Inc. + * + * 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 com.datastax.oss.quarkus.deployment.api; + +import io.quarkus.bootstrap.classloading.QuarkusClassLoader; +import io.quarkus.deployment.IsNormal; +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.annotations.BuildSteps; +import io.quarkus.deployment.builditem.DevServicesResultBuildItem; +import io.quarkus.deployment.builditem.DevServicesResultBuildItem.RunningDevService; +import io.quarkus.deployment.builditem.DockerStatusBuildItem; +import io.quarkus.deployment.builditem.LaunchModeBuildItem; +import io.quarkus.deployment.console.ConsoleInstalledBuildItem; +import io.quarkus.deployment.console.StartupLogCompressor; +import io.quarkus.deployment.dev.devservices.GlobalDevServicesConfig; +import io.quarkus.deployment.logging.LoggingSetupBuildItem; +import io.quarkus.devservices.common.ContainerLocator; +import io.quarkus.runtime.LaunchMode; +import java.io.Closeable; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Supplier; +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; +import org.eclipse.microprofile.config.ConfigValue; +import org.jboss.logging.Logger; +import org.testcontainers.containers.CassandraContainer; +import org.testcontainers.containers.Network; +import org.testcontainers.utility.DockerImageName; + +@BuildSteps(onlyIfNot = IsNormal.class, onlyIf = GlobalDevServicesConfig.Enabled.class) +public class CassandraDevServicesProcessor { + private static final Logger log = Logger.getLogger(CassandraDevServicesProcessor.class); + + private static final String DEV_SERVICE_LABEL = "quarkus-dev-service-cassandra"; + + private static final int CASSANDRA_PORT = 9042; + + private static final ContainerLocator cassandraContainerLocator = + new ContainerLocator(DEV_SERVICE_LABEL, CASSANDRA_PORT); + static volatile RunningDevService devService; + static volatile CassandraDevServiceCfg cfg; + static volatile boolean first = true; + + @BuildStep + public DevServicesResultBuildItem startCassandraDevService( + DockerStatusBuildItem dockerStatusBuildItem, + LaunchModeBuildItem launchMode, + CassandraClientBuildTimeConfig cassandraClientBuildTimeConfig, + Optional consoleInstalledBuildItem, + LoggingSetupBuildItem loggingSetupBuildItem, + GlobalDevServicesConfig devServicesConfig) { + + CassandraDevServiceCfg configuration = getConfiguration(cassandraClientBuildTimeConfig); + + if (devService != null) { + boolean shouldShutdownTheCassandra = !configuration.equals(cfg); + if (!shouldShutdownTheCassandra) { + return devService.toBuildItem(); + } + shutdownCassandra(); + cfg = null; + } + + StartupLogCompressor compressor = + new StartupLogCompressor( + (launchMode.isTest() ? "(test) " : "") + "Cassandra Dev Services Starting:", + consoleInstalledBuildItem, + loggingSetupBuildItem); + try { + DevServicesResultBuildItem.RunningDevService newDevService = + startCassandra( + dockerStatusBuildItem, configuration, launchMode, devServicesConfig.timeout); + if (newDevService != null) { + devService = newDevService; + + Map config = devService.getConfig(); + if (devService.isOwner()) { + log.info("Dev Services for Cassandra started."); + } + } + if (devService == null) { + compressor.closeAndDumpCaptured(); + } else { + compressor.close(); + } + } catch (Throwable t) { + compressor.closeAndDumpCaptured(); + throw new RuntimeException(t); + } + + if (devService == null) { + return null; + } + + // Configure the watch dog + if (first) { + first = false; + Runnable closeTask = + () -> { + if (devService != null) { + shutdownCassandra(); + + log.info("Dev Services for Cassandra shut down."); + } + first = true; + devService = null; + cfg = null; + }; + QuarkusClassLoader cl = (QuarkusClassLoader) Thread.currentThread().getContextClassLoader(); + ((QuarkusClassLoader) cl.parent()).addCloseTask(closeTask); + } + cfg = configuration; + return devService.toBuildItem(); + } + + private void shutdownCassandra() { + if (devService != null) { + try { + devService.close(); + } catch (Throwable e) { + log.error("Failed to stop the Cassandra", e); + } finally { + devService = null; + } + } + } + + private DevServicesResultBuildItem.RunningDevService startCassandra( + DockerStatusBuildItem dockerStatusBuildItem, + CassandraDevServiceCfg config, + LaunchModeBuildItem launchMode, + Optional timeout) { + if (!config.devServicesEnabled) { + // explicitly disabled + log.debug("Not starting Dev Services for Cassandra, as it has been disabled in the config."); + return null; + } + + // Verify that we have Cassandra without contact points + if (!hasCassandraContactPointsWithoutHostAndPort()) { + log.debug("Not starting Dev Services for Cassandra, all the channels are configured."); + return null; + } + + if (!dockerStatusBuildItem.isDockerAvailable()) { + log.warn("Docker isn't working, please configure the Cassandra location."); + return null; + } + + ConfiguredCassandraContainer container = + new ConfiguredCassandraContainer( + DockerImageName.parse(config.imageName).asCompatibleSubstituteFor("cassandra"), + config.fixedExposedPort, + launchMode.getLaunchMode() == LaunchMode.DEVELOPMENT ? config.serviceName : null, + config.initScript); + + final Supplier defaultCassandraSupplier = + () -> { + + // Starting cassandra + timeout.ifPresent(container::withStartupTimeout); + container.start(); + return getRunningDevService( + container.getContainerId(), + container::close, + container.getHost(), + container.getPort()); + }; + + return cassandraContainerLocator + .locateContainer(config.serviceName, config.shared, launchMode.getLaunchMode()) + .map( + containerAddress -> + getRunningDevService( + containerAddress.getId(), + null, + containerAddress.getHost(), + containerAddress.getPort())) + .orElseGet(defaultCassandraSupplier); + } + + private boolean hasCassandraContactPointsWithoutHostAndPort() { + Config config = ConfigProvider.getConfig(); + // TODO: support for named connections? + // TODO: refactor validation of contact points + // for (String name : config.getPropertyNames()) { + // if (name.equals("quarkus.cassandra.contact-points") + // && config.getValue(name, String.class).isBlank()) { + // return true; + // } + // } + ConfigValue configValue = config.getConfigValue("quarkus.cassandra.contact-points"); + return configValue.getValue() == null || configValue.getValue().isBlank(); + } + + private DevServicesResultBuildItem.RunningDevService getRunningDevService( + String containerId, Closeable closeable, String host, int port) { + Map configMap = new HashMap<>(); + configMap.putIfAbsent("quarkus.cassandra.contact-points", String.format("%s:%d", host, port)); + configMap.putIfAbsent("quarkus.cassandra.local-datacenter", "datacenter1"); + return new DevServicesResultBuildItem.RunningDevService( + "CASSANDRA", containerId, closeable, configMap); + } + + private CassandraDevServiceCfg getConfiguration(CassandraClientBuildTimeConfig cfg) { + CassandraDevServicesBuildTimeConfig devServicesConfig = cfg.devservices; + return new CassandraDevServiceCfg(devServicesConfig); + } + + private static final class CassandraDevServiceCfg { + + private final boolean devServicesEnabled; + private final String imageName; + private final Integer fixedExposedPort; + private final boolean shared; + private final String serviceName; + + private final String initScript; + + public CassandraDevServiceCfg(CassandraDevServicesBuildTimeConfig devServicesConfig) { + this.devServicesEnabled = devServicesConfig.enabled.orElse(true); + this.imageName = devServicesConfig.imageName; + this.fixedExposedPort = devServicesConfig.port.orElse(0); + this.shared = devServicesConfig.shared; + this.serviceName = devServicesConfig.serviceName; + this.initScript = devServicesConfig.initScript.orElse(null); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CassandraDevServiceCfg that = (CassandraDevServiceCfg) o; + return devServicesEnabled == that.devServicesEnabled + && Objects.equals(imageName, that.imageName) + && Objects.equals(fixedExposedPort, that.fixedExposedPort); + } + + @Override + public int hashCode() { + return Objects.hash(devServicesEnabled, imageName, fixedExposedPort); + } + } + + private static final class ConfiguredCassandraContainer + extends CassandraContainer { + + private final int port; + + private ConfiguredCassandraContainer( + DockerImageName dockerImageName, + int fixedExposedPort, + String serviceName, + String initScript) { + super(dockerImageName); + this.port = fixedExposedPort; + withExposedPorts(CASSANDRA_PORT); + if (initScript != null) { + withInitScript(initScript); + } + withNetwork(Network.SHARED); + if (serviceName != null) { // Only adds the label in dev mode. + withLabel(DEV_SERVICE_LABEL, serviceName); + } + if (!dockerImageName.getRepository().endsWith("cassandra")) { + throw new IllegalArgumentException("Only official cassandra images are supported"); + } + } + + @Override + protected void configure() { + super.configure(); + if (port > 0) { + addFixedExposedPort(port, CASSANDRA_PORT); + } + } + + public int getPort() { + return getMappedPort(CASSANDRA_PORT); + } + } +} diff --git a/integration-tests/devservices/pom.xml b/integration-tests/devservices/pom.xml new file mode 100644 index 00000000..0f6fb5f2 --- /dev/null +++ b/integration-tests/devservices/pom.xml @@ -0,0 +1,105 @@ + + + + 4.0.0 + + com.datastax.oss.quarkus + cassandra-quarkus-integration-tests + 1.1.4-SNAPSHOT + + cassandra-quarkus-integration-tests-devservices + Cassandra Quarkus :: IT :: Devservices + + + + com.datastax.oss.quarkus + cassandra-quarkus-client + + + io.quarkus + quarkus-resteasy + + + io.quarkus + quarkus-resteasy-jsonb + + + + io.quarkus + quarkus-test-common + test + + + com.datastax.oss.quarkus + cassandra-quarkus-test-framework + test + + + io.quarkus + quarkus-junit5 + test + + + org.assertj + assertj-core + test + + + io.rest-assured + rest-assured + test + + + + + + maven-compiler-plugin + + + + maven-jar-plugin + + + + javadoc-jar + package + + jar + + + javadoc + + ** + + + + + test-jar + + test-jar + + + + + + + diff --git a/integration-tests/devservices/src/main/java/com/datastax/oss/quarkus/tests/entity/Product.java b/integration-tests/devservices/src/main/java/com/datastax/oss/quarkus/tests/entity/Product.java new file mode 100644 index 00000000..dd03c71b --- /dev/null +++ b/integration-tests/devservices/src/main/java/com/datastax/oss/quarkus/tests/entity/Product.java @@ -0,0 +1,71 @@ +/* + * Copyright DataStax, Inc. + * + * 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 com.datastax.oss.quarkus.tests.entity; + +import java.util.Objects; +import java.util.UUID; + +public class Product { + + private UUID id; + + private String name; + + public Product() {} + + public Product(UUID id, String name) { + this.id = id; + this.name = name; + } + + public UUID getId() { + return id; + } + + public void setId(UUID id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof Product)) { + return false; + } + Product product = (Product) o; + return id.equals(product.id) && name.equals(product.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } + + @Override + public String toString() { + return "Product{id=" + id + ", name='" + name + "'}"; + } +} diff --git a/integration-tests/devservices/src/main/java/com/datastax/oss/quarkus/tests/resource/ProductResource.java b/integration-tests/devservices/src/main/java/com/datastax/oss/quarkus/tests/resource/ProductResource.java new file mode 100644 index 00000000..c4c79785 --- /dev/null +++ b/integration-tests/devservices/src/main/java/com/datastax/oss/quarkus/tests/resource/ProductResource.java @@ -0,0 +1,54 @@ +/* + * Copyright DataStax, Inc. + * + * 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 com.datastax.oss.quarkus.tests.resource; + +import com.datastax.oss.driver.api.core.AsyncPagingIterable; +import com.datastax.oss.driver.api.core.cql.SimpleStatement; +import com.datastax.oss.quarkus.runtime.api.session.QuarkusCqlSession; +import com.datastax.oss.quarkus.tests.entity.Product; +import java.util.UUID; +import java.util.concurrent.CompletionStage; +import javax.inject.Inject; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; + +@Path("/product") +public class ProductResource { + + @Inject QuarkusCqlSession session; + + @GET + @Path("/{id}") + @Produces(MediaType.APPLICATION_JSON) + public CompletionStage getProduct(@PathParam("id") UUID id) { + return session + .executeAsync(SimpleStatement.newInstance("SELECT id, name FROM product WHERE id = ?", id)) + .thenApply(AsyncPagingIterable::one) + .thenApply( + row -> { + if (row == null) { + return Response.status(Status.NOT_FOUND).build(); + } else { + return Response.ok(new Product(row.getUuid(0), row.getString(1))).build(); + } + }); + } +} diff --git a/integration-tests/devservices/src/main/resources/application.properties b/integration-tests/devservices/src/main/resources/application.properties new file mode 100644 index 00000000..d52be90a --- /dev/null +++ b/integration-tests/devservices/src/main/resources/application.properties @@ -0,0 +1,30 @@ +# +# Copyright DataStax, Inc. +# +# 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. +# + +quarkus.cassandra.keyspace=ks1 + +quarkus.cassandra.devservices.enabled=true + +quarkus.cassandra.devservices.init-script=init_script.cql + +#quarkus.log.level=DEBUG +#quarkus.log.min-level=DEBUG +#quarkus.log.category."com.datastax.oss.quarkus".level=DEBUG +#quarkus.log.category."com.datastax.oss.driver".level=DEBUG +#quarkus.log.category."com.datastax.dse.driver".level=INFO +quarkus.log.category."org.testcontainers".level=WARN +quarkus.log.category."com.github.dockerjava".level=WARN +quarkus.log.category."com.datastax.driver".level=ERROR diff --git a/integration-tests/devservices/src/main/resources/init_script.cql b/integration-tests/devservices/src/main/resources/init_script.cql new file mode 100644 index 00000000..8280a221 --- /dev/null +++ b/integration-tests/devservices/src/main/resources/init_script.cql @@ -0,0 +1,10 @@ +CREATE KEYSPACE IF NOT EXISTS ks1 + WITH replication = {'class':'SimpleStrategy', 'replication_factor':1}; + +CREATE TABLE IF NOT EXISTS ks1.product +( + id uuid PRIMARY KEY, + name text +); + +INSERT INTO ks1.product (id, name) VALUES (00000000-0000-0000-0000-000000000001, 'product1'); \ No newline at end of file diff --git a/integration-tests/devservices/src/test/java/com/datastax/oss/quarkus/tests/ProductResourceIT.java b/integration-tests/devservices/src/test/java/com/datastax/oss/quarkus/tests/ProductResourceIT.java new file mode 100644 index 00000000..fa5954ff --- /dev/null +++ b/integration-tests/devservices/src/test/java/com/datastax/oss/quarkus/tests/ProductResourceIT.java @@ -0,0 +1,49 @@ +/* + * Copyright DataStax, Inc. + * + * 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 com.datastax.oss.quarkus.tests; + +import static io.restassured.RestAssured.when; +import static org.assertj.core.api.Assertions.assertThat; + +import com.datastax.oss.quarkus.test.CassandraTestResource; +import com.datastax.oss.quarkus.tests.entity.Product; +import io.quarkus.test.common.QuarkusTestResource; +import io.quarkus.test.junit.QuarkusTest; +import io.restassured.http.ContentType; +import java.util.UUID; +import javax.ws.rs.core.Response.Status; +import org.junit.jupiter.api.Test; + +@QuarkusTest +@QuarkusTestResource(CassandraTestResource.class) +public class ProductResourceIT { + + @Test + public void should_create_and_retrieve_product() { + Product expected = + new Product(UUID.fromString("00000000-0000-0000-0000-000000000001"), "product1"); + Product actual = + when() + .get("/product/{id}", expected.getId()) + .then() + .contentType(ContentType.JSON) + .statusCode(Status.OK.getStatusCode()) + .extract() + .body() + .as(Product.class); + assertThat(actual).isEqualTo(expected); + } +} diff --git a/integration-tests/devservices/src/test/java/com/datastax/oss/quarkus/tests/ProductResourceNativeIT.java b/integration-tests/devservices/src/test/java/com/datastax/oss/quarkus/tests/ProductResourceNativeIT.java new file mode 100644 index 00000000..4463cd07 --- /dev/null +++ b/integration-tests/devservices/src/test/java/com/datastax/oss/quarkus/tests/ProductResourceNativeIT.java @@ -0,0 +1,23 @@ +/* + * Copyright DataStax, Inc. + * + * 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 com.datastax.oss.quarkus.tests; + +import io.quarkus.test.junit.QuarkusIntegrationTest; +import org.junit.jupiter.api.Tag; + +@QuarkusIntegrationTest +@Tag("native") +public class ProductResourceNativeIT extends ProductResourceIT {} diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index adfd8bf2..22b96e1e 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -36,6 +36,7 @@ metrics-microprofile metrics-disabled no-mapper + devservices