diff --git a/spring-boot-project/spring-boot-autoconfigure/pom.xml b/spring-boot-project/spring-boot-autoconfigure/pom.xml index 70f9e1349a..cd7633bb0e 100755 --- a/spring-boot-project/spring-boot-autoconfigure/pom.xml +++ b/spring-boot-project/spring-boot-autoconfigure/pom.xml @@ -957,6 +957,11 @@ cassandra test + + org.testcontainers + couchbase + test + org.testcontainers elasticsearch diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseConfiguration.java index dca5184964..cee5ec6580 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -37,6 +37,7 @@ import org.springframework.context.annotation.Primary; * Support class to configure Couchbase based on {@link CouchbaseProperties}. * * @author Stephane Nicoll + * @author Brian Clozel * @since 2.1.0 */ @Configuration @@ -76,6 +77,9 @@ public class CouchbaseConfiguration { @Primary @DependsOn("couchbaseClient") public ClusterInfo couchbaseClusterInfo() { + if (isRoleBasedAccessControlEnabled()) { + return couchbaseCluster().clusterManager().info(); + } return couchbaseCluster() .clusterManager(this.properties.getBucket().getName(), this.properties.getBucket().getPassword()) .info(); @@ -103,7 +107,14 @@ public class CouchbaseConfiguration { protected DefaultCouchbaseEnvironment.Builder initializeEnvironmentBuilder(CouchbaseProperties properties) { CouchbaseProperties.Endpoints endpoints = properties.getEnv().getEndpoints(); CouchbaseProperties.Timeouts timeouts = properties.getEnv().getTimeouts(); + CouchbaseProperties.Bootstrap bootstrap = properties.getEnv().getBootstrap(); DefaultCouchbaseEnvironment.Builder builder = DefaultCouchbaseEnvironment.builder(); + if (bootstrap.getHttpDirectPort() != null) { + builder.bootstrapHttpDirectPort(bootstrap.getHttpDirectPort()); + } + if (bootstrap.getHttpSslPort() != null) { + builder.bootstrapHttpSslPort(bootstrap.getHttpSslPort()); + } if (timeouts.getConnect() != null) { builder = builder.connectTimeout(timeouts.getConnect().toMillis()); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseProperties.java index e7080ec5af..21d548eea1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ import org.springframework.util.StringUtils; * @author EddĂș MelĂ©ndez * @author Stephane Nicoll * @author Yulin Qin + * @author Brian Clozel * @since 1.4.0 */ @ConfigurationProperties(prefix = "spring.couchbase") @@ -116,12 +117,18 @@ public class CouchbaseProperties { public static class Env { + private final Bootstrap bootstrap = new Bootstrap(); + private final Endpoints endpoints = new Endpoints(); private final Ssl ssl = new Ssl(); private final Timeouts timeouts = new Timeouts(); + public Bootstrap getBootstrap() { + return this.bootstrap; + } + public Endpoints getEndpoints() { return this.endpoints; } @@ -314,4 +321,34 @@ public class CouchbaseProperties { } + public static class Bootstrap { + + /** + * Port for the HTTP bootstrap. + */ + private Integer httpDirectPort; + + /** + * Port for the HTTPS bootstrap. + */ + private Integer httpSslPort; + + public Integer getHttpDirectPort() { + return this.httpDirectPort; + } + + public void setHttpDirectPort(Integer httpDirectPort) { + this.httpDirectPort = httpDirectPort; + } + + public Integer getHttpSslPort() { + return this.httpSslPort; + } + + public void setHttpSslPort(Integer httpSslPort) { + this.httpSslPort = httpSslPort; + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationIntegrationTests.java index d11bc5eda0..9a2549e3a0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/CouchbaseAutoConfigurationIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,17 +16,24 @@ package org.springframework.boot.autoconfigure.couchbase; +import java.time.Duration; + import com.couchbase.client.java.Bucket; import com.couchbase.client.java.Cluster; import com.couchbase.client.java.CouchbaseBucket; +import com.couchbase.client.java.bucket.BucketType; import com.couchbase.client.java.cluster.ClusterInfo; +import com.couchbase.client.java.cluster.DefaultBucketSettings; import com.couchbase.client.java.env.CouchbaseEnvironment; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; +import org.testcontainers.couchbase.CouchbaseContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -37,29 +44,53 @@ import static org.mockito.Mockito.mock; * Integration tests for {@link CouchbaseAutoConfiguration}. * * @author Stephane Nicoll + * @author Brian Clozel */ -@ExtendWith(LocalCouchbaseServer.class) +@Testcontainers(disabledWithoutDocker = true) class CouchbaseAutoConfigurationIntegrationTests { - private ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration( - AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, CouchbaseAutoConfiguration.class)); + @Container + static final CouchbaseContainer couchbase = new CouchbaseContainer().withClusterAdmin("spring", "password") + .withNewBucket(DefaultBucketSettings.builder().enableFlush(true).name("default").password("secret") + .quota(100).replicas(0).type(BucketType.COUCHBASE).build()) + .withStartupAttempts(5).withStartupTimeout(Duration.ofMinutes(2)); + + private AnnotationConfigApplicationContext context; + + @BeforeEach + void setUp() { + this.context = new AnnotationConfigApplicationContext(); + this.context.register(CouchbaseAutoConfiguration.class); + TestPropertyValues.of("spring.couchbase.bootstrap-hosts=localhost", + "spring.couchbase.env.bootstrap.http-direct-port:" + couchbase.getMappedPort(8091), + "spring.couchbase.username:spring", "spring.couchbase.password:password", + "spring.couchbase.bucket.name:default").applyTo(this.context.getEnvironment()); + } + + @AfterEach + void close() { + if (this.context != null) { + this.context.close(); + } + } @Test void defaultConfiguration() { - this.contextRunner.withPropertyValues("spring.couchbase.bootstrapHosts=localhost") - .run((context) -> assertThat(context).hasSingleBean(Cluster.class).hasSingleBean(ClusterInfo.class) - .hasSingleBean(CouchbaseEnvironment.class).hasSingleBean(Bucket.class)); + this.context.refresh(); + assertThat(this.context.getBeansOfType(Cluster.class)).hasSize(1); + assertThat(this.context.getBeansOfType(ClusterInfo.class)).hasSize(1); + assertThat(this.context.getBeansOfType(CouchbaseEnvironment.class)).hasSize(1); + assertThat(this.context.getBeansOfType(Bucket.class)).hasSize(1); } @Test void customConfiguration() { - this.contextRunner.withUserConfiguration(CustomConfiguration.class) - .withPropertyValues("spring.couchbase.bootstrapHosts=localhost").run((context) -> { - assertThat(context.getBeansOfType(Cluster.class)).hasSize(2); - assertThat(context.getBeansOfType(ClusterInfo.class)).hasSize(1); - assertThat(context.getBeansOfType(CouchbaseEnvironment.class)).hasSize(1); - assertThat(context.getBeansOfType(Bucket.class)).hasSize(2); - }); + this.context.register(CustomConfiguration.class); + this.context.refresh(); + assertThat(this.context.getBeansOfType(Cluster.class)).hasSize(2); + assertThat(this.context.getBeansOfType(ClusterInfo.class)).hasSize(1); + assertThat(this.context.getBeansOfType(CouchbaseEnvironment.class)).hasSize(1); + assertThat(this.context.getBeansOfType(Bucket.class)).hasSize(2); } @Configuration(proxyBeanMethods = false) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/LocalCouchbaseServer.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/LocalCouchbaseServer.java deleted file mode 100644 index 80103bb32c..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/couchbase/LocalCouchbaseServer.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * 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 - * - * https://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 org.springframework.boot.autoconfigure.couchbase; - -import java.util.concurrent.TimeUnit; - -import com.couchbase.client.java.Bucket; -import com.couchbase.client.java.Cluster; -import com.couchbase.client.java.CouchbaseCluster; -import com.couchbase.client.java.env.CouchbaseEnvironment; -import com.couchbase.client.java.env.DefaultCouchbaseEnvironment; -import org.junit.jupiter.api.extension.ConditionEvaluationResult; -import org.junit.jupiter.api.extension.ExecutionCondition; -import org.junit.jupiter.api.extension.Extension; -import org.junit.jupiter.api.extension.ExtensionContext; -import org.junit.jupiter.api.extension.TestExecutionExceptionHandler; - -import org.springframework.beans.factory.BeanCreationException; - -/** - * {@link Extension} for working with an optional Couchbase server. Expects a default - * {@link Bucket} with no password to be available on localhost. - * - * @author Stephane Nicoll - * @author Andy Wilkinson - */ -class LocalCouchbaseServer implements ExecutionCondition, TestExecutionExceptionHandler { - - @Override - public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { - try { - CouchbaseEnvironment environment = DefaultCouchbaseEnvironment.create(); - Cluster cluster = CouchbaseCluster.create(environment, "localhost"); - testConnection(cluster); - cluster.disconnect(); - environment.shutdownAsync(); - return ConditionEvaluationResult.enabled("Local Couchbase server available"); - } - catch (Exception ex) { - return ConditionEvaluationResult.disabled("Local Couchbase server not available"); - } - } - - private static void testConnection(Cluster cluster) { - Bucket bucket = cluster.openBucket(2, TimeUnit.SECONDS); - bucket.close(); - } - - @Override - public void handleTestExecutionException(ExtensionContext context, Throwable ex) throws Throwable { - if ((ex instanceof BeanCreationException) - && "couchbaseClient".equals(((BeanCreationException) ex).getBeanName())) { - return; - } - throw ex; - } - -}