@Test void testUpdatePutDatabaseDown() { DynamoDbClient client = mock(DynamoDbClient.class); UsersDao usersDao = new DynamoDbUsersDao(client, "testTable", MAPPER); when(client.getItem(eq(GET_REQUEST))) .thenReturn(GetItemResponse.builder().item(ITEM).build()); when(client.putItem(any(PutItemRequest.class))) .thenThrow(SdkException.class); DatabaseException e = assertThrows(DatabaseException.class, () -> usersDao.update(null, USER)); assertEquals(DatabaseError.DATABASE_DOWN, e.getErrorKind()); verify(client, times(1)).getItem(eq(GET_REQUEST)); verify(client, times(1)).putItem(any(PutItemRequest.class)); }
@Override public User update(@Nullable String existingEmail, User user) { Objects.requireNonNull(user); if (existingEmail != null && !existingEmail.equals(user.getEmail().getAddress())) { LOG.info("User to update has new email. The user will be deleted and then reinserted."); return updateEmail(existingEmail, user); } GetItemRequest request = GetItemRequest.builder() .tableName(tableName) .key(Collections.singletonMap("email", AttributeValue.builder().s(user.getEmail().getAddress()).build())) .build(); GetItemResponse response; try { response = dynamoDbClient.getItem(request); } catch (SdkException e) { LOG.error("The database is currently unresponsive.", e); throw new DatabaseException("The database is currently unavailable.", DatabaseError.DATABASE_DOWN); } if (response.item().size() <= 0) { LOG.warn("The user {} was not found in the database.", user.getEmail().getAddress()); throw new DatabaseException("The user was not found.", DatabaseError.USER_NOT_FOUND); } long now = Instant.now().toEpochMilli(); String newVersion = UUID.randomUUID().toString(); String document = UsersDao.toJson(mapper, user); Map<String, AttributeValue> newItem = new HashMap<>(); newItem.put("email", response.item().get("email")); newItem.put("id", response.item().get("id")); newItem.put("creation_time", response.item().get("creation_time")); newItem.put("version", AttributeValue.builder().s(newVersion).build()); newItem.put("update_time", AttributeValue.builder().s(String.valueOf(now)).build()); newItem.put("document", AttributeValue.builder().s(document).build()); PutItemRequest putItemRequest = PutItemRequest.builder() .tableName(tableName) .item(newItem) .expected(Collections.singletonMap("version", ExpectedAttributeValue.builder() .comparisonOperator(ComparisonOperator.EQ) .value(response.item().get("version")) .build())) .build(); try { dynamoDbClient.putItem(putItemRequest); } catch (ConditionalCheckFailedException e) { LOG.error("The user was updated while this update was in progress." + " Aborting to avoid race condition.", e); throw new DatabaseException("The user to update is at an unexpected stage.", DatabaseError.CONFLICT); } catch (AwsServiceException e) { LOG.error("The database rejected the update request.", e); throw new DatabaseException("The database rejected the update request.", DatabaseError.REQUEST_REJECTED); } catch (SdkException e) { LOG.error("The database is currently unresponsive.", e); throw new DatabaseException("The database is currently unavailable.", DatabaseError.DATABASE_DOWN); } return user; }
DynamoDbUsersDao implements UsersDao { @Override public User update(@Nullable String existingEmail, User user) { Objects.requireNonNull(user); if (existingEmail != null && !existingEmail.equals(user.getEmail().getAddress())) { LOG.info("User to update has new email. The user will be deleted and then reinserted."); return updateEmail(existingEmail, user); } GetItemRequest request = GetItemRequest.builder() .tableName(tableName) .key(Collections.singletonMap("email", AttributeValue.builder().s(user.getEmail().getAddress()).build())) .build(); GetItemResponse response; try { response = dynamoDbClient.getItem(request); } catch (SdkException e) { LOG.error("The database is currently unresponsive.", e); throw new DatabaseException("The database is currently unavailable.", DatabaseError.DATABASE_DOWN); } if (response.item().size() <= 0) { LOG.warn("The user {} was not found in the database.", user.getEmail().getAddress()); throw new DatabaseException("The user was not found.", DatabaseError.USER_NOT_FOUND); } long now = Instant.now().toEpochMilli(); String newVersion = UUID.randomUUID().toString(); String document = UsersDao.toJson(mapper, user); Map<String, AttributeValue> newItem = new HashMap<>(); newItem.put("email", response.item().get("email")); newItem.put("id", response.item().get("id")); newItem.put("creation_time", response.item().get("creation_time")); newItem.put("version", AttributeValue.builder().s(newVersion).build()); newItem.put("update_time", AttributeValue.builder().s(String.valueOf(now)).build()); newItem.put("document", AttributeValue.builder().s(document).build()); PutItemRequest putItemRequest = PutItemRequest.builder() .tableName(tableName) .item(newItem) .expected(Collections.singletonMap("version", ExpectedAttributeValue.builder() .comparisonOperator(ComparisonOperator.EQ) .value(response.item().get("version")) .build())) .build(); try { dynamoDbClient.putItem(putItemRequest); } catch (ConditionalCheckFailedException e) { LOG.error("The user was updated while this update was in progress." + " Aborting to avoid race condition.", e); throw new DatabaseException("The user to update is at an unexpected stage.", DatabaseError.CONFLICT); } catch (AwsServiceException e) { LOG.error("The database rejected the update request.", e); throw new DatabaseException("The database rejected the update request.", DatabaseError.REQUEST_REJECTED); } catch (SdkException e) { LOG.error("The database is currently unresponsive.", e); throw new DatabaseException("The database is currently unavailable.", DatabaseError.DATABASE_DOWN); } return user; } }
DynamoDbUsersDao implements UsersDao { @Override public User update(@Nullable String existingEmail, User user) { Objects.requireNonNull(user); if (existingEmail != null && !existingEmail.equals(user.getEmail().getAddress())) { LOG.info("User to update has new email. The user will be deleted and then reinserted."); return updateEmail(existingEmail, user); } GetItemRequest request = GetItemRequest.builder() .tableName(tableName) .key(Collections.singletonMap("email", AttributeValue.builder().s(user.getEmail().getAddress()).build())) .build(); GetItemResponse response; try { response = dynamoDbClient.getItem(request); } catch (SdkException e) { LOG.error("The database is currently unresponsive.", e); throw new DatabaseException("The database is currently unavailable.", DatabaseError.DATABASE_DOWN); } if (response.item().size() <= 0) { LOG.warn("The user {} was not found in the database.", user.getEmail().getAddress()); throw new DatabaseException("The user was not found.", DatabaseError.USER_NOT_FOUND); } long now = Instant.now().toEpochMilli(); String newVersion = UUID.randomUUID().toString(); String document = UsersDao.toJson(mapper, user); Map<String, AttributeValue> newItem = new HashMap<>(); newItem.put("email", response.item().get("email")); newItem.put("id", response.item().get("id")); newItem.put("creation_time", response.item().get("creation_time")); newItem.put("version", AttributeValue.builder().s(newVersion).build()); newItem.put("update_time", AttributeValue.builder().s(String.valueOf(now)).build()); newItem.put("document", AttributeValue.builder().s(document).build()); PutItemRequest putItemRequest = PutItemRequest.builder() .tableName(tableName) .item(newItem) .expected(Collections.singletonMap("version", ExpectedAttributeValue.builder() .comparisonOperator(ComparisonOperator.EQ) .value(response.item().get("version")) .build())) .build(); try { dynamoDbClient.putItem(putItemRequest); } catch (ConditionalCheckFailedException e) { LOG.error("The user was updated while this update was in progress." + " Aborting to avoid race condition.", e); throw new DatabaseException("The user to update is at an unexpected stage.", DatabaseError.CONFLICT); } catch (AwsServiceException e) { LOG.error("The database rejected the update request.", e); throw new DatabaseException("The database rejected the update request.", DatabaseError.REQUEST_REJECTED); } catch (SdkException e) { LOG.error("The database is currently unresponsive.", e); throw new DatabaseException("The database is currently unavailable.", DatabaseError.DATABASE_DOWN); } return user; } @Inject  DynamoDbUsersDao(DynamoDbClient dynamoDbClient, String tableName, ObjectMapper mapper); }
DynamoDbUsersDao implements UsersDao { @Override public User update(@Nullable String existingEmail, User user) { Objects.requireNonNull(user); if (existingEmail != null && !existingEmail.equals(user.getEmail().getAddress())) { LOG.info("User to update has new email. The user will be deleted and then reinserted."); return updateEmail(existingEmail, user); } GetItemRequest request = GetItemRequest.builder() .tableName(tableName) .key(Collections.singletonMap("email", AttributeValue.builder().s(user.getEmail().getAddress()).build())) .build(); GetItemResponse response; try { response = dynamoDbClient.getItem(request); } catch (SdkException e) { LOG.error("The database is currently unresponsive.", e); throw new DatabaseException("The database is currently unavailable.", DatabaseError.DATABASE_DOWN); } if (response.item().size() <= 0) { LOG.warn("The user {} was not found in the database.", user.getEmail().getAddress()); throw new DatabaseException("The user was not found.", DatabaseError.USER_NOT_FOUND); } long now = Instant.now().toEpochMilli(); String newVersion = UUID.randomUUID().toString(); String document = UsersDao.toJson(mapper, user); Map<String, AttributeValue> newItem = new HashMap<>(); newItem.put("email", response.item().get("email")); newItem.put("id", response.item().get("id")); newItem.put("creation_time", response.item().get("creation_time")); newItem.put("version", AttributeValue.builder().s(newVersion).build()); newItem.put("update_time", AttributeValue.builder().s(String.valueOf(now)).build()); newItem.put("document", AttributeValue.builder().s(document).build()); PutItemRequest putItemRequest = PutItemRequest.builder() .tableName(tableName) .item(newItem) .expected(Collections.singletonMap("version", ExpectedAttributeValue.builder() .comparisonOperator(ComparisonOperator.EQ) .value(response.item().get("version")) .build())) .build(); try { dynamoDbClient.putItem(putItemRequest); } catch (ConditionalCheckFailedException e) { LOG.error("The user was updated while this update was in progress." + " Aborting to avoid race condition.", e); throw new DatabaseException("The user to update is at an unexpected stage.", DatabaseError.CONFLICT); } catch (AwsServiceException e) { LOG.error("The database rejected the update request.", e); throw new DatabaseException("The database rejected the update request.", DatabaseError.REQUEST_REJECTED); } catch (SdkException e) { LOG.error("The database is currently unresponsive.", e); throw new DatabaseException("The database is currently unavailable.", DatabaseError.DATABASE_DOWN); } return user; } @Inject  DynamoDbUsersDao(DynamoDbClient dynamoDbClient, String tableName, ObjectMapper mapper); @Override User insert(User user); @Override User findByEmail(String email); @Override User update(@Nullable String existingEmail, User user); @Override User delete(String email); }
DynamoDbUsersDao implements UsersDao { @Override public User update(@Nullable String existingEmail, User user) { Objects.requireNonNull(user); if (existingEmail != null && !existingEmail.equals(user.getEmail().getAddress())) { LOG.info("User to update has new email. The user will be deleted and then reinserted."); return updateEmail(existingEmail, user); } GetItemRequest request = GetItemRequest.builder() .tableName(tableName) .key(Collections.singletonMap("email", AttributeValue.builder().s(user.getEmail().getAddress()).build())) .build(); GetItemResponse response; try { response = dynamoDbClient.getItem(request); } catch (SdkException e) { LOG.error("The database is currently unresponsive.", e); throw new DatabaseException("The database is currently unavailable.", DatabaseError.DATABASE_DOWN); } if (response.item().size() <= 0) { LOG.warn("The user {} was not found in the database.", user.getEmail().getAddress()); throw new DatabaseException("The user was not found.", DatabaseError.USER_NOT_FOUND); } long now = Instant.now().toEpochMilli(); String newVersion = UUID.randomUUID().toString(); String document = UsersDao.toJson(mapper, user); Map<String, AttributeValue> newItem = new HashMap<>(); newItem.put("email", response.item().get("email")); newItem.put("id", response.item().get("id")); newItem.put("creation_time", response.item().get("creation_time")); newItem.put("version", AttributeValue.builder().s(newVersion).build()); newItem.put("update_time", AttributeValue.builder().s(String.valueOf(now)).build()); newItem.put("document", AttributeValue.builder().s(document).build()); PutItemRequest putItemRequest = PutItemRequest.builder() .tableName(tableName) .item(newItem) .expected(Collections.singletonMap("version", ExpectedAttributeValue.builder() .comparisonOperator(ComparisonOperator.EQ) .value(response.item().get("version")) .build())) .build(); try { dynamoDbClient.putItem(putItemRequest); } catch (ConditionalCheckFailedException e) { LOG.error("The user was updated while this update was in progress." + " Aborting to avoid race condition.", e); throw new DatabaseException("The user to update is at an unexpected stage.", DatabaseError.CONFLICT); } catch (AwsServiceException e) { LOG.error("The database rejected the update request.", e); throw new DatabaseException("The database rejected the update request.", DatabaseError.REQUEST_REJECTED); } catch (SdkException e) { LOG.error("The database is currently unresponsive.", e); throw new DatabaseException("The database is currently unavailable.", DatabaseError.DATABASE_DOWN); } return user; } @Inject  DynamoDbUsersDao(DynamoDbClient dynamoDbClient, String tableName, ObjectMapper mapper); @Override User insert(User user); @Override User findByEmail(String email); @Override User update(@Nullable String existingEmail, User user); @Override User delete(String email);  }