Skip to content

Commit 3bd48ba

Browse files
chore(dafny): Add Update and delete test (#1942)
1 parent 69c37c6 commit 3bd48ba

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

TestVectors/dafny/DDBEncryption/src/TestVectors.dfy

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,12 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
397397
BasicIoTestBatchWriteItem(c1, c2, globalRecords);
398398
BasicIoTestPutItem(c1, c2, globalRecords);
399399
BasicIoTestTransactWriteItems(c1, c2, globalRecords);
400+
BasicIoTestUpdateItem(c1, c2, globalRecords, "One");
401+
BasicIoTestUpdateItem(c1, c2, globalRecords, "Two");
402+
BasicIoTestDeleteItem(c1, c2, globalRecords, "One", "Uno");
403+
BasicIoTestDeleteItem(c1, c2, globalRecords, "Two", "Dos");
404+
BasicIoTestDeleteItemWithoutConditionExpression(c1, c2, globalRecords, "One", "Uno");
405+
BasicIoTestDeleteItemWithoutConditionExpression(c1, c2, globalRecords, "Two", "Dos");
400406
BasicIoTestExecuteStatement(c1, c2);
401407
BasicIoTestExecuteTransaction(c1, c2);
402408
BasicIoTestBatchExecuteStatement(c1, c2);
@@ -844,6 +850,108 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
844850
BasicIoTestTransactGetItems(rClient, records);
845851
}
846852

853+
method BasicIoTestUpdateItem(writeConfig : TableConfig, readConfig : TableConfig, records : seq<Record>, attributeToUpdate: DDB.AttributeName)
854+
{
855+
var wClient, rClient := SetupTestTable(writeConfig, readConfig);
856+
WriteAllRecords(wClient, records);
857+
// Update each record by appending "updated" to the partition key
858+
for i := 0 to |records| {
859+
var newValue := "updated";
860+
// Create an update expression to update the partition key
861+
var updateExpr := "SET #att = :val";
862+
expect attributeToUpdate in writeConfig.config.attributeActionsOnEncrypt, "`attributeToUpdate` not in attributeActionsOnEncrypt";
863+
var exprAttrNames := map["#att" := attributeToUpdate];
864+
var exprAttrValues := map[":val" := DDB.AttributeValue.S(newValue)];
865+
expect HashName in records[i].item, "`HashName` is not in records.";
866+
var updateInput := DDB.UpdateItemInput(
867+
TableName := TableName,
868+
Key := map[HashName := records[i].item[HashName]],
869+
UpdateExpression := Some(updateExpr),
870+
ExpressionAttributeNames := Some(exprAttrNames),
871+
ExpressionAttributeValues := Some(exprAttrValues),
872+
ReturnValues := None,
873+
ReturnConsumedCapacity := None,
874+
ReturnItemCollectionMetrics := None,
875+
ConditionExpression := None
876+
);
877+
var updateResult := wClient.UpdateItem(updateInput);
878+
if writeConfig.config.attributeActionsOnEncrypt[attributeToUpdate] == SE.ENCRYPT_AND_SIGN || writeConfig.config.attributeActionsOnEncrypt[attributeToUpdate] == SE.SIGN_ONLY {
879+
expect updateResult.Failure?, "UpdateItem should have failed for signed item.";
880+
// This error is of type DynamoDbEncryptionTransformsException
881+
// but AWS SDK wraps it into its own type for which customers should be unwrapping.
882+
// In test vectors, we still have to change the error from AWS SDK to dafny so it turns out to be OpaqueWithText.
883+
expect updateResult.error.OpaqueWithText?, "Error should have been of type OpaqueWithText";
884+
var hasDynamoDbEncryptionTransformsException? := String.HasSubString(updateResult.error.objMessage, "Update Expressions forbidden on signed attributes");
885+
expect hasDynamoDbEncryptionTransformsException?.Some?, "Error might is not be of type DynamoDbEncryptionTransformsException";
886+
} else {
887+
expect updateResult.Success?;
888+
}
889+
}
890+
}
891+
892+
method BasicIoTestDeleteItem(writeConfig : TableConfig, readConfig : TableConfig, records : seq<Record>, attributeToDelete: DDB.AttributeName, expectedAttributeValue: string)
893+
{
894+
var wClient, rClient := SetupTestTable(writeConfig, readConfig);
895+
WriteAllRecords(wClient, records);
896+
// Try to delete records with a condition expression with condition to
897+
// delete records if the record has an attribute attributeToDelete with value expectedAttributeValue
898+
for i := 0 to |records| {
899+
// Set up condition expression to only delete if Two = expectedAttributeValue
900+
var conditionExpr := "#attr = :val";
901+
var exprAttrNames := map["#attr" := attributeToDelete];
902+
var exprAttrValues := map[":val" := DDB.AttributeValue.S(expectedAttributeValue)];
903+
expect HashName in records[i].item, "`HashName` is not in records.";
904+
var deleteInput := DDB.DeleteItemInput(
905+
TableName := TableName,
906+
Key := map[HashName := records[i].item[HashName]],
907+
ConditionExpression := Some(conditionExpr),
908+
ExpressionAttributeNames := Some(exprAttrNames),
909+
ExpressionAttributeValues := Some(exprAttrValues),
910+
ReturnValues := Some(DDB.ReturnValue.ALL_OLD)
911+
);
912+
var deleteResult := wClient.DeleteItem(deleteInput);
913+
expect attributeToDelete in writeConfig.config.attributeActionsOnEncrypt, "`attributeToDelete` not found in attributeActionsOnEncrypt of config.";
914+
if writeConfig.config.attributeActionsOnEncrypt[attributeToDelete] == SE.ENCRYPT_AND_SIGN {
915+
expect deleteResult.Failure?, "DeleteItem should have failed.";
916+
// This error is of type DynamoDbEncryptionTransformsException
917+
// but AWS SDK wraps it into its own type for which customers should be unwrapping.
918+
// In test vectors, we still have to change the error from AWS SDK to dafny so it turns out to be OpaqueWithText.
919+
expect deleteResult.error.OpaqueWithText?, "Error should have been of type OpaqueWithText";
920+
var hasDynamoDbEncryptionTransformsException? := String.HasSubString(deleteResult.error.objMessage, "Condition Expressions forbidden on encrypted attributes");
921+
expect hasDynamoDbEncryptionTransformsException?.Some?, "Error might is not be of type DynamoDbEncryptionTransformsException";
922+
} else if attributeToDelete in records[i].item && records[i].item[attributeToDelete].S? && records[i].item[attributeToDelete].S == expectedAttributeValue {
923+
expect deleteResult.Success?, "DeleteItem should have succeeded.";
924+
expect deleteResult.value.Attributes.Some?, "DeleteItemOutput should have had some attribute because ReturnValues was set as `ALL_OLD` in DeleteItemInput";
925+
expect HashName in deleteResult.value.Attributes.value, "Deleted item does not have right partition key:" + HashName;
926+
expect deleteResult.value.Attributes.value[HashName] == records[i].item[HashName], "Wrong item was deleted.";
927+
} else {
928+
expect deleteResult.Failure?, "DeleteItem should have failed.";
929+
expect deleteResult.error.ConditionalCheckFailedException?, "DeleteItem should have failed with ConditionalCheckFailedException";
930+
}
931+
}
932+
}
933+
934+
method BasicIoTestDeleteItemWithoutConditionExpression(writeConfig : TableConfig, readConfig : TableConfig, records : seq<Record>, attributeToDelete: DDB.AttributeName, expectedAttributeValue: string)
935+
{
936+
var wClient, rClient := SetupTestTable(writeConfig, readConfig);
937+
WriteAllRecords(wClient, records);
938+
for i := 0 to |records| {
939+
expect HashName in records[i].item, "`HashName` is not in records.";
940+
var deleteInputWithoutConditionExpression := DDB.DeleteItemInput(
941+
TableName := TableName,
942+
Key := map[HashName := records[i].item[HashName]],
943+
ReturnValues := Some(DDB.ReturnValue.ALL_OLD)
944+
);
945+
var deleteResultForWithoutConditionExpressionCase := wClient.DeleteItem(deleteInputWithoutConditionExpression);
946+
expect deleteResultForWithoutConditionExpressionCase.Success?, "DeleteItem should have succeeded.";
947+
expect deleteResultForWithoutConditionExpressionCase.value.Attributes.Some?, "DeleteItemOutput should have had some attribute because ReturnValues was set as `ALL_OLD` in DeleteItemInput";
948+
if attributeToDelete in records[i].item {
949+
expect HashName in deleteResultForWithoutConditionExpressionCase.value.Attributes.value, "Deleted item does not have right partition key:" + HashName;
950+
expect deleteResultForWithoutConditionExpressionCase.value.Attributes.value[HashName] == records[i].item[HashName], "Wrong item was deleted.";
951+
}
952+
}
953+
}
954+
847955
method BasicIoTestExecuteStatement(writeConfig : TableConfig, readConfig : TableConfig)
848956
{
849957
var wClient, rClient := SetupTestTable(writeConfig, readConfig);

0 commit comments

Comments
 (0)