1717
1818import static org .assertj .core .api .Assertions .assertThat ;
1919import static org .assertj .core .api .Assertions .assertThatThrownBy ;
20- import static org .junit .Assert .assertEquals ;
21- import static org .junit .Assert .assertThrows ;
22- import static org .junit .Assert .assertTrue ;
2320
2421import org .assertj .core .data .Offset ;
2522import org .junit .After ;
2623import org .junit .AfterClass ;
2724import org .junit .BeforeClass ;
2825import org .junit .Test ;
29- import software .amazon .awssdk .enhanced .dynamodb .extensions .VersionedRecordExtension ;
3026import software .amazon .awssdk .enhanced .dynamodb .model .DeleteItemEnhancedRequest ;
3127import software .amazon .awssdk .enhanced .dynamodb .model .DeleteItemEnhancedResponse ;
3228import software .amazon .awssdk .enhanced .dynamodb .model .EnhancedLocalSecondaryIndex ;
3329import software .amazon .awssdk .enhanced .dynamodb .model .GetItemEnhancedResponse ;
3430import software .amazon .awssdk .enhanced .dynamodb .model .PutItemEnhancedRequest ;
3531import software .amazon .awssdk .enhanced .dynamodb .model .PutItemEnhancedResponse ;
3632import software .amazon .awssdk .enhanced .dynamodb .model .Record ;
37- import software .amazon .awssdk .enhanced .dynamodb .model .TransactDeleteItemEnhancedRequest ;
38- import software .amazon .awssdk .enhanced .dynamodb .model .TransactWriteItemsEnhancedRequest ;
3933import software .amazon .awssdk .enhanced .dynamodb .model .UpdateItemEnhancedRequest ;
4034import software .amazon .awssdk .enhanced .dynamodb .model .UpdateItemEnhancedResponse ;
41- import software .amazon .awssdk .enhanced .dynamodb .model .VersionedRecord ;
4235import software .amazon .awssdk .services .dynamodb .DynamoDbClient ;
43- import software .amazon .awssdk .services .dynamodb .model .AttributeValue ;
4436import software .amazon .awssdk .services .dynamodb .model .ConditionalCheckFailedException ;
4537import software .amazon .awssdk .services .dynamodb .model .ConsumedCapacity ;
4638import software .amazon .awssdk .services .dynamodb .model .Projection ;
4739import software .amazon .awssdk .services .dynamodb .model .ProjectionType ;
4840import software .amazon .awssdk .services .dynamodb .model .ReturnConsumedCapacity ;
4941import software .amazon .awssdk .services .dynamodb .model .ReturnItemCollectionMetrics ;
5042import software .amazon .awssdk .services .dynamodb .model .ReturnValuesOnConditionCheckFailure ;
51- import software .amazon .awssdk .services .dynamodb .model .TransactionCanceledException ;
5243
5344public class CrudWithResponseIntegrationTest extends DynamoDbEnhancedIntegrationTestBase {
5445
5546 private static final String TABLE_NAME = createTestTableName ();
56- private static final String VERSIONED_TABLE_NAME = createTestTableName ();
5747
5848 private static final EnhancedLocalSecondaryIndex LOCAL_SECONDARY_INDEX =
5949 EnhancedLocalSecondaryIndex .builder ()
@@ -66,39 +56,27 @@ public class CrudWithResponseIntegrationTest extends DynamoDbEnhancedIntegration
6656 private static DynamoDbClient dynamoDbClient ;
6757 private static DynamoDbEnhancedClient enhancedClient ;
6858 private static DynamoDbTable <Record > mappedTable ;
69- private static DynamoDbTable <VersionedRecord > versionedRecordTable ;
7059
7160 @ BeforeClass
7261 public static void beforeClass () {
7362 dynamoDbClient = createDynamoDbClient ();
74- enhancedClient = DynamoDbEnhancedClient .builder ()
75- .dynamoDbClient (dynamoDbClient )
76- .extensions (VersionedRecordExtension .builder ().build ())
77- .build ();
63+ enhancedClient = DynamoDbEnhancedClient .builder ().dynamoDbClient (dynamoDbClient ).build ();
7864 mappedTable = enhancedClient .table (TABLE_NAME , TABLE_SCHEMA );
7965 mappedTable .createTable (r -> r .localSecondaryIndices (LOCAL_SECONDARY_INDEX ));
80- versionedRecordTable = enhancedClient .table (VERSIONED_TABLE_NAME , VERSIONED_RECORD_TABLE_SCHEMA );
81- versionedRecordTable .createTable ();
8266 dynamoDbClient .waiter ().waitUntilTableExists (r -> r .tableName (TABLE_NAME ));
83- dynamoDbClient .waiter ().waitUntilTableExists (r -> r .tableName (VERSIONED_TABLE_NAME ));
8467 }
8568
8669 @ After
8770 public void tearDown () {
8871 mappedTable .scan ()
8972 .items ()
9073 .forEach (record -> mappedTable .deleteItem (record ));
91-
92- versionedRecordTable .scan ()
93- .items ()
94- .forEach (versionedRecord -> versionedRecordTable .deleteItem (versionedRecord ));
9574 }
9675
9776 @ AfterClass
9877 public static void afterClass () {
9978 try {
10079 dynamoDbClient .deleteTable (r -> r .tableName (TABLE_NAME ));
101- dynamoDbClient .deleteTable (r -> r .tableName (VERSIONED_TABLE_NAME ));
10280 } finally {
10381 dynamoDbClient .close ();
10482 }
@@ -343,213 +321,4 @@ public void getItem_set_stronglyConsistent() {
343321 // A strongly consistent read request of an item up to 4 KB requires one read request unit.
344322 assertThat (consumedCapacity .capacityUnits ()).isCloseTo (20.0 , Offset .offset (1.0 ));
345323 }
346-
347- // ========== OPTIMISTIC LOCKING TESTS ==========
348-
349- // 1. deleteItem(T item) - Non-versioned record
350- @ Test
351- public void deleteItem_nonVersionedRecord_shouldSucceed () {
352- Record item = new Record ().setId ("123" ).setSort (10 ).setStringAttribute ("Test Item" );
353- Key recordKey = Key .builder ().partitionValue (item .getId ()).sortValue (item .getSort ()).build ();
354-
355- mappedTable .putItem (item );
356- mappedTable .deleteItem (item );
357-
358- Record deletedItem = mappedTable .getItem (r -> r .key (recordKey ));
359- assertThat (deletedItem ).isNull ();
360- }
361-
362- // 2. deleteItem(T item) - Versioned record, versions match
363- @ Test
364- public void deleteItem_versionedRecord_versionMatch_shouldSucceed () {
365- VersionedRecord item = new VersionedRecord ().setId ("123" ).setSort (10 ).setStringAttribute ("Test Item" );
366- Key recordKey = Key .builder ().partitionValue (item .getId ()).sortValue (item .getSort ()).build ();
367-
368- versionedRecordTable .putItem (item );
369- VersionedRecord savedItem = versionedRecordTable .getItem (r -> r .key (recordKey ));
370- versionedRecordTable .deleteItem (savedItem );
371-
372- VersionedRecord deletedItem = versionedRecordTable .getItem (r -> r .key (recordKey ));
373- assertThat (deletedItem ).isNull ();
374- }
375-
376- // 3. deleteItem(T item, false) - Versioned record, should not use optimistic locking
377- @ Test
378- public void deleteItem_versionedRecord_flagFalse_shouldSucceed () {
379- VersionedRecord item = new VersionedRecord ().setId ("123" ).setSort (10 ).setStringAttribute ("Test Item" );
380- Key recordKey = Key .builder ().partitionValue (item .getId ()).sortValue (item .getSort ()).build ();
381-
382- versionedRecordTable .putItem (item );
383- VersionedRecord savedItem = versionedRecordTable .getItem (r -> r .key (recordKey ));
384-
385- // Update the item to change its version
386- savedItem .setStringAttribute ("Updated Item" );
387- versionedRecordTable .updateItem (savedItem );
388-
389- // Delete with old version but flag=false - should succeed (no optimistic locking)
390- VersionedRecord oldVersionItem = new VersionedRecord ().setId ("123" ).setSort (10 ).setVersion (1 );
391- versionedRecordTable .deleteItem (oldVersionItem , false );
392-
393- VersionedRecord deletedItem = versionedRecordTable .getItem (r -> r .key (recordKey ));
394- assertThat (deletedItem ).isNull ();
395- }
396-
397- // 4. deleteItem(T item, true) - Versioned record, versions match
398- @ Test
399- public void deleteItem_versionedRecord_flagTrue_versionMatch_shouldSucceed () {
400- VersionedRecord item = new VersionedRecord ().setId ("123" ).setSort (10 ).setStringAttribute ("Test Item" );
401- Key recordKey = Key .builder ().partitionValue (item .getId ()).sortValue (item .getSort ()).build ();
402-
403- versionedRecordTable .putItem (item );
404- VersionedRecord savedItem = versionedRecordTable .getItem (r -> r .key (recordKey ));
405- versionedRecordTable .deleteItem (savedItem , true );
406-
407- VersionedRecord deletedItem = versionedRecordTable .getItem (r -> r .key (recordKey ));
408- assertThat (deletedItem ).isNull ();
409- }
410-
411- // 5. deleteItem(T item, true) - Versioned record, versions mismatch
412- @ Test
413- public void deleteItem_versionedRecord_flagTrue_versionMismatch_shouldFail () {
414- VersionedRecord item = new VersionedRecord ().setId ("123" ).setSort (10 ).setStringAttribute ("Test Item" );
415- Key recordKey = Key .builder ().partitionValue (item .getId ()).sortValue (item .getSort ()).build ();
416-
417- versionedRecordTable .putItem (item );
418- VersionedRecord savedItem = versionedRecordTable .getItem (r -> r .key (recordKey ));
419-
420- // Update the item to change its version
421- savedItem .setStringAttribute ("Updated Item" );
422- versionedRecordTable .updateItem (savedItem );
423-
424- // Try to delete with old version and flag=true - should fail
425- VersionedRecord oldVersionItem = new VersionedRecord ().setId ("123" ).setSort (10 ).setVersion (1 );
426-
427- assertThatThrownBy (() -> versionedRecordTable .deleteItem (oldVersionItem , true ))
428- .isInstanceOf (ConditionalCheckFailedException .class )
429- .satisfies (e -> assertThat (e .getMessage ()).contains ("The conditional request failed" ));
430- }
431-
432-
433-
434-
435- // 6. deleteItem(DeleteItemEnhancedRequest) with builder method - versions match
436- @ Test
437- public void deleteItemWithBuilder_versionMatch_shouldSucceed () {
438- VersionedRecord item = new VersionedRecord ().setId ("123" ).setSort (10 ).setStringAttribute ("Test Item" );
439- Key recordKey = Key .builder ().partitionValue (item .getId ()).sortValue (item .getSort ()).build ();
440-
441- versionedRecordTable .putItem (item );
442- VersionedRecord savedItem = versionedRecordTable .getItem (r -> r .key (recordKey ));
443-
444- DeleteItemEnhancedRequest requestWithLocking = DeleteItemEnhancedRequest .builder ()
445- .key (recordKey )
446- .withOptimisticLocking (AttributeValue .builder ().n (savedItem .getVersion ().toString ()).build (), "version" )
447- .build ();
448-
449- versionedRecordTable .deleteItem (requestWithLocking );
450-
451- VersionedRecord deletedItem = versionedRecordTable .getItem (r -> r .key (recordKey ));
452- assertThat (deletedItem ).isNull ();
453- }
454-
455- // 7. deleteItem(DeleteItemEnhancedRequest) with builder method - versions mismatch
456- @ Test
457- public void deleteItemWithBuilder_versionMismatch_shouldFail () {
458- VersionedRecord item = new VersionedRecord ().setId ("123" ).setSort (10 ).setStringAttribute ("Test Item" );
459- Key recordKey = Key .builder ().partitionValue (item .getId ()).sortValue (item .getSort ()).build ();
460-
461- versionedRecordTable .putItem (item );
462-
463- DeleteItemEnhancedRequest requestWithLocking = DeleteItemEnhancedRequest .builder ()
464- .key (recordKey )
465- .withOptimisticLocking (AttributeValue .builder ().n ("999" ).build (), "version" )
466- .build ();
467-
468- assertThatThrownBy (() -> versionedRecordTable .deleteItem (requestWithLocking ))
469- .isInstanceOf (ConditionalCheckFailedException .class )
470- .satisfies (e -> assertThat (e .getMessage ()).contains ("The conditional request failed" ));
471- }
472-
473- // 8. TransactWriteItems.addDeleteItem(T item) - Non-versioned record
474- @ Test
475- public void transactDeleteItem_nonVersionedRecord_shouldSucceed () {
476- Record item = new Record ().setId ("123" ).setSort (10 ).setStringAttribute ("Test Item" );
477- Key recordKey = Key .builder ().partitionValue (item .getId ()).sortValue (item .getSort ()).build ();
478-
479- mappedTable .putItem (item );
480-
481- enhancedClient .transactWriteItems (TransactWriteItemsEnhancedRequest .builder ()
482- .addDeleteItem (mappedTable , item )
483- .build ());
484-
485- Record deletedItem = mappedTable .getItem (r -> r .key (recordKey ));
486- assertThat (deletedItem ).isNull ();
487- }
488-
489- // 9. TransactWriteItems.addDeleteItem(T item) - Versioned record, versions match
490- @ Test
491- public void transactDeleteItem_versionedRecord_versionMatch_shouldSucceed () {
492- VersionedRecord item = new VersionedRecord ().setId ("123" ).setSort (10 ).setStringAttribute ("Test Item" );
493- Key recordKey = Key .builder ().partitionValue (item .getId ()).sortValue (item .getSort ()).build ();
494-
495- versionedRecordTable .putItem (item );
496- VersionedRecord savedItem = versionedRecordTable .getItem (r -> r .key (recordKey ));
497-
498- enhancedClient .transactWriteItems (TransactWriteItemsEnhancedRequest .builder ()
499- .addDeleteItem (versionedRecordTable , savedItem )
500- .build ());
501-
502- VersionedRecord deletedItem = versionedRecordTable .getItem (r -> r .key (recordKey ));
503- assertThat (deletedItem ).isNull ();
504- }
505-
506-
507-
508-
509- // 10. TransactWriteItems with builder method - versions match
510- @ Test
511- public void transactDeleteItemWithBuilder_versionMatch_shouldSucceed () {
512- VersionedRecord item = new VersionedRecord ().setId ("123" ).setSort (10 ).setStringAttribute ("Test Item" );
513- Key recordKey = Key .builder ().partitionValue (item .getId ()).sortValue (item .getSort ()).build ();
514-
515- versionedRecordTable .putItem (item );
516- VersionedRecord savedItem = versionedRecordTable .getItem (r -> r .key (recordKey ));
517-
518- TransactDeleteItemEnhancedRequest requestWithLocking = TransactDeleteItemEnhancedRequest .builder ()
519- .key (recordKey )
520- .withOptimisticLocking (AttributeValue .builder ().n (savedItem .getVersion ().toString ()).build (), "version" )
521- .build ();
522-
523- enhancedClient .transactWriteItems (TransactWriteItemsEnhancedRequest .builder ()
524- .addDeleteItem (versionedRecordTable ,
525- requestWithLocking )
526- .build ());
527-
528- VersionedRecord deletedItem = versionedRecordTable .getItem (r -> r .key (recordKey ));
529- assertThat (deletedItem ).isNull ();
530- }
531-
532- // 11. TransactWriteItems with builder method - versions mismatch
533- @ Test
534- public void transactDeleteItemWithBuilder_versionMismatch_shouldFail () {
535- VersionedRecord item = new VersionedRecord ().setId ("123" ).setSort (10 ).setStringAttribute ("Test Item" );
536- Key recordKey = Key .builder ().partitionValue (item .getId ()).sortValue (item .getSort ()).build ();
537-
538- versionedRecordTable .putItem (item );
539-
540- TransactDeleteItemEnhancedRequest requestWithLocking = TransactDeleteItemEnhancedRequest .builder ()
541- .key (recordKey )
542- .withOptimisticLocking (AttributeValue .builder ().n ("999" ).build (), "version" )
543- .build ();
544-
545- TransactionCanceledException ex = assertThrows (TransactionCanceledException .class ,
546- () -> enhancedClient .transactWriteItems (TransactWriteItemsEnhancedRequest .builder ()
547- .addDeleteItem (versionedRecordTable , requestWithLocking )
548- .build ()));
549-
550- assertTrue (ex .hasCancellationReasons ());
551- assertEquals (1 , ex .cancellationReasons ().size ());
552- assertEquals ("ConditionalCheckFailed" , ex .cancellationReasons ().get (0 ).code ());
553- assertEquals ("The conditional request failed" , ex .cancellationReasons ().get (0 ).message ());
554- }
555- }
324+ }
0 commit comments