DATACOUCH-322 - Add RBAC username and password support

Motivation
----------
Couchbase server 5.0 allows role based access control and this allows
for users to be created and granted access to use bucket. Expose this
feature in SDC.

Changes
-------
1. Couchbase configurations allow for user name to be set. The user password
property is still retrieved from bucket password property.
2. CouchbaseFactoryBean has additional constructor for the username
property.
3. Couchbase bucket schema for xml configurations also includes username
property.
4. Integration tests have been restructured majorly to accomadate for
username
    - Testcontainers are used to allow for container based testing.
    - Container based testing is optional, it can be configured using
      resources/server.properties

Results
-------
The RBAC change has been tested with pre 5.0 and 5.0+ versions using
containers. The tests pass.

Original pull request: #158.
This commit is contained in:
Subhashni Balakrishnan
2018-02-13 16:29:05 -08:00
parent 039e106032
commit 0960f11a9c
61 changed files with 520 additions and 185 deletions

View File

@@ -20,6 +20,10 @@ Server as a document database and cache while retaining store-specific features
of Spring Data Couchbase are a POJO centric model for interacting with a Couchbase Server Bucket and easily writing a
repository style data access layer.
Integration tests require a couchbase server with a bucket name "protected" with "password" as the password set.
If the server allows users, then an user with username "protected" with "password" as the password should also be set.
The recommended way to run tests is to install docker and use container in server.properties.
## Getting Help
For a comprehensive treatment of all the Spring Data Couchbase features, please refer to:

View File

@@ -112,6 +112,13 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<version>1.6.0</version>
<scope>test</scope>
</dependency>
<!-- JSR 303 Validation -->
<dependency>
<groupId>javax.validation</groupId>

View File

@@ -0,0 +1,20 @@
package org.springframework.data.couchbase;
import org.junit.ClassRule;
import org.junit.runners.model.InitializationError;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* This runner initializes container for the container based testing.
*
* @author Subhashni Balakrishnan
*/
public class ContainerResourceRunner extends SpringJUnit4ClassRunner {
@ClassRule
public static final TestContainerResource resource = TestContainerResource.getResource();
public ContainerResourceRunner(Class<?> clazz) throws InitializationError {
super(clazz);
}
}

View File

@@ -0,0 +1,46 @@
package org.springframework.data.couchbase;
import java.util.concurrent.Callable;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
/**
* Helper to check if the Couchbase http endpoints are up.
*/
public class CouchbaseHttpPortListeningCheck implements Callable<Boolean> {
private final int port;
private final String path;
public CouchbaseHttpPortListeningCheck(int port, String path) {
this.port = port;
this.path = path;
}
private Boolean executeRequest(URIBuilder builder) throws Exception {
try {
HttpGet request = new HttpGet(builder.build());
HttpClient client = HttpClientBuilder.create().build();
HttpResponse response = client.execute(request);
int status = response.getStatusLine().getStatusCode();
if (status < 200 || status >= 300) {
return false;
}
return true;
} catch (Exception ex) {
Thread.sleep(1000);
throw ex;
}
}
@Override
public Boolean call() throws Exception {
URIBuilder builder = new URIBuilder();
builder.setScheme("http").setHost("localhost").setPort(this.port).setPath(this.path);
return executeRequest(builder);
}
}

View File

@@ -0,0 +1,123 @@
package org.springframework.data.couchbase;
import static java.time.temporal.ChronoUnit.SECONDS;
import java.time.Duration;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import com.couchbase.client.java.util.features.Version;
import org.rnorth.ducttape.ratelimits.RateLimiterBuilder;
import org.rnorth.ducttape.unreliables.Unreliables;
import org.testcontainers.containers.Container;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.WaitStrategy;
/**
* WaitStrategy for Couchbase containers which makes the Server node is
* initialized, RBAC user and default bucket is created.
*/
public class CouchbaseWaitStrategy implements WaitStrategy {
private Duration startupTimeout = Duration.of(60, SECONDS);
private final Boolean rbacEnabled;
public CouchbaseWaitStrategy(String serverVersion) {
Version version = Version.parseVersion(serverVersion);
rbacEnabled = version.major() >= 5;
}
private void checkResult(Container.ExecResult result, String command) throws Exception {
if (!result.getStdout().contains("SUCCESS")) {
throw new Exception(command + " command failed");
}
}
private void checkService(int port, String path) {
Callable<Boolean> externalCheck = new CouchbaseHttpPortListeningCheck(port, path);
Unreliables.retryUntilSuccess((int) startupTimeout.getSeconds(), TimeUnit.SECONDS, () ->
externalCheck.call());
}
@Override
public void waitUntilReady(GenericContainer container) {
try {
checkService(8091, "/pools");
Container.ExecResult result;
if (rbacEnabled) {
result = container.execInContainer("/opt/couchbase/bin/couchbase-cli",
"cluster-init",
"--cluster=127.0.0.1:8091",
"--services=data,index,query",
"--cluster-name=localcontainer",
"--cluster-username=Administrator",
"--cluster-password=password",
"--cluster-ramsize=512",
"--cluster-index-ramsize=512",
"--index-storage-setting=default");
checkResult(result, "Cluster init");
result = container.execInContainer("/opt/couchbase/bin/couchbase-cli",
"user-manage",
"--cluster=127.0.0.1:8091",
"--username=Administrator",
"--password=password",
"--set",
"--rbac-username=protected",
"--rbac-password=password",
"--rbac-name=default",
"--roles=admin",
"--auth-domain=local");
checkResult(result, "User manage");
result = container.execInContainer("/opt/couchbase/bin/couchbase-cli",
"bucket-create",
"--cluster=127.0.0.1:8091",
"--username=Administrator",
"--password=password",
"--bucket=protected",
"--bucket-type=couchbase",
"--bucket-ramsize=200",
"--enable-flush=1",
"--wait");
} else {
result = container.execInContainer("/opt/couchbase/bin/couchbase-cli",
"cluster-init",
"--cluster=127.0.0.1:8091",
"--services=data,index,query",
"-u",
"Administrator",
"-p",
"password",
"--cluster-ramsize=512",
"--cluster-index-ramsize=512",
"--index-storage-setting=default");
checkResult(result, "Cluster init");
result = container.execInContainer("/opt/couchbase/bin/couchbase-cli",
"bucket-create",
"--cluster=127.0.0.1:8091",
"-u",
"Administrator",
"-p",
"password",
"--bucket=protected",
"--bucket-password=password",
"--bucket-type=couchbase",
"--bucket-ramsize=200",
"--enable-flush=1",
"--wait");
}
checkResult(result, "Bucket create");
checkService(8093, "/query/ping");
} catch (Exception ex) {
ex.printStackTrace();
System.exit(1);
}
}
@Override
public WaitStrategy withStartupTimeout(Duration startupTimeout) {
this.startupTimeout = startupTimeout;
return this;
}
}

View File

@@ -6,10 +6,8 @@ import java.util.List;
import com.couchbase.client.java.env.CouchbaseEnvironment;
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
import org.springframework.data.couchbase.config.CouchbaseConfigurer;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
@@ -20,35 +18,31 @@ import org.springframework.data.couchbase.repository.support.IndexManager;
@Configuration
public class IntegrationTestApplicationConfig extends AbstractCouchbaseConfiguration {
@Autowired
private Environment springEnv;
@Bean
public String couchbaseAdminUser() {
return springEnv.getProperty("couchbase.adminUser", "Administrator");
return "Administrator";
}
@Bean
public String couchbaseAdminPassword() {
return springEnv.getProperty("couchbase.adminUser", "password");
return "password";
}
@Override
protected List<String> getBootstrapHosts() {
return Collections.singletonList(springEnv.getProperty("couchbase.host", "127.0.0.1"));
return Collections.singletonList("127.0.0.1");
}
@Override
protected String getBucketName() {
return springEnv.getProperty("couchbase.bucket", "default");
return "protected";
}
@Override
protected String getBucketPassword() {
return springEnv.getProperty("couchbase.password", "");
return "password";
}
//TODO maybe create the bucket if doesn't exist
@Override

View File

@@ -2,9 +2,7 @@ package org.springframework.data.couchbase;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
import org.springframework.data.couchbase.config.CouchbaseConfigurer;
@@ -15,41 +13,38 @@ import org.springframework.data.couchbase.config.CouchbaseConfigurer;
*/
public class IntegrationTestNoShutdownApplicationConfig extends AbstractCouchbaseConfiguration {
@Autowired
private Environment springEnv;
@Bean
public String couchbaseAdminUser() {
return "Administrator";
}
@Bean
public String couchbaseAdminUser() {
return springEnv.getProperty("couchbase.adminUser", "Administrator");
}
@Bean
public String couchbaseAdminPassword() {
return "password";
}
@Bean
public String couchbaseAdminPassword() {
return springEnv.getProperty("couchbase.adminUser", "password");
}
@Override
protected List<String> getBootstrapHosts() {
return Collections.singletonList("127.0.0.1");
}
@Override
protected List<String> getBootstrapHosts() {
return Collections.singletonList(springEnv.getProperty("couchbase.host", "127.0.0.1"));
}
@Override
protected String getBucketName() {
return "protected";
}
@Override
protected String getBucketName() {
return springEnv.getProperty("couchbase.bucket", "default");
}
@Override
protected String getBucketPassword() {
return "password";
}
@Override
protected String getBucketPassword() {
return springEnv.getProperty("couchbase.password", "");
}
@Override
protected boolean isEnvironmentManagedBySpring() {
return false;
}
@Override
protected boolean isEnvironmentManagedBySpring() {
return false;
}
@Override
protected CouchbaseConfigurer couchbaseConfigurer() {
return this;
}
@Override
protected CouchbaseConfigurer couchbaseConfigurer() {
return this;
}
}

View File

@@ -6,10 +6,8 @@ import java.util.List;
import com.couchbase.client.java.env.CouchbaseEnvironment;
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.couchbase.config.AbstractReactiveCouchbaseConfiguration;
import org.springframework.data.couchbase.core.RxJavaCouchbaseTemplate;
import org.springframework.data.couchbase.core.WriteResultChecking;
@@ -19,32 +17,29 @@ import org.springframework.data.couchbase.repository.support.IndexManager;
@Configuration
public class ReactiveIntegrationTestApplicationConfig extends AbstractReactiveCouchbaseConfiguration {
@Autowired
private Environment springEnv;
@Bean
public String couchbaseAdminUser() {
return springEnv.getProperty("couchbase.adminUser", "Administrator");
return "Administrator";
}
@Bean
public String couchbaseAdminPassword() {
return springEnv.getProperty("couchbase.adminUser", "password");
return "password";
}
@Override
protected List<String> getBootstrapHosts() {
return Collections.singletonList(springEnv.getProperty("couchbase.host", "127.0.0.1"));
return Collections.singletonList("127.0.0.1");
}
@Override
protected String getBucketName() {
return springEnv.getProperty("couchbase.bucket", "default");
return "protected";
}
@Override
protected String getBucketPassword() {
return springEnv.getProperty("couchbase.password", "");
return "password";
}
@Override
@@ -74,4 +69,4 @@ public class ReactiveIntegrationTestApplicationConfig extends AbstractReactiveCo
protected Consistency getDefaultConsistency() {
return Consistency.READ_YOUR_OWN_WRITES;
}
}
}

View File

@@ -0,0 +1,67 @@
package org.springframework.data.couchbase;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.rules.ExternalResource;
import org.testcontainers.containers.FixedHostPortGenericContainer;
/**
* Testcontainers as external resource. It is recommended to use it as ClassRule.
* It also does the internal reference counting, in case if the getResource is called again.
*
*/
public class TestContainerResource extends ExternalResource {
private static FixedHostPortGenericContainer couchbaseContainer = null;
private static final AtomicInteger referenceCount = new AtomicInteger();
private static TestContainerResource currentInstance;
private static String serverVersion;
public static TestContainerResource getResource() {
if (currentInstance == null) {
currentInstance = new TestContainerResource();
try {
Properties properties = new Properties();
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("server.properties"));
serverVersion = properties.getProperty("server.version");
if(!properties.getProperty("server.resource").contentEquals("container")) {
return null;
}
} catch (Exception ex) {
serverVersion = "5.0.1";
}
couchbaseContainer = new FixedHostPortGenericContainer("couchbase:" + serverVersion)
.withFixedExposedPort(8091, 8091)
.withFixedExposedPort(18091, 18091)
.withFixedExposedPort(8092, 8092)
.withFixedExposedPort(18092, 18092)
.withFixedExposedPort(8093, 8093)
.withFixedExposedPort(18093, 18093)
.withFixedExposedPort(8094, 8094)
.withFixedExposedPort(18094, 18094)
.withFixedExposedPort(11210, 11210)
.withFixedExposedPort(11211, 11211)
.withFixedExposedPort(11207, 11207);
couchbaseContainer.waitingFor(new CouchbaseWaitStrategy(serverVersion));
couchbaseContainer.start();
}
return currentInstance;
}
@Override
protected void before() {
referenceCount.incrementAndGet();
}
@Override
protected void after() {
if (referenceCount.decrementAndGet() == 0 && couchbaseContainer != null) {
if(couchbaseContainer.isRunning()) {
couchbaseContainer.close();
}
currentInstance = null;
}
}
}

View File

@@ -2,6 +2,8 @@ package org.springframework.data.couchbase.config;
import static org.junit.Assert.*;
import javax.swing.*;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.Cluster;
import com.couchbase.client.java.CouchbaseCluster;
@@ -16,11 +18,11 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.annotation.Id;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.repository.CouchbaseRepository;
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
import org.springframework.stereotype.Repository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* This test case demonstrates that the {@link AbstractCouchbaseDataConfiguration} can take its SDK beans
@@ -31,7 +33,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
* @author Simon Baslé
*/
@SuppressWarnings("SpringJavaAutowiringInspection")
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration
public class AbstractCouchbaseDataConfigurationTest {
@@ -45,8 +47,8 @@ public class AbstractCouchbaseDataConfigurationTest {
static class SdkConfig {
private static final String IP = "127.0.0.1";
private static final String BUCKET_NAME = "default";
private static final String BUCKET_PASSWORD = "";
private static final String BUCKET_NAME = "protected";
private static final String BUCKET_PASSWORD = "password";
public static Bucket bucket;

View File

@@ -5,14 +5,14 @@ import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestNoShutdownApplicationConfig;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Simple test to make sure that environment is not shutdown if not life cycle managed by Spring.
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = IntegrationTestNoShutdownApplicationConfig.class)
public class CouchbaseEnvironmentNoShutdownProxyTest {

View File

@@ -23,20 +23,25 @@ import com.couchbase.client.java.document.json.JsonObject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
import org.springframework.data.couchbase.core.query.Consistency;
import org.springframework.data.couchbase.repository.User;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Michael Nitschinger
* @author Simon Baslé
*/
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes=CouchbaseTemplateParserIntegrationTests.class)
public class CouchbaseTemplateParserIntegrationTests {
DefaultListableBeanFactory factory;

View File

@@ -11,6 +11,7 @@ import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.Id;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.core.mapping.Document;
import org.springframework.data.couchbase.core.mapping.id.GeneratedValue;
@@ -18,12 +19,11 @@ import org.springframework.data.couchbase.core.mapping.id.IdAttribute;
import org.springframework.data.couchbase.core.mapping.id.IdPrefix;
import org.springframework.data.couchbase.core.mapping.id.IdSuffix;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Subhashni Balakrishnan
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
public class CouchbaseTemplateIdGenerationTests {

View File

@@ -1,9 +1,6 @@
package org.springframework.data.couchbase.core;
import static org.junit.Assert.*;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.error.DocumentDoesNotExistException;
import com.couchbase.client.java.repository.annotation.Id;
import org.junit.Before;
import org.junit.Rule;
@@ -11,17 +8,18 @@ import org.junit.Test;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestCustomKeySettings;
import org.springframework.data.couchbase.core.mapping.Document;
import org.springframework.data.couchbase.core.mapping.KeySettings;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Subhashni Balakrishnan
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = IntegrationTestCustomKeySettings.class)
public class CouchbaseTemplateKeySettingsTests {

View File

@@ -54,22 +54,22 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Version;
;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
import org.springframework.data.couchbase.core.mapping.Document;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Michael Nitschinger
* @author Simon Baslé
* @author Anastasiia Smirnova */
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
@TestExecutionListeners(CouchbaseTemplateQueryListener.class)
public class CouchbaseTemplateTests {
@Rule
public TestName testName = new TestName();
@@ -485,9 +485,9 @@ public class CouchbaseTemplateTests {
String id = "simple-doc-with-update-expiry-for-read";
DocumentWithTouchOnRead doc = new DocumentWithTouchOnRead(id);
template.save(doc);
Thread.sleep(1500);
Thread.sleep(1000);
assertNotNull(template.findById(id, DocumentWithTouchOnRead.class));
Thread.sleep(1500);
Thread.sleep(1000);
assertNotNull(template.findById(id, DocumentWithTouchOnRead.class));
Thread.sleep(3000);
assertNull(template.findById(id, DocumentWithTouchOnRead.class));

View File

@@ -49,19 +49,19 @@ import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Version;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.ReactiveIntegrationTestApplicationConfig;
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
import org.springframework.data.couchbase.core.mapping.Document;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import rx.observers.TestSubscriber;
/**
* @author Subhashni Balakrishnan
* @author Alex Derkach
**/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = ReactiveIntegrationTestApplicationConfig.class)
@TestExecutionListeners(RxCouchbaseTemplateQueryListener.class)
public class RxJavaCouchbaseTemplateTests {

View File

@@ -28,18 +28,18 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestCustomTypeKeyConfig;
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Tests the Java Config template around type key modification (DATACOUCH-134)
*
* @author Simon Baslé
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = IntegrationTestCustomTypeKeyConfig.class)
public class TypeKeyTests {

View File

@@ -19,13 +19,17 @@ package org.springframework.data.couchbase.core.mapping;
import java.util.Arrays;
import java.util.UUID;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.TestContainerResource;
import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions;
import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter;
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
@@ -38,7 +42,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Subhashni Balakrishnan
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
public class CustomConverterTests {

View File

@@ -24,16 +24,15 @@ import com.couchbase.client.java.Bucket;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Michael Nitschinger
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
public class ClientInfoTests {

View File

@@ -21,17 +21,23 @@ import static org.hamcrest.Matchers.greaterThan;
import com.couchbase.client.java.Bucket;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.TestContainerResource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Michael Nitschinger
*/
@Ignore(value = "Cant run get cluster info on test container")
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
public class ClusterInfoTests {
@@ -59,4 +65,4 @@ public class ClusterInfoTests {
assertThat(ci.getTotalRAMUsed(), greaterThan(0L));
}
}
}

View File

@@ -20,6 +20,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.Id;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.core.mapping.Document;
import org.springframework.data.couchbase.core.mapping.id.GeneratedValue;
@@ -29,7 +31,6 @@ import org.springframework.data.couchbase.repository.support.IndexManager;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.springframework.data.couchbase.core.mapping.id.GenerationStrategy.UNIQUE;
@@ -37,11 +38,13 @@ import static org.springframework.data.couchbase.core.mapping.id.GenerationStrat
/**
* @author Maxence Labusquiere
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
public class CouchbaseIdGenerationRepository {
public class CouchbaseIdGenerationTests {
@Autowired
private RepositoryOperationsMapping operationsMapping;
@Autowired
private IndexManager indexManager;
private CrudRepository<SimpleClassWithGeneratedIdValueUsingUUID, String> entityRepository;

View File

@@ -156,7 +156,9 @@ public class CouchbaseRepositoryViewTests {
assertEquals(expected, in);
assertEquals(expected, gteLte);
assertEquals(expected, between);
assertEquals(expected, gteLimited);
assertTrue(gteLimited.contains(u1));
assertTrue(gteLimited.contains(u2));
assertTrue(gteLimited.contains(u3));
}
@Test

View File

@@ -12,6 +12,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.core.CouchbaseQueryExecutionException;
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
@@ -25,12 +27,11 @@ import org.springframework.data.geo.Polygon;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Simon Baslé
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
@TestExecutionListeners(PartyPopulatorListener.class)
public class DimensionalQueryTests {

View File

@@ -2,8 +2,10 @@ package org.springframework.data.couchbase.repository;
import java.util.List;
import org.springframework.data.couchbase.core.query.N1qlPrimaryIndexed;
import org.springframework.data.repository.CrudRepository;
@N1qlPrimaryIndexed
public interface ItemRepository extends CrudRepository<Item, String> {
List<Object> findAllByDescriptionNotNull();

View File

@@ -25,6 +25,8 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataRetrievalFailureException;
;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
@@ -37,7 +39,6 @@ import org.springframework.data.mapping.model.MappingInstantiationException;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.List;
@@ -47,7 +48,7 @@ import java.util.List;
* @author Simon Baslé
* @author Subhashni Balakrishnan
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
@TestExecutionListeners(PartyPopulatorListener.class)
public class N1qlCouchbaseRepositoryTests {

View File

@@ -29,6 +29,8 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataRetrievalFailureException;
;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.core.CouchbaseQueryExecutionException;
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
@@ -36,12 +38,11 @@ import org.springframework.data.couchbase.repository.support.CouchbaseRepository
import org.springframework.data.couchbase.repository.support.IndexManager;
import org.springframework.data.geo.Point;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Simon Baslé
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
public class N1qlCrudRepositoryTests {

View File

@@ -25,6 +25,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.core.query.Query;
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
@@ -34,12 +35,11 @@ import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Simon Baslé
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
@TestExecutionListeners(PartyPopulatorListener.class)
public class N1qlPlaceholderTests {

View File

@@ -13,6 +13,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
@@ -23,9 +24,8 @@ import org.springframework.data.domain.Slice;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
@TestExecutionListeners(SimpleCouchbaseRepositoryListener.class)
public class PageAndSliceTests {

View File

@@ -19,6 +19,7 @@ package org.springframework.data.couchbase.repository;
import java.util.Date;
import java.util.List;
import org.springframework.data.couchbase.core.query.N1qlPrimaryIndexed;
import org.springframework.data.couchbase.core.query.N1qlSecondaryIndexed;
import org.springframework.data.couchbase.core.query.Query;
import org.springframework.data.couchbase.core.query.View;
@@ -33,6 +34,7 @@ import org.springframework.data.repository.query.Param;
* @author Subhashni Balakrishnan
*/
@ViewIndexed(designDoc = "party", viewName = "all")
@N1qlPrimaryIndexed
@N1qlSecondaryIndexed(indexName = "party")
public interface PartyRepository extends CouchbaseRepository<Party, String> {

View File

@@ -16,6 +16,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
@@ -23,13 +24,12 @@ import org.springframework.data.couchbase.repository.support.IndexManager;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Simon Baslé
* @author Mark Paluch
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
@TestExecutionListeners(PartyPopulatorListener.class)
public class QueryDerivationConversionTests {

View File

@@ -25,6 +25,7 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.ReactiveIntegrationTestApplicationConfig;
import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping;
import org.springframework.data.couchbase.repository.support.IndexManager;
@@ -33,14 +34,13 @@ import org.springframework.data.domain.Sort;
import org.springframework.data.repository.core.support.ReactiveRepositoryFactorySupport;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* This tests ReactiveSortingRepository features in the Couchbase connector.
*
* @author Subhashni Balakrishnan
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = ReactiveIntegrationTestApplicationConfig.class)
@TestExecutionListeners(PartyPopulatorListener.class)
public class ReactiveN1qlCouchbaseRepositoryTests {

View File

@@ -34,6 +34,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Version;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.core.AsyncUtils;
import org.springframework.data.couchbase.core.CouchbaseQueryExecutionException;
@@ -44,7 +45,6 @@ import org.springframework.data.couchbase.repository.support.IndexManager;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.document.JsonDocument;
@@ -57,7 +57,7 @@ import com.couchbase.client.java.view.ViewQuery;
* @author Michael Nitschinger
* @author Mark Paluch
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
@TestExecutionListeners(SimpleCouchbaseRepositoryListener.class)
public class SimpleCouchbaseRepositoryTests {

View File

@@ -26,6 +26,7 @@ import org.junit.Test;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.ReactiveIntegrationTestApplicationConfig;
import org.springframework.data.couchbase.core.CouchbaseQueryExecutionException;
import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping;
@@ -34,7 +35,6 @@ import org.springframework.data.couchbase.repository.support.ReactiveCouchbaseRe
import org.springframework.data.repository.core.support.ReactiveRepositoryFactorySupport;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.couchbase.client.java.Bucket;
import com.couchbase.client.java.error.DocumentDoesNotExistException;
@@ -44,7 +44,7 @@ import com.couchbase.client.java.view.ViewQuery;
/**
* @author Subhashni Balakrishnan
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = ReactiveIntegrationTestApplicationConfig.class)
@TestExecutionListeners(SimpleReactiveCouchbaseRepositoryListener.class)
public class SimpleReactiveCouchbaseRepositoryTests {

View File

@@ -44,7 +44,7 @@ public interface UserRepository extends CouchbaseRepository<User, String> {
@Query("SELECT * FROM #{#n1ql.bucket} WHERE username = $1 and #{#n1ql.filter} ")
User findByUsernameBadSelect(String username);
@Query("#{#n1ql.selectEntity} WHERE username LIKE '%-#{3 + 1}' and #{#n1ql.filter}'")
@Query("#{#n1ql.selectEntity} WHERE username LIKE '%-4' and #{#n1ql.filter}")
User findByUsernameWithSpelAndPlaceholder();
@Query

View File

@@ -6,10 +6,14 @@ import java.util.Date;
import java.util.Optional;
import org.junit.After;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.TestContainerResource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -17,7 +21,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
* @author Simon Baslé
* @author Mark Paluch
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = AuditedApplicationConfig.class)
public class AuditingTests {

View File

@@ -30,6 +30,9 @@ import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.test.context.ContextConfiguration;
import javax.enterprise.inject.se.SeContainer;
import javax.enterprise.inject.se.SeContainerInitializer;
@@ -37,6 +40,9 @@ import javax.enterprise.inject.se.SeContainerInitializer;
/**
* @author Mark Paluch
*/
@SuppressWarnings("SpringJavaAutowiringInspection")
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = CdiRepositoryTests.class)
public class CdiRepositoryTests {
private static SeContainer cdiContainer;
@@ -46,7 +52,6 @@ public class CdiRepositoryTests {
@BeforeClass
public static void init() {
cdiContainer = SeContainerInitializer.newInstance() //
.disableDiscovery() //
.addPackages(CdiRepositoryClient.class) //

View File

@@ -43,7 +43,7 @@ class CouchbaseClientProducer {
@Produces
public Bucket createCouchbaseClient(Cluster cluster) throws Exception {
CouchbaseBucketFactoryBean couchbaseFactoryBean = new CouchbaseBucketFactoryBean(cluster, "default");
CouchbaseBucketFactoryBean couchbaseFactoryBean = new CouchbaseBucketFactoryBean(cluster, "protected", "protected", "password");
couchbaseFactoryBean.afterPropertiesSet();
return couchbaseFactoryBean.getObject();
}

View File

@@ -36,7 +36,7 @@ class CouchbaseClusterInfoProducer {
@Produces
public ClusterInfo createClusterInfo(Cluster cluster) throws Exception {
return cluster.clusterManager("default", "").info();
return cluster.clusterManager("protected", "password").info();
}
}

View File

@@ -35,16 +35,15 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.annotation.Id;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.repository.User;
import org.springframework.data.couchbase.repository.UserRepository;
import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories;
import org.springframework.data.couchbase.repository.extending.base.impl.MyRepository;
import org.springframework.data.couchbase.repository.extending.base.impl.MyRepositoryImpl;
import org.springframework.data.couchbase.repository.support.IndexManager;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* This tests custom implementation of base repository.
@@ -52,7 +51,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
* @author Simon Baslé
*/
@SuppressWarnings("SpringJavaAutowiringInspection")
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration
public class RepositoryBaseTest {
@@ -93,12 +92,12 @@ public class RepositoryBaseTest {
@Override
protected String getBucketName() {
return "default";
return "protected";
}
@Override
protected String getBucketPassword() {
return "";
return "password";
}
@Bean

View File

@@ -17,17 +17,12 @@
package org.springframework.data.couchbase.repository.extending.method;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import java.util.Arrays;
import java.util.List;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
@@ -61,12 +56,12 @@ public class RepositoryCustomMethodTest {
@Override
protected String getBucketName() {
return "default";
return "protected";
}
@Override
protected String getBucketPassword() {
return "";
return "password";
}
//this is for dev so it is ok to auto-create indexes

View File

@@ -30,6 +30,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.UnsupportedCouchbaseFeatureException;
import org.springframework.data.couchbase.repository.User;
@@ -39,14 +41,13 @@ import org.springframework.data.couchbase.repository.support.CouchbaseRepository
import org.springframework.data.couchbase.repository.support.IndexManager;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* An integration test that validates feature checking with Java Config.
*
* @author Simon Baslé
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = FeatureDetectionTestApplicationConfig.class)
public class FeatureDetectionRepositoryTests {

View File

@@ -9,10 +9,8 @@ import com.couchbase.client.java.document.json.JsonObject;
import com.couchbase.client.java.env.CouchbaseEnvironment;
import com.couchbase.client.java.env.DefaultCouchbaseEnvironment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.core.WriteResultChecking;
@@ -21,32 +19,29 @@ import org.springframework.data.couchbase.repository.support.IndexManager;
@Configuration
public class FeatureDetectionTestApplicationConfig extends AbstractCouchbaseConfiguration {
@Autowired
private Environment springEnv;
@Bean
public String couchbaseAdminUser() {
return springEnv.getProperty("couchbase.adminUser", "Administrator");
return "Administrator";
}
@Bean
public String couchbaseAdminPassword() {
return springEnv.getProperty("couchbase.adminUser", "password");
return "password";
}
@Override
protected List<String> getBootstrapHosts() {
return Collections.singletonList(springEnv.getProperty("couchbase.host", "127.0.0.1"));
return Collections.singletonList("127.0.0.1");
}
@Override
protected String getBucketName() {
return springEnv.getProperty("couchbase.bucket", "default");
return "protected";
}
@Override
protected String getBucketPassword() {
return springEnv.getProperty("couchbase.password", "");
return "password";
}

View File

@@ -30,6 +30,8 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.IntegrationTestApplicationConfig;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
@@ -38,7 +40,6 @@ import org.springframework.data.couchbase.repository.support.IndexManager;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* This tests automatic index creation features in the Couchbase connector.
@@ -46,7 +47,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
*
* @author Simon Baslé
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = IntegrationTestApplicationConfig.class)
@TestExecutionListeners(IndexedRepositoryTestListener.class)
public class IndexedRepositoryTests {

View File

@@ -23,28 +23,23 @@ import static org.junit.Assert.*;
import java.util.List;
import com.couchbase.client.java.Bucket;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.repository.SimpleCouchbaseRepositoryListener;
import org.springframework.data.couchbase.repository.User;
import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping;
import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactory;
import org.springframework.data.couchbase.repository.support.IndexManager;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.query.EvaluationContextProvider;
import org.springframework.data.repository.query.spi.EvaluationContextExtension;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Simon Baslé
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = SpelConfig.class)
@TestExecutionListeners(SimpleCouchbaseRepositoryListener.class)
public class SpelRepositoryTests {

View File

@@ -17,6 +17,8 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.annotation.Id;
;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.data.couchbase.config.AbstractCouchbaseConfiguration;
import org.springframework.data.couchbase.core.CouchbaseOperations;
import org.springframework.data.couchbase.core.CouchbaseTemplate;
@@ -28,7 +30,6 @@ import org.springframework.data.couchbase.repository.config.RepositoryOperations
import org.springframework.data.couchbase.repository.support.IndexManager;
import org.springframework.stereotype.Repository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* This test case demonstrates (with a bit of mocking) that the framework will take the
@@ -39,7 +40,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
* @author Mark Paluch
*/
@SuppressWarnings("SpringJavaAutowiringInspection")
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration
public class RepositoryTemplateWiringTests {
@@ -92,12 +93,12 @@ public class RepositoryTemplateWiringTests {
@Override
protected String getBucketName() {
return "default";
return "protected";
}
@Override
protected String getBucketPassword() {
return "";
return "password";
}
@Bean

View File

@@ -6,15 +6,21 @@ import static org.junit.Assert.assertTrue;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionReader;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.couchbase.ContainerResourceRunner;
import org.springframework.test.context.ContextConfiguration;
/**
* @author Simon Baslé
*/
@SuppressWarnings("SpringJavaAutowiringInspection")
@RunWith(ContainerResourceRunner.class)
@ContextConfiguration(classes = XmlRepositoryConfigurationTests.class)
public class XmlRepositoryConfigurationTests {
DefaultListableBeanFactory factory;

View File

@@ -7,8 +7,8 @@
<couchbase:env/>
<couchbase:cluster/>
<couchbase:clusterInfo/>
<couchbase:bucket/>
<couchbase:clusterInfo login="protected" password="password"/>
<couchbase:bucket username="protected" bucketName="protected" bucketPassword="password"/>
<couchbase:template id="template" consistency="EVENTUALLY_CONSISTENT"/>
<couchbase:template id="templateBad" consistency="BadConsistency"/>

View File

@@ -8,10 +8,10 @@
<couchbase:env/>
<couchbase:cluster/>
<couchbase:clusterInfo/>
<couchbase:clusterInfo login="protected" password="password"/>
<couchbase:bucket id="cb-first"/>
<couchbase:bucket id="cb-second"/>
<couchbase:bucket id="cb-first" bucketName="protected" username="protected" bucketPassword="password"/>
<couchbase:bucket id="cb-second" bucketName="protected" username="protected" bucketPassword="password"/>
<couchbase:template id="cb-template-first" bucket-ref="cb-first" />
<couchbase:template id="cb-template-second" bucket-ref="cb-second" />

View File

@@ -7,8 +7,8 @@
<couchbase:env/>
<couchbase:cluster/>
<couchbase:clusterInfo/>
<couchbase:bucket/>
<couchbase:clusterInfo login="protected" password="password"/>
<couchbase:bucket username="protected" bucketName="protected" bucketPassword="password"/>
<couchbase:template/>

View File

@@ -7,8 +7,8 @@
<couchbase:env/>
<couchbase:cluster/>
<couchbase:clusterInfo/>
<couchbase:bucket/>
<couchbase:clusterInfo login="protected" password="password"/>
<couchbase:bucket username="protected" bucketName="protected" bucketPassword="password"/>
<couchbase:template/>

View File

@@ -7,8 +7,8 @@
<couchbase:env/>
<couchbase:cluster/>
<couchbase:clusterInfo/>
<couchbase:bucket/>
<couchbase:clusterInfo login="protected" password="password"/>
<couchbase:bucket username="protected" bucketName="protected" bucketPassword="password"/>
<couchbase:template translation-service-ref="myCustomTranslationService"/>

View File

@@ -7,8 +7,8 @@
<couchbase:env/>
<couchbase:cluster/>
<couchbase:clusterInfo/>
<couchbase:bucket/>
<couchbase:clusterInfo login="protected" password="password"/>
<couchbase:bucket username="protected" bucketName="protected" bucketPassword="password"/>
<!--note that the template needs both converter and translation service if you want to customize converter-->
<couchbase:template translation-service-ref="myCustomTranslationService" converter-ref="myCustomConverter"/>

View File

@@ -1,3 +0,0 @@
couchbase.host=127.0.0.1
couchbase.bucket=default
couchbase.password=

View File

@@ -0,0 +1,6 @@
#Couchbase server versions 4.5 and above are supported
server.version=5.1.0
#resource can be set to container or omitted
#container just would require docker installed
#omitted indicates that there is a local couchbase server running
server.resource=container

View File

@@ -55,6 +55,13 @@ public abstract class AbstractCouchbaseConfiguration
*/
protected abstract String getBucketName();
/**
* The user of the bucket. Override the method for users in Couchbase Server 5.0+.
*
* @return user name.
*/
protected String getUsername() { return getBucketName(); }
/**
* The password of the bucket (can be an empty string).
*
@@ -115,7 +122,7 @@ public abstract class AbstractCouchbaseConfiguration
@Override
@Bean(name = BeanNames.COUCHBASE_CLUSTER_INFO)
public ClusterInfo couchbaseClusterInfo() throws Exception {
return couchbaseCluster().clusterManager(getBucketName(), getBucketPassword()).info();
return couchbaseCluster().clusterManager(getUsername(), getBucketPassword()).info();
}
/**
@@ -127,6 +134,13 @@ public abstract class AbstractCouchbaseConfiguration
@Bean(destroyMethod = "close", name = BeanNames.COUCHBASE_BUCKET)
public Bucket couchbaseClient() throws Exception {
//@Bean method can use another @Bean method in the same @Configuration by directly invoking it
return couchbaseCluster().openBucket(getBucketName(), getBucketPassword());
Cluster cluster = couchbaseCluster();
if(!getUsername().contentEquals(getBucketName())){
cluster.authenticate(getUsername(), getBucketPassword());
} else if (!getBucketPassword().isEmpty()) {
return cluster.openBucket(getBucketName(), getBucketPassword());
}
return cluster.openBucket(getBucketName());
}
}

View File

@@ -54,9 +54,16 @@ public abstract class AbstractReactiveCouchbaseConfiguration
protected abstract String getBucketName();
/**
* The password of the bucket (can be an empty string).
* The user of the bucket. Override the method for users in Couchbase Server 5.0+.
*
* @return the password of the bucket.
* @return the user name.
*/
protected String getUsername() { return getBucketName(); }
/**
* The password of the bucket/User of the bucket (can be an empty string).
*
* @return the password of the bucket/user.
*/
protected abstract String getBucketPassword();
@@ -113,7 +120,7 @@ public abstract class AbstractReactiveCouchbaseConfiguration
@Override
@Bean(name = BeanNames.COUCHBASE_CLUSTER_INFO)
public ClusterInfo couchbaseClusterInfo() throws Exception {
return couchbaseCluster().clusterManager(getBucketName(), getBucketPassword()).info();
return couchbaseCluster().clusterManager(getUsername(), getBucketPassword()).info();
}
/**
@@ -125,6 +132,13 @@ public abstract class AbstractReactiveCouchbaseConfiguration
@Bean(destroyMethod = "close", name = BeanNames.COUCHBASE_BUCKET)
public Bucket couchbaseClient() throws Exception {
//@Bean method can use another @Bean method in the same @Configuration by directly invoking it
return couchbaseCluster().openBucket(getBucketName(), getBucketPassword());
Cluster cluster = couchbaseCluster();
if(!getUsername().contentEquals(getBucketName())){
cluster.authenticate(getUsername(), getBucketPassword());
} else if (!getBucketPassword().isEmpty()) {
return cluster.openBucket(getBucketName(), getBucketPassword());
}
return cluster.openBucket(getBucketName());
}
}

View File

@@ -30,27 +30,30 @@ import org.springframework.data.couchbase.core.CouchbaseExceptionTranslator;
* {@link Cluster} reference.
*
* @author Simon Baslé
* @author Subhashni Balakrishnan
*/
public class CouchbaseBucketFactoryBean extends AbstractFactoryBean<Bucket> implements PersistenceExceptionTranslator {
private final Cluster cluster;
private final String bucketName;
private final String bucketPassword;
private final String username;
private final String password;
private final PersistenceExceptionTranslator exceptionTranslator = new CouchbaseExceptionTranslator();
public CouchbaseBucketFactoryBean(Cluster cluster) {
this(cluster, null, null);
this(cluster, null, null, null);
}
public CouchbaseBucketFactoryBean(Cluster cluster, String bucketName) {
this(cluster, bucketName, null);
this(cluster, bucketName, bucketName, null);
}
public CouchbaseBucketFactoryBean(Cluster cluster, String bucketName, String bucketPassword) {
public CouchbaseBucketFactoryBean(Cluster cluster, String bucketName, String username, String password) {
this.cluster = cluster;
this.bucketName = bucketName;
this.bucketPassword = bucketPassword;
this.username = username;
this.password = password;
}
@Override
@@ -63,11 +66,15 @@ public class CouchbaseBucketFactoryBean extends AbstractFactoryBean<Bucket> impl
if (bucketName == null) {
return cluster.openBucket();
}
else if (bucketPassword == null) {
else if (password == null) {
return cluster.openBucket(bucketName);
}
else if (bucketName.contentEquals(username)) {
return cluster.openBucket(bucketName, password);
}
else {
return cluster.openBucket(bucketName, bucketPassword);
cluster.authenticate(username, password);
return cluster.openBucket(bucketName);
}
}

View File

@@ -30,7 +30,7 @@ import org.springframework.util.StringUtils;
* The parser for XML definition of a {@link Bucket}, to be constructed from a {@link Cluster} reference.
* If no reference is given, the default reference <code>{@value BeanNames#COUCHBASE_CLUSTER}</code> is used.
*
* See attributes {@link #CLUSTER_REF_ATTR}, {@link #BUCKETNAME_ATTR} and {@link #BUCKETPASSWORD_ATTR}.
* See attributes {@link #CLUSTER_REF_ATTR}, {@link #BUCKETNAME_ATTR}, {@link #USERNAME_ATTR} and {@link #BUCKETPASSWORD_ATTR}.
*
* @author Simon Baslé
*/
@@ -46,8 +46,13 @@ public class CouchbaseBucketParser extends AbstractSingleBeanDefinitionParser {
*/
public static final String BUCKETNAME_ATTR = "bucketName";
/*
* The <code>username</code> attribute in a bucket definition defines the user of the bucket to open.
*/
public static final String USERNAME_ATTR = "username";
/**
* The <code>bucketPassword</code> attribute in a bucket definition defines the password of the bucket to open.
* The <code>bucketPassword</code> attribute in a bucket definition defines the password of the bucket/user of the bucket to open.
*/
public static final String BUCKETPASSWORD_ATTR = "bucketPassword";
@@ -95,9 +100,14 @@ public class CouchbaseBucketParser extends AbstractSingleBeanDefinitionParser {
builder.addConstructorArgValue(bucketName);
}
String bucketPassword = element.getAttribute(BUCKETPASSWORD_ATTR);
if (StringUtils.hasText(bucketPassword)) {
builder.addConstructorArgValue(bucketPassword);
String username = element.getAttribute(USERNAME_ATTR);
if (StringUtils.hasText(username)) {
builder.addConstructorArgValue(username);
}
String password = element.getAttribute(BUCKETPASSWORD_ATTR);
if (StringUtils.hasText(password)) {
builder.addConstructorArgValue(password);
}
}
}

View File

@@ -36,6 +36,7 @@
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="cluster-ref" type="xsd:string" use="optional"/>
<xsd:attribute name="bucketName" type="xsd:string" use="optional"/>
<xsd:attribute name="username" type="xsd:string" use="optional"/>
<xsd:attribute name="bucketPassword" type="xsd:string" use="optional"/>
</xsd:extension>
</xsd:complexContent>

View File

@@ -108,7 +108,7 @@ public class CouchbaseBucketParserTest {
BeanDefinition def = factory.getBeanDefinition("bucketWithNameAndPassword");
assertThat(def, is(notNullValue()));
assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(3)));
assertThat(def.getConstructorArgumentValues().getArgumentCount(), is(equalTo(4)));
assertThat(def.getPropertyValues().size(), is(equalTo(0)));
ConstructorArgumentValues.ValueHolder holder = def.getConstructorArgumentValues()
@@ -123,8 +123,15 @@ public class CouchbaseBucketParserTest {
assertThat(nameHolder.getValue(), is(instanceOf(String.class)));
assertThat(nameHolder.getValue().toString(), is((equalTo("test"))));
ConstructorArgumentValues.ValueHolder passwordHolder = def.getConstructorArgumentValues()
ConstructorArgumentValues.ValueHolder usernameHolder = def.getConstructorArgumentValues()
.getArgumentValue(2, Object.class);
assertThat(usernameHolder.getValue(), is(instanceOf(String.class)));
assertThat(usernameHolder.getValue().toString(), is((equalTo("testuser"))));
ConstructorArgumentValues.ValueHolder passwordHolder = def.getConstructorArgumentValues()
.getArgumentValue(3, Object.class);
assertThat(passwordHolder.getValue(), is(instanceOf(String.class)));
assertThat(passwordHolder.getValue().toString(), is((equalTo("123"))));
}

View File

@@ -14,6 +14,6 @@
<couchbase:bucket id="bucketWithName" cluster-ref="clusterDefault" bucketName="toto" />
<couchbase:bucket id="bucketWithNameAndPassword" cluster-ref="clusterDefault" bucketName="test" bucketPassword="123" />
<couchbase:bucket id="bucketWithNameAndPassword" cluster-ref="clusterDefault" bucketName="test" username="testuser" bucketPassword="123" />
</beans>