Skip to content

Feature/dynamodb enhanced increase functional tests coverage - #6946

Merged
alextwoods merged 2 commits into
aws:masterfrom
iulianbudau:feature/dynamodb-enhanced-increase-functional-tests-coverage
Aug 13, 2026
Merged

Feature/dynamodb enhanced increase functional tests coverage#6946
alextwoods merged 2 commits into
aws:masterfrom
iulianbudau:feature/dynamodb-enhanced-increase-functional-tests-coverage

Conversation

@iulianbudau

@iulianbudau iulianbudau commented May 7, 2026

Copy link
Copy Markdown
Contributor

Motivation and Context

The goal of this work is to increase functional tests coverage of the aws-sdk-java-v2/services-custom/dynamodb-enhanced module through cross configuration (e.g. mixed schema types, shared client behavior, mixed extensions interaction) scenarios to prevent regressions for future changes.

This PR also includes a bugfix in AutoGeneratedTimestampRecordExtension: when a custom or third-party TableSchema does not support converterForAttribute (default method throws UnsupportedOperationException), the extension now skips timestamp insertion for that attribute instead of failing the write. The same handling applies for nested schemas.

Testing

Expanded functional tests with scenarios on the below cross configurations:

  • Mixed-schema multi-table request scenarios
  • Shared client cross-table behavior
  • Extensions interaction combinations
  • Nested/flattened cross-operation invariants
  • @DynamoDbConvertedBy list-attribute regression coverage for AutoGeneratedTimestampRecordExtension across put/update/batchWrite/transact (sync and async)
  • Extension SPI contract tests for standalone extensions (AutoGeneratedTimestampRecordExtension, AutoGeneratedUuidExtension, AtomicCounterExtension, VersionedRecordExtension) verifying graceful no-op behavior when optional capabilities are absent, across put/update/batchWrite/transact write operations

Screenshots (if appropriate)

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Checklist

  • I have read the CONTRIBUTING document
  • Local run of mvn install succeeds
  • My code follows the code style of this project
  • My change requires a change to the Javadoc documentation
  • I have updated the Javadoc documentation accordingly
  • I have added tests to cover my changes
  • All new and existing tests passed
  • I have added a changelog entry. Adding a new entry must be accomplished by running the scripts/new-change script and following the instructions. Commit the new file created by the script in .changes/next-release with your changes.
  • My change is to implement 1.11 parity feature and I have updated LaunchChangelog

License

  • I confirm that this pull request can be released under the Apache 2 license

@iulianbudau
iulianbudau requested a review from a team as a code owner May 7, 2026 09:41
…verage

refactoring

Added changelog file for "Increase functional tests coverage on dynamodb-enhanced module"

removed fully qualified references
@iulianbudau
iulianbudau force-pushed the feature/dynamodb-enhanced-increase-functional-tests-coverage branch from edd446a to 08b4044 Compare June 23, 2026 14:36
@@ -0,0 +1,6 @@
{
"type": "feature",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I'd argue this should be a bugfix rather than a feature - I notice there are more than just test changes in the PR - we're including additional bugfixes in the AutoGeneratedTimestampRecordExtensionnced - that should be mentioned in the description as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the changelog entry to bugfix and adjusted the description to call out the AutoGeneratedTimestampRecordExtension change for converterForAttribute throwing UnsupportedOperationException. I also updated the PR description to mention that bugfix.

AttributeConverter<?> converter;
try {
converter = nestedSchema.converterForAttribute(key);
} catch (UnsupportedOperationException e) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do the test cases actually cover this? When I removed this check, all the tests still passed which implies we don't actually have sufficient coverage of a nested schema case that hits this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added coverage specifically for nested schemas that throw UnsupportedOperationException from converterForAttribute. This is now exercised by AutoGeneratedTimestampExtensionTest#beforeWrite_nestedSchemaWithoutConverterForAttribute_doesNotThrow_nestedTimestampsSkipped, which verifies the write does not fail and nested timestamp insertion is skipped.

@Test
public void queryRecords_withEmptyProjectionString_shouldThrowAssertionError() {
insertNestedRecords();
assertThatExceptionOfType(AssertionError.class).isThrownBy(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this test could pass for the wrong reason since its just looking for assertion failures in drain publisher.

I think we can change this to use the existing drainPublisherToError and then look for CompletionException. (and update the test name)

Note - I think this comment applies to a few tests:

  • AsyncBasicQueryTest.queryRecords_withEmptyProjectionString_shouldThrowAssertionError
  • AsyncBasicQueryTest.queryRecords_withEmptyNestedProjectionName_shouldThrowAssertionError
  • AsyncBasicScanTest.scanRecords_withEmptyNestedAttributeName_shouldThrowAssertionError
  • AsyncBasicScanTest.scanRecords_withEmptyTopLevelAttributeName_shouldThrowAssertionError

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated these tests to use drainPublisherToError and assert CompletionException, and renamed them accordingly. This applies to the empty projection/attribute-name cases in AsyncBasicQueryTest and AsyncBasicScanTest.

Comment on lines +42 to +44
assertThat(persisted.getDefaultCounter()).isEqualTo(2L);
assertThat(persisted.getCustomCounter()).isEqualTo(20L);
assertThat(persisted.getDecreasingCounter()).isEqualTo(-22L);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These feel like magic numbers. Where do they come from? We should at least comment how they were derived so that when they fail in the future we can understand why

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a comment explaining how the expected counter values are derived from the AtomicCounterRecord annotation defaults (start / delta) across the three updateItem calls.

Comment on lines +247 to +249
assertThat(persisted.getDefaultCounter()).isEqualTo(1L);
assertThat(persisted.getCustomCounter()).isEqualTo(15L);
assertThat(persisted.getDecreasingCounter()).isEqualTo(-21L);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These feel like magic numbers. Where do they come from? We should at least comment how they were derived so that when they fail in the future we can understand why

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a comment explaining how the expected counter values are derived from the AtomicCounterRecord annotation defaults (start / delta) for the put followed by a conditioned update.

@@ -0,0 +1,46 @@
package software.amazon.awssdk.enhanced.dynamodb.functionaltests;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: This file, along with other new ones are missing the copyright header.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the standard Apache 2.0 copyright header to the new async test files called out here, including AsyncAtomicCounterTest, AsyncAutoGeneratedUuidRecordTest, AsyncUpdateBehaviorTest, AsyncUpdateExpressionTest, and AsyncVersionedRecordTest.

.setter(Record2::setAttribute))
.build();

private static final TableSchema<TimestampedRecord> TIMESTAMPED_TABLE_SCHEMA =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the TimestampedRecord and this TIMESTAMPED_TABLE_SCHEMA table schema are repeated in a number of places - should probably be extracted

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I extracted the shared TimestampedRecord model and schema into functionaltests.models.TimestampedRecord and updated the batch/transact write tests (sync and async) to use TimestampedRecord.TABLE_SCHEMA.

Comment on lines +593 to +604
String extensionTableName = getConcreteTableName("doc-extension-table");
DynamoDbEnhancedClient extensionClient = DynamoDbEnhancedClient.builder()
.dynamoDbClient(getDynamoDbClient())
.extensions(AutoGeneratedTimestampRecordExtension.create())
.build();
DynamoDbTable<EnhancedDocument> extensionTable =
extensionClient.table(extensionTableName,
TableSchema.documentSchemaBuilder()
.addIndexPartitionKey(TableMetadata.primaryIndexName(), "id", AttributeValueType.S)
.attributeConverterProviders(defaultProvider())
.build());
extensionTable.createTable(r -> r.provisionedThroughput(getDefaultProvisionedThroughput()));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a lot of duplicated code between the new methods

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reduced the duplicated setup by introducing shared helpers for creating the extension client/table and cleaning up the table in the dedicated document extension CRUD test classes.

}

@Test
public void documentSchema_withExtension_putAndUpdate_shouldSucceed() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like these tests do not depend on the Paramaterized testData at all - which I believe means they will get run 10x+ times with identical data (and report the same success/failure many times). Assuming that is true, these should be moved out to a non parameterized test class.
I think this applies for the BasicAsyncCrudTest as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved these document-schema extension scenarios out of the parameterized BasicCrudTest / BasicAsyncCrudTest into DocumentSchemaExtensionCrudTest and DocumentSchemaExtensionAsyncCrudTest, since they do not depend on testData.

@alextwoods

Copy link
Copy Markdown
Contributor

CI passes in: #7272

@alextwoods
alextwoods merged commit 1c845aa into aws:master Aug 13, 2026
9 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants