* Added support for Cosmos Key Credential
Added new tests
Updated existing tests
Updated azure-cosmos version to 3.1.0
Added secondary key to application.properties
Updated build.xml with secondary key

* add cosmosdb.secondaryKey for CI

* add cosmosdb.secondaryKey in setup.bat for CI

* Removing getter, as its not required and we don't want to expose public
API for cosmosClient

* Adding private getter back because of compilation issues
This commit is contained in:
Kushagra Thapar 2019-08-09 03:53:41 -07:00 коммит произвёл Xiaolu Dai
Родитель 1fefc23172
Коммит b9476204cc
12 изменённых файлов: 150 добавлений и 53 удалений

Просмотреть файл

@ -7,16 +7,21 @@
<arg value=".\src\libs\setup.bat"/>
<arg value="${azure.test.resourcegroup}"/>
<arg value="${azure.test.dbname}"/>
<redirector outputproperty="cosmosdb.key"/>
<redirector outputproperty="cosmosdb.keys"/>
</exec>
<exec osfamily="unix" executable="bash">
<arg value="./src/libs/setup.sh"/>
<arg value="${azure.test.resourcegroup}"/>
<arg value="${azure.test.dbname}"/>
<redirector outputproperty="cosmosdb.key"/>
<redirector outputproperty="cosmosdb.keys"/>
</exec>
<script language="javascript">
project.setProperty('cosmosdb.key', project.getProperty('cosmosdb.keys').split(' ')[0]);
project.setProperty('cosmosdb.secondaryKey', project.getProperty('cosmosdb.keys').split(' ')[1]);
</script>
<propertyfile file="./src/test/resources/application.properties">
<entry key="cosmosdb.key" value="${cosmosdb.key}"/>
<entry key="cosmosdb.secondaryKey" value="${cosmosdb.secondaryKey}"/>
<entry key="cosmosdb.uri" value="https://${azure.test.dbname}.documents.azure.com:443"/>
</propertyfile>
</target>

Просмотреть файл

@ -59,7 +59,7 @@
<project.reactor.test.version>3.2.5.RELEASE</project.reactor.test.version>
<azure.documentdb.version>1.16.2</azure.documentdb.version>
<azure.cosmos.version>3.0.0</azure.cosmos.version>
<azure.cosmos.version>3.1.0</azure.cosmos.version>
<azure.test.resourcegroup>spring-data-cosmosdb-test</azure.test.resourcegroup>
<azure.test.dbname>testdb-${maven.build.timestamp}</azure.test.dbname>
<skip.integration.tests>true</skip.integration.tests>

Просмотреть файл

@ -1,3 +1,4 @@
azure.cosmosdb.uri=your-cosmosDb-uri
azure.cosmosdb.key=your-cosmosDb-key
azure.cosmosdb.secondaryKey=your-cosmosDb-secondary-key
azure.cosmosdb.database=your-cosmosDb-dbName

Просмотреть файл

@ -1,3 +1,4 @@
azure.cosmosdb.uri=your-cosmosDb-uri
azure.cosmosdb.key=your-cosmosDb-key
azure.cosmosdb.secondaryKey=your-cosmosDb-secondary-key
azure.cosmosdb.database=your-cosmosDb-dbName

Просмотреть файл

@ -30,9 +30,14 @@ set createcmd='az cosmosdb create --name %dbname% --resource-group %resourcegrou
for /f "tokens=*" %%a in (%createcmd%) do (set cosmosdburi=%%a)
set listcmd='az cosmosdb keys list --name %dbname% --resource-group %resourcegroup% --query primaryMasterKey'
for /f "tokens=*" %%a in (%listcmd%) do (set cosmosdbkey=%%a)
set cosmosdbkey=%cosmosdbkey:"=%
echo %cosmosdbkey%
for /f "tokens=*" %%a in (%listcmd%) do (set cosmosdbPrimarykey=%%a)
set cosmosdbPrimarykey=%cosmosdbPrimarykey:"=%
set listSecondaryKeycmd='az cosmosdb keys list --name %dbname% --resource-group %resourcegroup% --query secondaryMasterKey'
for /f "tokens=*" %%a in (%listSecondaryKeycmd%) do (set cosmosdbSecondarykey=%%a)
set cosmosdbSecondarykey=%cosmosdbSecondarykey:"=%
echo %cosmosdbPrimarykey% %cosmosdbSecondarykey%
goto :end

Просмотреть файл

@ -16,6 +16,7 @@ fi
az login --service-principal -u $CLIENT_ID -p $CLIENT_KEY --tenant $TENANT_ID >> tmp.txt
az group create -l westus -n $resourcegroup 2>1 > /dev/null
cosmosDbUri=$(az cosmosdb create --name $dbname --resource-group $resourcegroup --kind GlobalDocumentDB --query documentEndpoint)
cosmosDbKey=$(az cosmosdb keys list --name $dbname --resource-group $resourcegroup --query primaryMasterKey)
cosmosDbPrimaryKey=$(az cosmosdb keys list --name $dbname --resource-group $resourcegroup --query primaryMasterKey)
cosmosDbSecondaryKey=$(az cosmosdb keys list --name $dbname --resource-group $resourcegroup --query secondaryMasterKey)
echo $cosmosDbKey | sed -e 's/^"//' -e 's/"$//'
echo "$cosmosDbPrimaryKey $cosmosDbSecondaryKey" | sed -e 's/"//g'

Просмотреть файл

@ -15,6 +15,7 @@ import com.microsoft.azure.spring.data.cosmosdb.config.DocumentDBConfig;
import lombok.Getter;
import lombok.NonNull;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import javax.annotation.PostConstruct;
@ -49,14 +50,20 @@ public class CosmosDbFactory {
policy.setUserAgentSuffix(userAgent);
return CosmosClient.builder()
.endpoint(config.getUri())
.key(config.getKey())
.build();
.endpoint(config.getUri())
.key(config.getKey())
.cosmosKeyCredential(config.getCosmosKeyCredential())
.build();
}
private void validateConfig(@NonNull DocumentDBConfig config) {
Assert.hasText(config.getUri(), "cosmosdb host url should have text!");
Assert.hasText(config.getKey(), "cosmosdb host key should have text!");
if (config.getCosmosKeyCredential() == null) {
Assert.hasText(config.getKey(), "cosmosdb host key should have text!");
} else if (StringUtils.isEmpty(config.getKey())) {
Assert.hasText(config.getCosmosKeyCredential().key(),
"cosmosdb credential host key should have text!");
}
Assert.hasText(config.getDatabase(), "cosmosdb database should have text!");
Assert.notNull(config.getConnectionPolicy(), "cosmosdb connection policy should not be null!");
}

Просмотреть файл

@ -5,6 +5,7 @@
*/
package com.microsoft.azure.spring.data.cosmosdb.config;
import com.azure.data.cosmos.CosmosKeyCredential;
import com.microsoft.azure.documentdb.ConnectionPolicy;
import com.microsoft.azure.documentdb.ConsistencyLevel;
import com.microsoft.azure.documentdb.RequestOptions;
@ -30,6 +31,19 @@ public class DocumentDBConfig {
private RequestOptions requestOptions;
private CosmosKeyCredential cosmosKeyCredential;
public static DocumentDBConfigBuilder builder(String uri, CosmosKeyCredential cosmosKeyCredential,
String database) {
return defaultBuilder()
.uri(uri)
.cosmosKeyCredential(cosmosKeyCredential)
.database(database)
.connectionPolicy(ConnectionPolicy.GetDefault())
.consistencyLevel(ConsistencyLevel.Session)
.requestOptions(new RequestOptions());
}
public static DocumentDBConfigBuilder builder(String uri, String key, String database) {
return defaultBuilder()
.uri(uri)

Просмотреть файл

@ -18,8 +18,8 @@ import static org.assertj.core.api.Assertions.assertThat;
public class DocumentDbFactoryUnitTest {
@Test(expected = IllegalArgumentException.class)
public void testNullKey() {
final DocumentDBConfig dbConfig = DocumentDBConfig.builder(DOCUMENTDB_FAKE_HOST, null, DB_NAME).build();
public void testEmptyKey() {
final DocumentDBConfig dbConfig = DocumentDBConfig.builder(DOCUMENTDB_FAKE_HOST, "", DB_NAME).build();
new DocumentDbFactory(dbConfig);
}

Просмотреть файл

@ -6,6 +6,7 @@
package com.microsoft.azure.spring.data.cosmosdb.core;
import com.azure.data.cosmos.CosmosClientException;
import com.azure.data.cosmos.CosmosKeyCredential;
import com.azure.data.cosmos.PartitionKey;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.microsoft.azure.spring.data.cosmosdb.CosmosDbFactory;
@ -63,16 +64,20 @@ public class ReactiveCosmosTemplateIT {
private String documentDbUri;
@Value("${cosmosdb.key}")
private String documentDbKey;
@Value("${cosmosdb.secondaryKey}")
private String documentDbSecondaryKey;
private ReactiveCosmosTemplate dbTemplate;
private ReactiveCosmosTemplate cosmosTemplate;
private String containerName;
private CosmosKeyCredential cosmosKeyCredential;
@Autowired
private ApplicationContext applicationContext;
@Before
public void setUp() throws ClassNotFoundException {
final DocumentDBConfig dbConfig = DocumentDBConfig.builder(documentDbUri, documentDbKey, DB_NAME).build();
cosmosKeyCredential = new CosmosKeyCredential(documentDbKey);
final DocumentDBConfig dbConfig = DocumentDBConfig.builder(documentDbUri, cosmosKeyCredential, DB_NAME).build();
final CosmosDbFactory dbFactory = new CosmosDbFactory(dbConfig);
final DocumentDbMappingContext mappingContext = new DocumentDbMappingContext();
@ -84,19 +89,21 @@ public class ReactiveCosmosTemplateIT {
final MappingDocumentDbConverter dbConverter = new MappingDocumentDbConverter(mappingContext, objectMapper);
dbTemplate = new ReactiveCosmosTemplate(dbFactory, dbConverter, DB_NAME);
dbTemplate.createCollectionIfNotExists(personInfo).block().container();
dbTemplate.insert(TEST_PERSON).block();
cosmosTemplate = new ReactiveCosmosTemplate(dbFactory, dbConverter, DB_NAME);
cosmosTemplate.createCollectionIfNotExists(personInfo).block().container();
cosmosTemplate.insert(TEST_PERSON).block();
}
@After
public void cleanup() {
dbTemplate.deleteContainer(Person.class.getSimpleName());
// Reset master key
cosmosKeyCredential.key(documentDbKey);
cosmosTemplate.deleteContainer(Person.class.getSimpleName());
}
@Test
public void testInsertDuplicateId() {
final Mono<Person> insertMono = dbTemplate.insert(TEST_PERSON);
final Mono<Person> insertMono = cosmosTemplate.insert(TEST_PERSON);
final TestSubscriber testSubscriber = new TestSubscriber();
insertMono.subscribe(testSubscriber);
testSubscriber.awaitTerminalEvent();
@ -108,7 +115,7 @@ public class ReactiveCosmosTemplateIT {
@Test
public void testFindByID() {
final Mono<Person> findById = dbTemplate.findById(Person.class.getSimpleName(), TEST_PERSON.getId(),
final Mono<Person> findById = cosmosTemplate.findById(Person.class.getSimpleName(), TEST_PERSON.getId(),
Person.class);
StepVerifier.create(findById).consumeNextWith(actual -> {
Assert.assertThat(actual.getFirstName(), is(equalTo(TEST_PERSON.getFirstName())));
@ -116,15 +123,26 @@ public class ReactiveCosmosTemplateIT {
}).verifyComplete();
}
@Test
public void testFindByIDBySecondaryKey() {
cosmosKeyCredential.key(documentDbSecondaryKey);
final Mono<Person> findById = cosmosTemplate.findById(Person.class.getSimpleName(), TEST_PERSON.getId(),
Person.class);
StepVerifier.create(findById).consumeNextWith(actual -> {
Assert.assertThat(actual.getFirstName(), is(equalTo(TEST_PERSON.getFirstName())));
Assert.assertThat(actual.getLastName(), is(equalTo(TEST_PERSON.getLastName())));
}).verifyComplete();
}
@Test
public void testFindAll() {
final Flux<Person> flux = dbTemplate.findAll(Person.class.getSimpleName(), Person.class);
final Flux<Person> flux = cosmosTemplate.findAll(Person.class.getSimpleName(), Person.class);
StepVerifier.create(flux).expectNextCount(1).verifyComplete();
}
@Test
public void testFindByIdWithContainerName() {
StepVerifier.create(dbTemplate.findById(Person.class.getSimpleName(), TEST_PERSON.getId(), Person.class))
StepVerifier.create(cosmosTemplate.findById(Person.class.getSimpleName(), TEST_PERSON.getId(), Person.class))
.consumeNextWith(actual -> {
Assert.assertThat(actual.getFirstName(), is(equalTo(TEST_PERSON.getFirstName())));
Assert.assertThat(actual.getLastName(), is(equalTo(TEST_PERSON.getLastName())));
@ -133,13 +151,20 @@ public class ReactiveCosmosTemplateIT {
@Test
public void testInsert() {
StepVerifier.create(dbTemplate.insert(TEST_PERSON_3))
StepVerifier.create(cosmosTemplate.insert(TEST_PERSON_3))
.expectNext(TEST_PERSON_3).verifyComplete();
}
@Test
public void testInsertBySecondaryKey() {
cosmosKeyCredential.key(documentDbSecondaryKey);
StepVerifier.create(cosmosTemplate.insert(TEST_PERSON_3))
.expectNext(TEST_PERSON_3).verifyComplete();
}
@Test
public void testInsertWithCollectionName() {
StepVerifier.create(dbTemplate.insert(Person.class.getSimpleName(), TEST_PERSON_2, null))
StepVerifier.create(cosmosTemplate.insert(Person.class.getSimpleName(), TEST_PERSON_2, null))
.expectNext(TEST_PERSON_2).verifyComplete();
}
@ -149,7 +174,18 @@ public class ReactiveCosmosTemplateIT {
final ArrayList<String> hobbies = new ArrayList<>(p.getHobbies());
hobbies.add("more code");
p.setHobbies(hobbies);
final Mono<Person> upsert = dbTemplate.upsert(p, null);
final Mono<Person> upsert = cosmosTemplate.upsert(p, null);
StepVerifier.create(upsert).expectNextCount(1).verifyComplete();
}
@Test
public void testUpsertBySecondaryKey() {
cosmosKeyCredential.key(documentDbSecondaryKey);
final Person p = TEST_PERSON_2;
final ArrayList<String> hobbies = new ArrayList<>(p.getHobbies());
hobbies.add("more code");
p.setHobbies(hobbies);
final Mono<Person> upsert = cosmosTemplate.upsert(p, null);
StepVerifier.create(upsert).expectNextCount(1).verifyComplete();
}
@ -159,24 +195,33 @@ public class ReactiveCosmosTemplateIT {
final ArrayList<String> hobbies = new ArrayList<>(p.getHobbies());
hobbies.add("more code");
p.setHobbies(hobbies);
final Mono<Person> upsert = dbTemplate.upsert(Person.class.getSimpleName(), p, null);
final Mono<Person> upsert = cosmosTemplate.upsert(Person.class.getSimpleName(), p, null);
StepVerifier.create(upsert).expectNextCount(1).verifyComplete();
}
@Test
public void testDeleteById() {
dbTemplate.insert(TEST_PERSON_4).block();
final Mono<Void> voidMono = dbTemplate.deleteById(Person.class.getSimpleName(), TEST_PERSON_4.getId(),
cosmosTemplate.insert(TEST_PERSON_4).block();
final Mono<Void> voidMono = cosmosTemplate.deleteById(Person.class.getSimpleName(), TEST_PERSON_4.getId(),
new PartitionKey(TEST_PERSON_4.getId()));
StepVerifier.create(voidMono).verifyComplete();
}
@Test
public void testDeleteByIdBySecondaryKey() {
cosmosKeyCredential.key(documentDbSecondaryKey);
cosmosTemplate.insert(TEST_PERSON_4).block();
final Mono<Void> voidMono = cosmosTemplate.deleteById(Person.class.getSimpleName(), TEST_PERSON_4.getId(),
new PartitionKey(TEST_PERSON_4.getId()));
StepVerifier.create(voidMono).verifyComplete();
}
@Test
public void testFind() {
final Criteria criteria = Criteria.getInstance(CriteriaType.IS_EQUAL, "firstName",
Arrays.asList(TEST_PERSON.getFirstName()));
final DocumentQuery query = new DocumentQuery(criteria);
final Flux<Person> personFlux = dbTemplate.find(query, Person.class, Person.class.getSimpleName());
final Flux<Person> personFlux = cosmosTemplate.find(query, Person.class, Person.class.getSimpleName());
StepVerifier.create(personFlux).expectNextCount(1).verifyComplete();
}
@ -185,14 +230,29 @@ public class ReactiveCosmosTemplateIT {
final Criteria criteria = Criteria.getInstance(CriteriaType.IS_EQUAL, "firstName",
Arrays.asList(TEST_PERSON.getFirstName()));
final DocumentQuery query = new DocumentQuery(criteria);
final Mono<Boolean> exists = dbTemplate.exists(query, Person.class, containerName);
final Mono<Boolean> exists = cosmosTemplate.exists(query, Person.class, containerName);
StepVerifier.create(exists).expectNext(true).verifyComplete();
}
@Test
public void testCount() {
final Mono<Long> count = dbTemplate.count(containerName);
final Mono<Long> count = cosmosTemplate.count(containerName);
StepVerifier.create(count).expectNext((long) 1).verifyComplete();
}
@Test
public void testCountBySecondaryKey() {
cosmosKeyCredential.key(documentDbSecondaryKey);
final Mono<Long> count = cosmosTemplate.count(containerName);
StepVerifier.create(count).expectNext((long) 1).verifyComplete();
}
@Test
public void testInvalidSecondaryKey() {
cosmosKeyCredential.key("Invalid secondary key");
final Mono<Person> findById = cosmosTemplate.findById(Person.class.getSimpleName(), TEST_PERSON.getId(),
Person.class);
StepVerifier.create(findById).expectError(IllegalArgumentException.class);
}
}

Просмотреть файл

@ -64,7 +64,7 @@ public class ReactiveCosmosTemplatePartitionIT {
@Value("${cosmosdb.key}")
private String documentDbKey;
private ReactiveCosmosTemplate dbTemplate;
private ReactiveCosmosTemplate cosmosTemplate;
private String containerName;
@Autowired
@ -84,22 +84,22 @@ public class ReactiveCosmosTemplatePartitionIT {
mappingContext.setInitialEntitySet(new EntityScanner(this.applicationContext).scan(Persistent.class));
final MappingDocumentDbConverter dbConverter = new MappingDocumentDbConverter(mappingContext, objectMapper);
dbTemplate = new ReactiveCosmosTemplate(dbFactory, dbConverter, DB_NAME);
cosmosTemplate = new ReactiveCosmosTemplate(dbFactory, dbConverter, DB_NAME);
dbTemplate.createCollectionIfNotExists(personInfo).block().container();
dbTemplate.insert(TEST_PERSON).block();
cosmosTemplate.createCollectionIfNotExists(personInfo).block().container();
cosmosTemplate.insert(TEST_PERSON).block();
}
@After
public void cleanup() {
dbTemplate.deleteContainer(PartitionPerson.class.getSimpleName());
cosmosTemplate.deleteContainer(PartitionPerson.class.getSimpleName());
}
@Test
public void testFindWithPartition() {
final Criteria criteria = Criteria.getInstance(IS_EQUAL, PROPERTY_LAST_NAME, Arrays.asList(LAST_NAME));
final DocumentQuery query = new DocumentQuery(criteria);
final Flux<PartitionPerson> partitionPersonFlux = dbTemplate.find(query, PartitionPerson.class,
final Flux<PartitionPerson> partitionPersonFlux = cosmosTemplate.find(query, PartitionPerson.class,
PartitionPerson.class.getSimpleName());
StepVerifier.create(partitionPersonFlux).consumeNextWith(actual -> {
Assert.assertThat(actual.getFirstName(), is(equalTo(TEST_PERSON.getFirstName())));
@ -118,7 +118,7 @@ public class ReactiveCosmosTemplatePartitionIT {
final PartitionPerson newPerson = new PartitionPerson(UUID.randomUUID().toString(), firstName, NEW_LAST_NAME,
null, null);
final String partitionKeyValue = newPerson.getLastName();
final Mono<PartitionPerson> upsert = dbTemplate.upsert(newPerson, new PartitionKey(partitionKeyValue));
final Mono<PartitionPerson> upsert = cosmosTemplate.upsert(newPerson, new PartitionKey(partitionKeyValue));
StepVerifier.create(upsert).expectNextCount(1).verifyComplete();
}
@ -126,41 +126,43 @@ public class ReactiveCosmosTemplatePartitionIT {
public void testUpdateWithPartition() {
final PartitionPerson updated = new PartitionPerson(TEST_PERSON.getId(), UPDATED_FIRST_NAME,
TEST_PERSON.getLastName(), TEST_PERSON.getHobbies(), TEST_PERSON.getShippingAddresses());
dbTemplate.upsert(updated, new PartitionKey(updated.getLastName())).block();
cosmosTemplate.upsert(updated, new PartitionKey(updated.getLastName())).block();
final PartitionPerson person = dbTemplate.findAll(PartitionPerson.class.getSimpleName(), PartitionPerson.class)
.toStream()
.filter(p -> TEST_PERSON.getId().equals(p.getId())).findFirst().get();
final PartitionPerson person = cosmosTemplate
.findAll(PartitionPerson.class.getSimpleName(), PartitionPerson.class)
.toStream()
.filter(p -> TEST_PERSON.getId().equals(p.getId()))
.findFirst().get();
assertTrue(person.equals(updated));
}
@Test
public void testDeleteByIdPartition() {
dbTemplate.insert(TEST_PERSON_2, new PartitionKey(TEST_PERSON_2.getLastName())).block();
cosmosTemplate.insert(TEST_PERSON_2, new PartitionKey(TEST_PERSON_2.getLastName())).block();
System.out.println("TEST_PERSON_2 = " + TEST_PERSON_2);
StepVerifier.create(dbTemplate.findAll(PartitionPerson.class)).expectNextCount(2).verifyComplete();
StepVerifier.create(cosmosTemplate.findAll(PartitionPerson.class)).expectNextCount(2).verifyComplete();
dbTemplate.deleteById(PartitionPerson.class.getSimpleName(),
cosmosTemplate.deleteById(PartitionPerson.class.getSimpleName(),
TEST_PERSON.getId(), new PartitionKey(TEST_PERSON.getLastName())).block();
StepVerifier.create(dbTemplate.findAll(PartitionPerson.class))
StepVerifier.create(cosmosTemplate.findAll(PartitionPerson.class))
.expectNext(TEST_PERSON_2)
.verifyComplete();
}
@Test
public void testCountForPartitionedCollection() {
StepVerifier.create(dbTemplate.count(containerName)).expectNext((long) 1).verifyComplete();
dbTemplate.insert(TEST_PERSON_2, new PartitionKey(TEST_PERSON_2.getLastName())).block();
StepVerifier.create(dbTemplate.count(containerName)).expectNext((long) 2).verifyComplete();
StepVerifier.create(cosmosTemplate.count(containerName)).expectNext((long) 1).verifyComplete();
cosmosTemplate.insert(TEST_PERSON_2, new PartitionKey(TEST_PERSON_2.getLastName())).block();
StepVerifier.create(cosmosTemplate.count(containerName)).expectNext((long) 2).verifyComplete();
}
@Test
public void testCountForPartitionedCollectionByQuery() {
dbTemplate.insert(TEST_PERSON_2, new PartitionKey(TEST_PERSON_2.getLastName())).block();
cosmosTemplate.insert(TEST_PERSON_2, new PartitionKey(TEST_PERSON_2.getLastName())).block();
final Criteria criteria = Criteria.getInstance(IS_EQUAL, "firstName",
Arrays.asList(TEST_PERSON_2.getFirstName()));
final DocumentQuery query = new DocumentQuery(criteria);
StepVerifier.create(dbTemplate.count(query, containerName)).expectNext((long) 1).verifyComplete();
StepVerifier.create(cosmosTemplate.count(query, containerName)).expectNext((long) 1).verifyComplete();
}
}

Просмотреть файл

@ -1,5 +1,6 @@
cosmosdb.uri=${DOCUMENTDB_URI}
cosmosdb.key=${DOCUMENTDB_KEY}
cosmosdb.secondaryKey=${COSMOSDB_SECONDARY_KEY}
#You can also use connection string instead of uri and key to connect to cosmos DB
#cosmosdb.connection-string=${DOCUMENTDB_CONNECTION_STRING}