Skip to content

Commit

Permalink
Added support for capturing CosmosException diagnostics on Cosmos Rep…
Browse files Browse the repository at this point in the history
…ository and Reactive Cosmos Repository APIs (Azure#25898)

* Added error diagnostics APIs on cosmos exceptions

* Added Annie Liang to contributors list to Spring Data Cosmos

* Fixed build analyze issues with java docs
  • Loading branch information
kushagraThapar authored Dec 9, 2021
1 parent aff2413 commit 4f846ee
Show file tree
Hide file tree
Showing 10 changed files with 178 additions and 69 deletions.
4 changes: 2 additions & 2 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,9 @@
# PRLabel: %Cosmos
/sdk/cosmos/ @moderakh @kushagraThapar @FabianMeiswinkel @kirankumarkolli @mbhaskar @simplynaveen20 @xinlian12 @milismsft @aayush3011
# PRLabel: %azure-spring
/sdk/cosmos/azure-spring-data-cosmos/ @kushagraThapar @mbhaskar @backwind1233 @chenrujun @hui1110 @jialigit @moarychan @saragluna @stliu @yiliuTo
/sdk/cosmos/azure-spring-data-cosmos/ @kushagraThapar @mbhaskar @backwind1233 @chenrujun @hui1110 @jialigit @moarychan @saragluna @stliu @yiliuTo @xinlian12
# PRLabel: %azure-spring
/sdk/cosmos/azure-spring-data-cosmos-test/ @kushagraThapar @mbhaskar @backwind1233 @chenrujun @hui1110 @jialigit @moarychan @saragluna @stliu @yiliuTo
/sdk/cosmos/azure-spring-data-cosmos-test/ @kushagraThapar @mbhaskar @backwind1233 @chenrujun @hui1110 @jialigit @moarychan @saragluna @stliu @yiliuTo @xinlian12

# PRLabel: %Digital Twins
/sdk/digitaltwins/ @johngallardo @efriesner @abhinav-ghai
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
import org.springframework.data.annotation.Persistent;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.query.parser.Part;
Expand Down Expand Up @@ -150,7 +149,8 @@ public void testInsertDuplicateIdShouldFailWithConflictException() {
new PartitionKey(personInfo.getPartitionKeyFieldValue(TEST_PERSON)));
fail();
} catch (CosmosAccessException ex) {
assertThat(ex.getCosmosException() instanceof ConflictException);
assertThat(ex.getCosmosException()).isInstanceOf(ConflictException.class);
assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
}
}

Expand Down Expand Up @@ -191,6 +191,7 @@ public void testFindById() {
final Person nullResult = cosmosTemplate.findById(Person.class.getSimpleName(),
NOT_EXIST_ID, Person.class);
assertThat(nullResult).isNull();
assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
}

@Test
Expand Down Expand Up @@ -220,7 +221,7 @@ public void testUpsertNewDocument() {

final String firstName = NEW_FIRST_NAME
+ "_"
+ UUID.randomUUID().toString();
+ UUID.randomUUID();
final Person newPerson = new Person(TEST_PERSON.getId(), firstName, NEW_FIRST_NAME, null, null,
AGE, PASSPORT_IDS_BY_COUNTRY);

Expand Down Expand Up @@ -277,6 +278,7 @@ public void testOptimisticLockWhenUpdatingWithWrongEtag() {
final Throwable cosmosClientException = e.getCosmosException();
assertThat(cosmosClientException).isInstanceOf(CosmosException.class);
assertThat(cosmosClientException.getMessage()).contains(PRECONDITION_IS_NOT_MET);
assertThat(responseDiagnosticsTestUtils.getDiagnostics()).isNotNull();

final Person unmodifiedPerson = cosmosTemplate.findById(Person.class.getSimpleName(),
TEST_PERSON.getId(), Person.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import com.azure.spring.data.cosmos.CosmosFactory;
import com.azure.spring.data.cosmos.IntegrationTestCollectionManager;
import com.azure.spring.data.cosmos.common.PageTestUtils;
import com.azure.spring.data.cosmos.common.ResponseDiagnosticsTestUtils;
import com.azure.spring.data.cosmos.common.TestConstants;
import com.azure.spring.data.cosmos.common.TestUtils;
import com.azure.spring.data.cosmos.config.CosmosConfig;
Expand Down Expand Up @@ -61,6 +62,7 @@
import static com.azure.spring.data.cosmos.common.TestConstants.ZIP_CODE;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestRepositoryConfig.class)
Expand All @@ -85,6 +87,8 @@ public class CosmosTemplatePartitionIT {
private CosmosConfig cosmosConfig;
@Autowired
private CosmosClientBuilder cosmosClientBuilder;
@Autowired
private ResponseDiagnosticsTestUtils responseDiagnosticsTestUtils;

@Before
public void setUp() throws ClassNotFoundException {
Expand Down Expand Up @@ -196,6 +200,16 @@ public void testFindByIdWithPartition() {
assertEquals(TEST_PERSON, partitionPersonById);
}

@Test
public void testFindByIdWithPartitionNotExists() {
final PartitionPerson partitionPersonById = cosmosTemplate.findById(NOT_EXIST_ID,
PartitionPerson.class,
new PartitionKey(personInfo.getPartitionKeyFieldValue(TEST_PERSON)));

assertNull(partitionPersonById);
assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
}

@Test
public void testFindByNonExistIdWithPartition() {
final Criteria criteria = Criteria.getInstance(CriteriaType.IS_EQUAL, PROPERTY_ID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@
import static com.azure.spring.data.cosmos.common.TestConstants.LAST_NAME;
import static com.azure.spring.data.cosmos.common.TestConstants.PASSPORT_IDS_BY_COUNTRY;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
Expand Down Expand Up @@ -150,8 +148,11 @@ public void testInsertDuplicateId() {
final Mono<Person> insertMono = cosmosTemplate.insert(TEST_PERSON,
new PartitionKey(personInfo.getPartitionKeyFieldValue(TEST_PERSON)));
StepVerifier.create(insertMono)
.expectErrorMatches(ex -> ex instanceof CosmosAccessException && ((CosmosAccessException) ex).getCosmosException() instanceof ConflictException)
.expectErrorMatches(ex -> ex instanceof CosmosAccessException &&
((CosmosAccessException) ex).getCosmosException() instanceof ConflictException)
.verify();

assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
}

@Test
Expand All @@ -174,8 +175,8 @@ public void testFindByIDBySecondaryKey() {
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())));
Assert.assertEquals(actual.getFirstName(), TEST_PERSON.getFirstName());
Assert.assertEquals(actual.getLastName(), TEST_PERSON.getLastName());
}).verifyComplete();

assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
Expand Down Expand Up @@ -247,6 +248,7 @@ public void testInsertShouldFailIfColumnNotAnnotatedWithAutoGenerate() {
person, new PartitionKey(person.getLastName()));
StepVerifier.create(entityMono).verifyError(CosmosAccessException.class);

assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
}

@Test
Expand Down Expand Up @@ -479,6 +481,7 @@ public void testInvalidSecondaryKey() {
StepVerifier.create(findById)
.expectError(CosmosAccessException.class)
.verify();
assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import com.azure.cosmos.models.SqlQuerySpec;
import com.azure.spring.data.cosmos.CosmosFactory;
import com.azure.spring.data.cosmos.ReactiveIntegrationTestCollectionManager;
import com.azure.spring.data.cosmos.common.ResponseDiagnosticsTestUtils;
import com.azure.spring.data.cosmos.common.TestConstants;
import com.azure.spring.data.cosmos.config.CosmosConfig;
import com.azure.spring.data.cosmos.core.convert.MappingCosmosConverter;
Expand All @@ -22,6 +23,7 @@
import com.azure.spring.data.cosmos.domain.PartitionPerson;
import com.azure.spring.data.cosmos.repository.TestRepositoryConfig;
import com.azure.spring.data.cosmos.repository.support.CosmosEntityInformation;
import org.assertj.core.api.Assertions;
import org.junit.Assert;
import org.junit.Before;
import org.junit.ClassRule;
Expand All @@ -42,9 +44,8 @@
import java.util.Map;
import java.util.UUID;

import static com.azure.spring.data.cosmos.common.TestConstants.NOT_EXIST_ID;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;

@RunWith(SpringJUnit4ClassRunner.class)
Expand Down Expand Up @@ -72,6 +73,8 @@ public class ReactiveCosmosTemplatePartitionIT {
private CosmosConfig cosmosConfig;
@Autowired
private CosmosClientBuilder cosmosClientBuilder;
@Autowired
private ResponseDiagnosticsTestUtils responseDiagnosticsTestUtils;

@Before
public void setUp() throws ClassNotFoundException {
Expand Down Expand Up @@ -105,9 +108,13 @@ public void testFindWithPartition() {
PartitionPerson.class,
PartitionPerson.class.getSimpleName());
StepVerifier.create(partitionPersonFlux).consumeNextWith(actual -> {
Assert.assertThat(actual.getFirstName(), is(equalTo(TEST_PERSON.getFirstName())));
Assert.assertThat(actual.getZipCode(), is(equalTo(TEST_PERSON.getZipCode())));
Assert.assertEquals(actual.getFirstName(), TEST_PERSON.getFirstName());
Assert.assertEquals(actual.getZipCode(), TEST_PERSON.getZipCode());
}).verifyComplete();

assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
Assertions.assertThat(responseDiagnosticsTestUtils.getCosmosResponseStatistics()).isNotNull();
Assertions.assertThat(responseDiagnosticsTestUtils.getCosmosResponseStatistics().getRequestCharge()).isGreaterThan(0);
}

@Test
Expand All @@ -120,8 +127,8 @@ public void testFindWithPartitionWithQueryPlanCachingEnabled() {
PartitionPerson.class,
PartitionPerson.class.getSimpleName());
StepVerifier.create(partitionPersonFlux).consumeNextWith(actual -> {
Assert.assertThat(actual.getFirstName(), is(equalTo(TEST_PERSON.getFirstName())));
Assert.assertThat(actual.getZipCode(), is(equalTo(TEST_PERSON.getZipCode())));
Assert.assertEquals(actual.getFirstName(), TEST_PERSON.getFirstName());
Assert.assertEquals(actual.getZipCode(), TEST_PERSON.getZipCode());
}).verifyComplete();

CosmosAsyncClient cosmosAsyncClient = cosmosFactory.getCosmosAsyncClient();
Expand All @@ -141,8 +148,8 @@ public void testFindWithPartitionWithQueryPlanCachingEnabled() {
PartitionPerson.class,
PartitionPerson.class.getSimpleName());
StepVerifier.create(partitionPersonFlux).consumeNextWith(actual -> {
Assert.assertThat(actual.getFirstName(), is(equalTo(TEST_PERSON_2.getFirstName())));
Assert.assertThat(actual.getZipCode(), is(equalTo(TEST_PERSON_2.getZipCode())));
Assert.assertEquals(actual.getFirstName(), TEST_PERSON_2.getFirstName());
Assert.assertEquals(actual.getZipCode(), TEST_PERSON_2.getZipCode());
}).verifyComplete();

Map<String, PartitionedQueryExecutionInfo> postQueryCallCache = asyncDocumentClient.getQueryPlanCache();
Expand All @@ -159,9 +166,13 @@ public void testFindIgnoreCaseWithPartition() {
PartitionPerson.class,
PartitionPerson.class.getSimpleName());
StepVerifier.create(partitionPersonFlux).consumeNextWith(actual -> {
Assert.assertThat(actual.getFirstName(), is(equalTo(TEST_PERSON.getFirstName())));
Assert.assertThat(actual.getZipCode(), is(equalTo(TEST_PERSON.getZipCode())));
Assert.assertEquals(actual.getFirstName(), TEST_PERSON.getFirstName());
Assert.assertEquals(actual.getZipCode(), TEST_PERSON.getZipCode());
}).verifyComplete();

assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
Assertions.assertThat(responseDiagnosticsTestUtils.getCosmosResponseStatistics()).isNotNull();
Assertions.assertThat(responseDiagnosticsTestUtils.getCosmosResponseStatistics().getRequestCharge()).isGreaterThan(0);
}


Expand All @@ -171,15 +182,22 @@ public void testFindByIdWithPartition() {
PartitionPerson.class,
new PartitionKey(personInfo.getPartitionKeyFieldValue(TEST_PERSON)));
StepVerifier.create(partitionPersonMono).consumeNextWith(actual -> {
Assert.assertThat(actual.getFirstName(), is(equalTo(TEST_PERSON.getFirstName())));
Assert.assertThat(actual.getZipCode(), is(equalTo(TEST_PERSON.getZipCode())));
Assert.assertEquals(actual.getFirstName(), TEST_PERSON.getFirstName());
Assert.assertEquals(actual.getZipCode(), TEST_PERSON.getZipCode());
}).verifyComplete();

assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
}

// @Test
// public void testFindByNonExistIdWithPartition() {
//
// }
@Test
public void testFindByIdWithPartitionNotExists() {
final Mono<PartitionPerson> partitionPersonMono = cosmosTemplate.findById(NOT_EXIST_ID,
PartitionPerson.class,
new PartitionKey(personInfo.getPartitionKeyFieldValue(TEST_PERSON)));
StepVerifier.create(partitionPersonMono).expectNextCount(0).verifyComplete();

assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
}

@Test
public void testUpsertNewDocumentPartition() {
Expand All @@ -189,6 +207,8 @@ public void testUpsertNewDocumentPartition() {
null, null);
final Mono<PartitionPerson> upsert = cosmosTemplate.upsert(newPerson);
StepVerifier.create(upsert).expectNextCount(1).verifyComplete();

assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
}

@Test
Expand All @@ -204,6 +224,10 @@ public void testUpdateWithPartition() {
.filter(p -> TEST_PERSON.getId().equals(p.getId()))
.findFirst().get();
assertEquals(person, updated);

assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
Assertions.assertThat(responseDiagnosticsTestUtils.getCosmosResponseStatistics()).isNotNull();
Assertions.assertThat(responseDiagnosticsTestUtils.getCosmosResponseStatistics().getRequestCharge()).isGreaterThan(0);
}

@Test
Expand All @@ -216,6 +240,10 @@ public void testDeleteByIdPartition() {
StepVerifier.create(cosmosTemplate.findAll(PartitionPerson.class))
.expectNext(TEST_PERSON_2)
.verifyComplete();

assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
Assertions.assertThat(responseDiagnosticsTestUtils.getCosmosResponseStatistics()).isNotNull();
Assertions.assertThat(responseDiagnosticsTestUtils.getCosmosResponseStatistics().getRequestCharge()).isGreaterThan(0);
}

@Test
Expand All @@ -226,6 +254,10 @@ public void testDeleteAll() {
StepVerifier.create(cosmosTemplate.findAll(PartitionPerson.class))
.expectNextCount(0)
.verifyComplete();

assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
Assertions.assertThat(responseDiagnosticsTestUtils.getCosmosResponseStatistics()).isNotNull();
Assertions.assertThat(responseDiagnosticsTestUtils.getCosmosResponseStatistics().getRequestCharge()).isGreaterThan(0);
}

@Test
Expand All @@ -235,6 +267,10 @@ public void testCountForPartitionedCollection() {
cosmosTemplate.insert(TEST_PERSON_2, new PartitionKey(TEST_PERSON_2.getZipCode())).block();
StepVerifier.create(cosmosTemplate.count(containerName))
.expectNext((long) 2).verifyComplete();

assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
Assertions.assertThat(responseDiagnosticsTestUtils.getCosmosResponseStatistics()).isNotNull();
Assertions.assertThat(responseDiagnosticsTestUtils.getCosmosResponseStatistics().getRequestCharge()).isGreaterThan(0);
}

@Test
Expand All @@ -245,6 +281,10 @@ public void testCountForPartitionedCollectionByQuery() {
final CosmosQuery query = new CosmosQuery(criteria);
StepVerifier.create(cosmosTemplate.count(query, containerName))
.expectNext((long) 1).verifyComplete();

assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
Assertions.assertThat(responseDiagnosticsTestUtils.getCosmosResponseStatistics()).isNotNull();
Assertions.assertThat(responseDiagnosticsTestUtils.getCosmosResponseStatistics().getRequestCharge()).isGreaterThan(0);
}

@Test
Expand All @@ -255,6 +295,10 @@ public void testCountIgnoreCaseForPartitionedCollectionByQuery() {
final CosmosQuery queryIgnoreCase = new CosmosQuery(criteriaIgnoreCase);
StepVerifier.create(cosmosTemplate.count(queryIgnoreCase, containerName))
.expectNext((long) 1).verifyComplete();

assertThat(responseDiagnosticsTestUtils.getCosmosDiagnostics()).isNotNull();
Assertions.assertThat(responseDiagnosticsTestUtils.getCosmosResponseStatistics()).isNotNull();
Assertions.assertThat(responseDiagnosticsTestUtils.getCosmosResponseStatistics().getRequestCharge()).isGreaterThan(0);
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -173,16 +173,6 @@ public void testCustomQuery() {

}

@Test
@Ignore // TODO(kuthapar): v3 doesn't support creation of items without id.
public void testNullIdContact() {
final Contact nullIdContact = new Contact(null, "testTitile");
final Contact savedContact = repository.save(nullIdContact);

Assert.assertNotNull(savedContact.getLogicId());
Assert.assertEquals(nullIdContact.getTitle(), savedContact.getTitle());
}

@Test
public void testFindById() {
final Optional<Contact> optional = repository.findById(TEST_CONTACT1.getLogicId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package com.azure.spring.data.cosmos.common;

import com.azure.cosmos.CosmosDiagnostics;
import com.azure.cosmos.CosmosException;
import com.azure.cosmos.models.FeedResponse;
import com.azure.spring.data.cosmos.core.ResponseDiagnostics;
import com.azure.spring.data.cosmos.core.ResponseDiagnosticsProcessor;
Expand Down Expand Up @@ -50,6 +51,22 @@ public static <T> void fillAndProcessResponseDiagnostics(
responseDiagnosticsProcessor.processResponseDiagnostics(responseDiagnostics);
}

/**
* Generate ResponseDiagnostics with CosmosException diagnostics
* @param responseDiagnosticsProcessor response diagnostics processor
* @param cosmosException cosmos exception
*/
public static void fillAndProcessCosmosExceptionDiagnostics(ResponseDiagnosticsProcessor responseDiagnosticsProcessor,
CosmosException cosmosException) {
if (responseDiagnosticsProcessor == null) {
return;
}
if (cosmosException == null || cosmosException.getDiagnostics() == null) {
return;
}
fillAndProcessResponseDiagnostics(responseDiagnosticsProcessor, cosmosException.getDiagnostics(), null);
}

/**
* ID value should be string value, real id type will be String, Integer, Long,
* all of these must be converted to String type.
Expand Down
Loading

0 comments on commit 4f846ee

Please sign in to comment.