Commit c2f8741e authored by Brian Clozel's avatar Brian Clozel

Merge branch '2.2.x'

Closes gh-19517
parents 76a48885 1320c44a
...@@ -957,6 +957,11 @@ ...@@ -957,6 +957,11 @@
<artifactId>cassandra</artifactId> <artifactId>cassandra</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>couchbase</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.testcontainers</groupId> <groupId>org.testcontainers</groupId>
<artifactId>elasticsearch</artifactId> <artifactId>elasticsearch</artifactId>
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -37,6 +37,7 @@ import org.springframework.context.annotation.Primary; ...@@ -37,6 +37,7 @@ import org.springframework.context.annotation.Primary;
* Support class to configure Couchbase based on {@link CouchbaseProperties}. * Support class to configure Couchbase based on {@link CouchbaseProperties}.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Brian Clozel
* @since 2.1.0 * @since 2.1.0
*/ */
@Configuration @Configuration
...@@ -76,6 +77,9 @@ public class CouchbaseConfiguration { ...@@ -76,6 +77,9 @@ public class CouchbaseConfiguration {
@Primary @Primary
@DependsOn("couchbaseClient") @DependsOn("couchbaseClient")
public ClusterInfo couchbaseClusterInfo() { public ClusterInfo couchbaseClusterInfo() {
if (isRoleBasedAccessControlEnabled()) {
return couchbaseCluster().clusterManager().info();
}
return couchbaseCluster() return couchbaseCluster()
.clusterManager(this.properties.getBucket().getName(), this.properties.getBucket().getPassword()) .clusterManager(this.properties.getBucket().getName(), this.properties.getBucket().getPassword())
.info(); .info();
...@@ -103,7 +107,14 @@ public class CouchbaseConfiguration { ...@@ -103,7 +107,14 @@ public class CouchbaseConfiguration {
protected DefaultCouchbaseEnvironment.Builder initializeEnvironmentBuilder(CouchbaseProperties properties) { protected DefaultCouchbaseEnvironment.Builder initializeEnvironmentBuilder(CouchbaseProperties properties) {
CouchbaseProperties.Endpoints endpoints = properties.getEnv().getEndpoints(); CouchbaseProperties.Endpoints endpoints = properties.getEnv().getEndpoints();
CouchbaseProperties.Timeouts timeouts = properties.getEnv().getTimeouts(); CouchbaseProperties.Timeouts timeouts = properties.getEnv().getTimeouts();
CouchbaseProperties.Bootstrap bootstrap = properties.getEnv().getBootstrap();
DefaultCouchbaseEnvironment.Builder builder = DefaultCouchbaseEnvironment.builder(); 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) { if (timeouts.getConnect() != null) {
builder = builder.connectTimeout(timeouts.getConnect().toMillis()); builder = builder.connectTimeout(timeouts.getConnect().toMillis());
} }
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -28,6 +28,7 @@ import org.springframework.util.StringUtils; ...@@ -28,6 +28,7 @@ import org.springframework.util.StringUtils;
* @author Eddú Meléndez * @author Eddú Meléndez
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Yulin Qin * @author Yulin Qin
* @author Brian Clozel
* @since 1.4.0 * @since 1.4.0
*/ */
@ConfigurationProperties(prefix = "spring.couchbase") @ConfigurationProperties(prefix = "spring.couchbase")
...@@ -116,12 +117,18 @@ public class CouchbaseProperties { ...@@ -116,12 +117,18 @@ public class CouchbaseProperties {
public static class Env { public static class Env {
private final Bootstrap bootstrap = new Bootstrap();
private final Endpoints endpoints = new Endpoints(); private final Endpoints endpoints = new Endpoints();
private final Ssl ssl = new Ssl(); private final Ssl ssl = new Ssl();
private final Timeouts timeouts = new Timeouts(); private final Timeouts timeouts = new Timeouts();
public Bootstrap getBootstrap() {
return this.bootstrap;
}
public Endpoints getEndpoints() { public Endpoints getEndpoints() {
return this.endpoints; return this.endpoints;
} }
...@@ -314,4 +321,34 @@ public class CouchbaseProperties { ...@@ -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;
}
}
} }
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -16,17 +16,24 @@ ...@@ -16,17 +16,24 @@
package org.springframework.boot.autoconfigure.couchbase; package org.springframework.boot.autoconfigure.couchbase;
import java.time.Duration;
import com.couchbase.client.java.Bucket; import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.Cluster; import com.couchbase.client.java.Cluster;
import com.couchbase.client.java.CouchbaseBucket; 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.ClusterInfo;
import com.couchbase.client.java.cluster.DefaultBucketSettings;
import com.couchbase.client.java.env.CouchbaseEnvironment; 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.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.test.util.TestPropertyValues;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
...@@ -37,29 +44,53 @@ import static org.mockito.Mockito.mock; ...@@ -37,29 +44,53 @@ import static org.mockito.Mockito.mock;
* Integration tests for {@link CouchbaseAutoConfiguration}. * Integration tests for {@link CouchbaseAutoConfiguration}.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Brian Clozel
*/ */
@ExtendWith(LocalCouchbaseServer.class) @Testcontainers(disabledWithoutDocker = true)
class CouchbaseAutoConfigurationIntegrationTests { class CouchbaseAutoConfigurationIntegrationTests {
private ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration( @Container
AutoConfigurations.of(PropertyPlaceholderAutoConfiguration.class, CouchbaseAutoConfiguration.class)); 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 @Test
void defaultConfiguration() { void defaultConfiguration() {
this.contextRunner.withPropertyValues("spring.couchbase.bootstrapHosts=localhost") this.context.refresh();
.run((context) -> assertThat(context).hasSingleBean(Cluster.class).hasSingleBean(ClusterInfo.class) assertThat(this.context.getBeansOfType(Cluster.class)).hasSize(1);
.hasSingleBean(CouchbaseEnvironment.class).hasSingleBean(Bucket.class)); 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 @Test
void customConfiguration() { void customConfiguration() {
this.contextRunner.withUserConfiguration(CustomConfiguration.class) this.context.register(CustomConfiguration.class);
.withPropertyValues("spring.couchbase.bootstrapHosts=localhost").run((context) -> { this.context.refresh();
assertThat(context.getBeansOfType(Cluster.class)).hasSize(2); assertThat(this.context.getBeansOfType(Cluster.class)).hasSize(2);
assertThat(context.getBeansOfType(ClusterInfo.class)).hasSize(1); assertThat(this.context.getBeansOfType(ClusterInfo.class)).hasSize(1);
assertThat(context.getBeansOfType(CouchbaseEnvironment.class)).hasSize(1); assertThat(this.context.getBeansOfType(CouchbaseEnvironment.class)).hasSize(1);
assertThat(context.getBeansOfType(Bucket.class)).hasSize(2); assertThat(this.context.getBeansOfType(Bucket.class)).hasSize(2);
});
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
......
/*
* 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;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment