Skip to content

Commit

Permalink
chore(dynamodb): add unit tests for DynamoDB connector (#453)
Browse files Browse the repository at this point in the history
  • Loading branch information
Oleksiivanov authored Apr 19, 2023
1 parent 71d43a3 commit 3a01106
Show file tree
Hide file tree
Showing 10 changed files with 600 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package io.camunda.connector.aws.dynamodb.operation.item;

import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.PrimaryKey;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
Expand All @@ -27,7 +28,10 @@ public GetItemOperation(final GetItem getItemModel) {

@Override
public Object invoke(final DynamoDB dynamoDB) {
return dynamoDB.getTable(getItemModel.getTableName()).getItem(createPrimaryKey()).attributes();
return Optional.ofNullable(
dynamoDB.getTable(getItemModel.getTableName()).getItem(createPrimaryKey()))
.map(Item::attributes)
.orElse(null);
}

private PrimaryKey createPrimaryKey() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. Licensed under a proprietary license.
* See the License.txt file for more information. You may not use this file
* except in compliance with the proprietary license.
*/
package io.camunda.connector.aws.dynamodb;

import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Table;
import com.amazonaws.services.dynamodbv2.model.TableDescription;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;

import java.util.Map;

import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public abstract class BaseDynamoDbOperationTest {
@Mock
protected DynamoDB dynamoDB;
@Mock
protected Table table;

@BeforeEach
public void beforeEach() {
when(dynamoDB.getTable(TestData.Table.NAME)).thenReturn(table);
when(table.describe()).thenReturn(new TableDescription().withTableName(TestData.Table.NAME));
}

public interface TestData {
interface Table {
String NAME = "my_table";
String PARTITION_KEY = "ID";
String PARTITION_KEY_ROLE_HASH = "HASH";
String PARTITION_KEY_TYPE_NUMBER = "N";
String SORT_KEY = "sortKey";
String SORT_KEY_ROLE_RANGE = "RANGE";
String SORT_KEY_TYPE_STRING = "S";
Long READ_CAPACITY = 4L;
Long WRITE_CAPACITY = 5L;
String FILTER_EXPRESSION = "age >= :ageVal";
Map<String, String> EXPRESSION_ATTRIBUTE_NAMES = Map.of("#name", "name");
Map<String, Object> EXPRESSION_ATTRIBUTE_VALUES = Map.of(":ageVal", 30);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. Licensed under a proprietary license.
* See the License.txt file for more information. You may not use this file
* except in compliance with the proprietary license.
*/
package io.camunda.connector.aws.dynamodb.operation.item;

import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.PutItemOutcome;
import io.camunda.connector.aws.dynamodb.BaseDynamoDbOperationTest;
import io.camunda.connector.aws.dynamodb.model.item.AddItem;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class AddItemOperationTest extends BaseDynamoDbOperationTest {
@Mock
private AddItem addItemModel;
@Mock
private Item item;
@Mock
private PutItemOutcome putItemOutcome;

@BeforeEach
public void setUp() {
when(addItemModel.getTableName()).thenReturn(TestData.Table.NAME);
when(addItemModel.getItem()).thenReturn(item);
when(dynamoDB.getTable(addItemModel.getTableName())).thenReturn(table);
when(table.putItem(any(Item.class))).thenReturn(putItemOutcome);
}

@Test
public void testInvoke() {
AddItemOperation addItemOperation = new AddItemOperation(addItemModel);
PutItemOutcome result = addItemOperation.invoke(dynamoDB);
verify(table).putItem(any(Item.class));
assertThat(result).isEqualTo(putItemOutcome);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. Licensed under a proprietary license.
* See the License.txt file for more information. You may not use this file
* except in compliance with the proprietary license.
*/
package io.camunda.connector.aws.dynamodb.operation.item;

import com.amazonaws.services.dynamodbv2.document.DeleteItemOutcome;
import com.amazonaws.services.dynamodbv2.document.KeyAttribute;
import io.camunda.connector.aws.dynamodb.BaseDynamoDbOperationTest;
import io.camunda.connector.aws.dynamodb.model.item.DeleteItem;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;

import java.util.HashMap;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.when;


class DeleteItemOperationTest extends BaseDynamoDbOperationTest {

private DeleteItemOperation deleteItemOperation;
@Mock
private DeleteItemOutcome deleteItemOutcome;
@Captor
private ArgumentCaptor<KeyAttribute> keyAttributeArgumentCaptor;

@BeforeEach
public void setup() {
Map<String, Object> primaryKeyComponents = new HashMap<>();
primaryKeyComponents.put("id", "1234");
DeleteItem deleteItem = new DeleteItem();
deleteItem.setTableName(TestData.Table.NAME);
deleteItem.setPrimaryKeyComponents(primaryKeyComponents);
this.deleteItemOperation = new DeleteItemOperation(deleteItem);
}

@Test
public void testInvoke() {
//Given
when(table.deleteItem(keyAttributeArgumentCaptor.capture())).thenReturn(deleteItemOutcome);
//When
Object result = this.deleteItemOperation.invoke(dynamoDB);
//Then
assertThat(result).isEqualTo(deleteItemOutcome);
KeyAttribute keyAttribute = keyAttributeArgumentCaptor.getValue();
assertThat(keyAttribute.getName()).isEqualTo("id");
assertThat(keyAttribute.getValue()).isEqualTo("1234");

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. Licensed under a proprietary license.
* See the License.txt file for more information. You may not use this file
* except in compliance with the proprietary license.
*/
package io.camunda.connector.aws.dynamodb.operation.item;

import com.amazonaws.services.dynamodbv2.document.Item;
import com.amazonaws.services.dynamodbv2.document.KeyAttribute;
import com.amazonaws.services.dynamodbv2.document.PrimaryKey;
import io.camunda.connector.aws.dynamodb.BaseDynamoDbOperationTest;
import io.camunda.connector.aws.dynamodb.model.item.GetItem;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;

import java.util.List;
import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class GetItemOperationTest extends BaseDynamoDbOperationTest {

private GetItemOperation getItemOperation;
@Captor
private ArgumentCaptor<KeyAttribute[]> keyAttributesCaptor;

@BeforeEach
public void setup() {
GetItem getItem = new GetItem();
getItem.setTableName(TestData.Table.NAME);
getItem.setPrimaryKeyComponents(Map.of("id", "1", "type", "user"));
getItemOperation = new GetItemOperation(getItem);
}

@SuppressWarnings("unchecked")
@Test
void invoke_shouldReturnItemAttributes_whenItemExists() {
// Given
Item mockItem = Item.fromMap(Map.of("id", "1", "type", "user", "name", "Alice"));
when(table.getItem(keyAttributesCaptor.capture())).thenReturn(mockItem);
mockItem.attributes();

// When
Iterable<Map.Entry<String, Object>> result = (Iterable<Map.Entry<String, Object>>) getItemOperation.invoke(dynamoDB);

// Then
verify(dynamoDB, times(1)).getTable(TestData.Table.NAME);
verify(table, times(1)).getItem(any(PrimaryKey.class));
List<KeyAttribute> keyAttributeList = List.of(keyAttributesCaptor.getValue());
assertThat(keyAttributeList)
.asList()
.contains(new KeyAttribute("id", "1"), new KeyAttribute("type", "user"));
assertThat(result).isEqualTo(mockItem.attributes());
}

@SuppressWarnings("unchecked")
@Test
void invoke_shouldReturnNull_whenItemDoesNotExist() {
// Given
when(table.getItem(any(KeyAttribute.class), any(KeyAttribute.class))).thenReturn(null);

// When
Map<String, Object> result = (Map<String, Object>) getItemOperation.invoke(dynamoDB);

// Then
verify(dynamoDB, times(1)).getTable(TestData.Table.NAME);
verify(table, times(1)).getItem(any(PrimaryKey.class));
assertThat(result).isNull();
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH
* under one or more contributor license agreements. Licensed under a proprietary license.
* See the License.txt file for more information. You may not use this file
* except in compliance with the proprietary license.
*/
package io.camunda.connector.aws.dynamodb.operation.item;

import com.amazonaws.services.dynamodbv2.document.AttributeUpdate;
import com.amazonaws.services.dynamodbv2.document.KeyAttribute;
import com.amazonaws.services.dynamodbv2.document.PrimaryKey;
import com.amazonaws.services.dynamodbv2.document.UpdateItemOutcome;
import io.camunda.connector.aws.dynamodb.BaseDynamoDbOperationTest;
import io.camunda.connector.aws.dynamodb.model.item.UpdateItem;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;

import java.util.Map;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;

class UpdateItemOperationTest extends BaseDynamoDbOperationTest {
private UpdateItemOperation updateItemOperation;
private UpdateItem updateItem;
@Mock
private UpdateItemOutcome updateItemOutcome;
@Captor
private ArgumentCaptor<PrimaryKey> primaryKeyArgumentCaptor;
@Captor
private ArgumentCaptor<AttributeUpdate> attributeUpdateArgumentCaptor;
private KeyAttribute keyAttribute;
private AttributeUpdate attributeUpdate;

@BeforeEach
public void setUp() {

keyAttribute = new KeyAttribute("id", "123");
attributeUpdate = new AttributeUpdate("name").addElements("John Doe");

Map<String, Object> primaryKey = Map.of(keyAttribute.getName(), keyAttribute.getValue());
Map<String, Object> attributeUpdates = Map.of(attributeUpdate.getAttributeName(), "John Doe");

updateItem = new UpdateItem();
updateItem.setTableName(TestData.Table.NAME);
updateItem.setAttributeAction("PUT");
updateItem.setKeyAttributes(attributeUpdates);
updateItem.setPrimaryKeyComponents(primaryKey);

updateItemOperation = new UpdateItemOperation(updateItem);
}

@Test
public void testInvoke() {
// Given
when(table.updateItem(
primaryKeyArgumentCaptor.capture(),
attributeUpdateArgumentCaptor.capture()
)).thenReturn(updateItemOutcome);
// When
Object result = updateItemOperation.invoke(dynamoDB);
// Then
assertThat(result).isInstanceOf(UpdateItemOutcome.class);
assertThat(((UpdateItemOutcome) result).getItem()).isEqualTo(updateItemOutcome.getItem());

assertThat(primaryKeyArgumentCaptor.getValue().getComponents()).contains(keyAttribute);
assertThat(attributeUpdateArgumentCaptor.getValue().getAttributeName()).isEqualTo(attributeUpdate.getAttributeName());
}

@Test
public void invoke_shouldThrowExceptionWhenUpdateActionIsInvalid() {
//Given
updateItem.setAttributeAction("ADD");
//When and Then
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class,
() -> updateItemOperation.invoke(dynamoDB),
"IllegalArgumentException was expected");
assertThat(thrown.getMessage()).contains("Unsupported action [ADD]");

}
}
Loading

0 comments on commit 3a01106

Please sign in to comment.