Skip to content

Commit 482e76b

Browse files
Update and delete test:
1 parent b532564 commit 482e76b

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed

TestVectors/dafny/DDBEncryption/src/TestVectors.dfy

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,8 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
384384
BasicIoTestBatchWriteItem(c1, c2, globalRecords);
385385
BasicIoTestPutItem(c1, c2, globalRecords);
386386
BasicIoTestTransactWriteItems(c1, c2, globalRecords);
387+
BasicIoTestUpdateItem(c1, c2, globalRecords);
388+
BasicIoTestDeleteItem(c1, c2, globalRecords);
387389
BasicIoTestExecuteStatement(c1, c2);
388390
}
389391
}
@@ -835,6 +837,108 @@ module {:options "-functionSyntax:4"} DdbEncryptionTestVectors {
835837
BasicIoTestTransactGetItems(rClient, records);
836838
}
837839

840+
method BasicIoTestUpdateItem(writeConfig : TableConfig, readConfig : TableConfig, records : seq<Record>)
841+
{
842+
var wClient :- expect newGazelle(writeConfig);
843+
var rClient :- expect newGazelle(readConfig);
844+
WriteAllRecords(wClient, records);
845+
846+
// Update each record by appending "-updated" to the partition key
847+
for i := 0 to |records| {
848+
:- expect Need(HashName in records[i].item, "");
849+
850+
// Get the current value of the partition key
851+
var currentValue;
852+
currentValue := records[i].item[HashName].N;
853+
854+
// Append "-updated" to the current value
855+
var newValue := currentValue + "-updated";
856+
857+
// Create an update expression to update the partition key
858+
var updateExpr := "SET #pk = :val";
859+
var exprAttrNames := map["#pk" := HashName];
860+
var exprAttrValues := map[":val" := DDB.AttributeValue.S(newValue)];
861+
862+
var updateInput := DDB.UpdateItemInput(
863+
TableName := TableName,
864+
Key := map[HashName := records[i].item[HashName]],
865+
UpdateExpression := Some(updateExpr),
866+
ExpressionAttributeNames := Some(exprAttrNames),
867+
ExpressionAttributeValues := Some(exprAttrValues),
868+
ReturnValues := None,
869+
ReturnConsumedCapacity := None,
870+
ReturnItemCollectionMetrics := None,
871+
ConditionExpression := None
872+
);
873+
874+
var updateSignedItemResult := wClient.UpdateItem(updateInput);
875+
876+
expect updateSignedItemResult.Failure?, "UpdateItem should have failed for signed item.";
877+
// This error is of type DynamoDbEncryptionTransformsException
878+
// but AWS SDK wraps it into its own type for which customers should be unwrapping.
879+
// In test vectors, we still have to change the error from AWS SDK to dafny so it turns out to be OpaqueWithText.
880+
expect updateSignedItemResult.error.OpaqueWithText?, "Error should have been of type OpaqueWithText";
881+
var hasDynamoDbEncryptionTransformsException? := String.HasSubString(updateSignedItemResult.error.objMessage, "Update Expressions forbidden on signed attributes");
882+
expect hasDynamoDbEncryptionTransformsException?.Some?;
883+
}
884+
}
885+
886+
method BasicIoTestDeleteItem(writeConfig : TableConfig, readConfig : TableConfig, records : seq<Record>)
887+
{
888+
var wClient :- expect newGazelle(writeConfig);
889+
var rClient :- expect newGazelle(readConfig);
890+
WriteAllRecords(wClient, records);
891+
892+
// Only delete half of the records to verify selective deletion
893+
var deleteCount := |records| / 2;
894+
895+
for i := 0 to deleteCount {
896+
:- expect Need(HashName in records[i].item, "");
897+
898+
var deleteInput := DDB.DeleteItemInput(
899+
TableName := TableName,
900+
Key := map[HashName := records[i].item[HashName]],
901+
Expected := None,
902+
ReturnValues := None,
903+
ReturnConsumedCapacity := None,
904+
ReturnItemCollectionMetrics := None,
905+
ConditionExpression := None,
906+
ExpressionAttributeNames := None,
907+
ExpressionAttributeValues := None
908+
);
909+
910+
var _ :- expect wClient.DeleteItem(deleteInput);
911+
}
912+
913+
// Verify deletions were successful
914+
for i := 0 to |records| {
915+
:- expect Need(HashName in records[i].item, "");
916+
917+
var getInput := DDB.GetItemInput(
918+
TableName := TableName,
919+
Key := map[HashName := records[i].item[HashName]],
920+
AttributesToGet := None,
921+
ConsistentRead := None,
922+
ReturnConsumedCapacity := None,
923+
ProjectionExpression := None,
924+
ExpressionAttributeNames := None
925+
);
926+
927+
var out := rClient.GetItem(getInput);
928+
929+
if i < deleteCount {
930+
// Deleted items should not be found
931+
expect out.Success?;
932+
expect out.value.Item.None?, "Item " + String.Base10Int2String(i) + " should have been deleted";
933+
} else {
934+
// Non-deleted items should still exist
935+
expect out.Success?;
936+
expect out.value.Item.Some?;
937+
expect NormalizeItem(out.value.Item.value) == NormalizeItem(records[i].item);
938+
}
939+
}
940+
}
941+
838942
method BasicIoTestExecuteStatement(writeConfig : TableConfig, readConfig : TableConfig)
839943
{
840944
var wClient :- expect newGazelle(writeConfig);

0 commit comments

Comments
 (0)