|
15 | 15 | package com.amazonaws.services.dynamodbv2.datamodeling;
|
16 | 16 |
|
17 | 17 | import static org.junit.Assert.assertEquals;
|
| 18 | +import static org.junit.Assert.assertFalse; |
18 | 19 | import static org.junit.Assert.assertNull;
|
| 20 | +import static org.junit.Assert.assertTrue; |
| 21 | +import static org.junit.Assert.fail; |
19 | 22 |
|
20 | 23 | import java.nio.ByteBuffer;
|
21 | 24 | import java.security.GeneralSecurityException;
|
|
34 | 37 | import javax.crypto.SecretKey;
|
35 | 38 | import javax.crypto.spec.SecretKeySpec;
|
36 | 39 |
|
| 40 | +import com.amazonaws.ClientConfiguration; |
| 41 | +import com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException; |
37 | 42 | import org.junit.Before;
|
38 | 43 | import org.junit.Test;
|
39 | 44 |
|
@@ -323,6 +328,75 @@ public void simpleSaveLoad() {
|
323 | 328 | assertNull(mapper.load(Mixed.class, 0, 15));
|
324 | 329 | }
|
325 | 330 |
|
| 331 | + /** |
| 332 | + * This test ensures that optimistic locking can be successfully done through the {@link DynamoDBMapper} when |
| 333 | + * combined with the @{link AttributeEncryptor}. Specifically it checks that {@link SaveBehavior#PUT} properly |
| 334 | + * enforces versioning and will result in a {@link ConditionalCheckFailedException} when optimistic locking should |
| 335 | + * prevent a write. Finally, it checks that {@link SaveBehavior#CLOBBER} properly ignores optimistic locking and |
| 336 | + * overwrites the old value. |
| 337 | + */ |
| 338 | + @Test |
| 339 | + public void optimisticLockingTest() { |
| 340 | + DynamoDBMapper mapper = new DynamoDBMapper(client, |
| 341 | + DynamoDBMapperConfig.builder() |
| 342 | + .withSaveBehavior(SaveBehavior.PUT).build(), |
| 343 | + new AttributeEncryptor(symProv)); |
| 344 | + DynamoDBMapper clobberMapper = new DynamoDBMapper(client, CLOBBER_CONFIG, new AttributeEncryptor(symProv)); |
| 345 | + |
| 346 | + /* |
| 347 | + * Lineage of objects |
| 348 | + * expected -> v1 -> v2 -> v3 |
| 349 | + * | |
| 350 | + * -> v2_2 -> clobbered |
| 351 | + * Splitting the lineage after v1 is what should |
| 352 | + * cause the ConditionalCheckFailedException. |
| 353 | + */ |
| 354 | + final int hashKey = 0; |
| 355 | + final int rangeKey = 15; |
| 356 | + final Mixed expected = new Mixed(); |
| 357 | + expected.setHashKey(hashKey); |
| 358 | + expected.setRangeKey(rangeKey); |
| 359 | + expected.setIntSet(new HashSet<Integer>()); |
| 360 | + expected.getIntSet().add(3); |
| 361 | + expected.getIntSet().add(5); |
| 362 | + expected.getIntSet().add(7); |
| 363 | + expected.setDoubleValue(15); |
| 364 | + expected.setStringValue("Blargh!"); |
| 365 | + expected.setDoubleSet( |
| 366 | + new HashSet<Double>(Arrays.asList(15.0D, 7.6D, -3D, -34.2D, 0.0D))); |
| 367 | + |
| 368 | + mapper.save(expected); |
| 369 | + Mixed v1 = mapper.load(Mixed.class, hashKey, rangeKey); |
| 370 | + assertEquals(expected, v1); |
| 371 | + v1.setStringValue("New value"); |
| 372 | + mapper.save(v1); |
| 373 | + Mixed v2 = mapper.load(Mixed.class, hashKey, rangeKey); |
| 374 | + assertEquals(v1, v2); |
| 375 | + Mixed v2_2 = mapper.load(Mixed.class, hashKey, rangeKey); |
| 376 | + |
| 377 | + v2.getIntSet().add(-37); |
| 378 | + mapper.save(v2); |
| 379 | + Mixed v3 = mapper.load(Mixed.class, hashKey, rangeKey); |
| 380 | + assertEquals(v2, v3); |
| 381 | + assertTrue(v3.getIntSet().contains(-37)); |
| 382 | + |
| 383 | + // This should fail due to optimistic locking |
| 384 | + v2_2.getIntSet().add(38); |
| 385 | + try { |
| 386 | + mapper.save(v2_2); |
| 387 | + fail("Expected ConditionalCheckFailedException"); |
| 388 | + } catch (ConditionalCheckFailedException ex) { |
| 389 | + // Expected exception |
| 390 | + } |
| 391 | + |
| 392 | + // Force the update with clobber |
| 393 | + clobberMapper.save(v2_2); |
| 394 | + Mixed clobbered = mapper.load(Mixed.class, hashKey, rangeKey); |
| 395 | + assertEquals(v2_2, clobbered); |
| 396 | + assertTrue(clobbered.getIntSet().contains(38)); |
| 397 | + assertFalse(clobbered.getIntSet().contains(-37)); |
| 398 | + } |
| 399 | + |
326 | 400 | @Test
|
327 | 401 | public void leadingAndTrailingZeros() {
|
328 | 402 | DynamoDBMapper mapper = new DynamoDBMapper(client, CLOBBER_CONFIG, new AttributeEncryptor(symProv));
|
|
0 commit comments