Skip to content

Commit 773c1ff

Browse files
authored
fix: use UUIDs and cleanup in beacon styles example to avoid stale item collisions (#2125)
* fix: use UUIDs and cleanup in beacon styles example to avoid stale item collisions - Generate unique work_id UUIDs per run instead of hardcoded "1" and "2" - Add temporary work_id IN filter to scans (to be removed after table cleanup) - Delete items in finally/cleanup block after assertions - Dynamic compound beacon value using UUID instead of hardcoded "I-1.T-small" - Applied to both Rust and Java examples * fix: use HashMap instead of Map.of for Java 8 compatibility * chore: remove TODO comments from filter expressions
1 parent 888aaba commit 773c1ff

2 files changed

Lines changed: 222 additions & 168 deletions

File tree

DynamoDbEncryption/runtimes/rust/examples/searchableencryption/beacon_styles_searchable_encryption.rs

Lines changed: 79 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,13 @@ pub async fn put_and_query_with_beacon(branch_key_id: &str) -> Result<(), crate:
201201
.table_encryption_configs(HashMap::from([(ddb_table_name.to_string(), table_config)]))
202202
.build()?;
203203

204+
// Generate unique work_id values for this run to avoid collisions with stale items
205+
let work_id1 = uuid::Uuid::new_v4().to_string();
206+
let work_id2 = uuid::Uuid::new_v4().to_string();
207+
204208
// 8. Create item one, specifically with "dessert != fruit", and "fruit in basket".
205209
let item1 = HashMap::from([
206-
("work_id".to_string(), AttributeValue::S("1".to_string())),
210+
("work_id".to_string(), AttributeValue::S(work_id1.clone())),
207211
(
208212
"inspection_date".to_string(),
209213
AttributeValue::S("2023-06-13".to_string()),
@@ -234,7 +238,7 @@ pub async fn put_and_query_with_beacon(branch_key_id: &str) -> Result<(), crate:
234238

235239
// 9. Create item two, specifically with "dessert == fruit", and "fruit not in basket".
236240
let item2 = HashMap::from([
237-
("work_id".to_string(), AttributeValue::S("2".to_string())),
241+
("work_id".to_string(), AttributeValue::S(work_id2.clone())),
238242
(
239243
"inspection_date".to_string(),
240244
AttributeValue::S("2023-06-13".to_string()),
@@ -285,43 +289,78 @@ pub async fn put_and_query_with_beacon(branch_key_id: &str) -> Result<(), crate:
285289
.send()
286290
.await?;
287291

292+
// Run all scan tests, then clean up items regardless of success or failure
293+
let result = run_scan_tests(&ddb, ddb_table_name, &item1, &item2, &work_id1, &work_id2).await;
294+
295+
// Clean up: delete both items
296+
let plain_ddb = aws_sdk_dynamodb::Client::new(&sdk_config);
297+
let _ = plain_ddb
298+
.delete_item()
299+
.table_name(ddb_table_name)
300+
.key("work_id", AttributeValue::S(work_id1))
301+
.key("inspection_date", AttributeValue::S("2023-06-13".to_string()))
302+
.send()
303+
.await;
304+
let _ = plain_ddb
305+
.delete_item()
306+
.table_name(ddb_table_name)
307+
.key("work_id", AttributeValue::S(work_id2))
308+
.key("inspection_date", AttributeValue::S("2023-06-13".to_string()))
309+
.send()
310+
.await;
311+
312+
result?;
313+
println!("beacon_styles_searchable_encryption successful.");
314+
Ok(())
315+
}
316+
317+
async fn run_scan_tests(
318+
ddb: &aws_sdk_dynamodb::Client,
319+
ddb_table_name: &str,
320+
item1: &HashMap<String, AttributeValue>,
321+
item2: &HashMap<String, AttributeValue>,
322+
work_id1: &str,
323+
work_id2: &str,
324+
) -> Result<(), crate::BoxError> {
325+
// These filters ensure scans only match items created by this test run.
326+
let wid_filter = "work_id IN (:wid1, :wid2)";
327+
let wid_values = HashMap::from([
328+
(":wid1".to_string(), AttributeValue::S(work_id1.to_string())),
329+
(":wid2".to_string(), AttributeValue::S(work_id2.to_string())),
330+
]);
331+
288332
// 12. Test the first type of Set operation :
289333
// Select records where the basket attribute holds a particular value
290-
let expression_attribute_values = HashMap::from([(
291-
":value".to_string(),
292-
AttributeValue::S("banana".to_string()),
293-
)]);
334+
let mut expr_vals = wid_values.clone();
335+
expr_vals.insert(":value".to_string(), AttributeValue::S("banana".to_string()));
294336

295337
let scan_response = ddb
296338
.scan()
297339
.table_name(ddb_table_name)
298-
.filter_expression("contains(basket, :value)")
299-
.set_expression_attribute_values(Some(expression_attribute_values.clone()))
340+
.filter_expression(format!("{wid_filter} AND contains(basket, :value)"))
341+
.set_expression_attribute_values(Some(expr_vals))
300342
.send()
301343
.await?;
302344

303345
let attribute_values = scan_response.items.unwrap();
304346
// Validate only 1 item was returned: item1
305347
assert_eq!(attribute_values.len(), 1);
306-
let returned_item = &attribute_values[0];
307-
// Validate the item has the expected attributes
308-
assert_eq!(returned_item["work_id"], item1["work_id"]);
348+
assert_eq!(attribute_values[0]["work_id"], item1["work_id"]);
309349

310350
// 13. Test the second type of Set operation :
311351
// Select records where the basket attribute holds the fruit attribute
312352
let scan_response = ddb
313353
.scan()
314354
.table_name(ddb_table_name)
315-
.filter_expression("contains(basket, fruit)")
355+
.filter_expression(format!("{wid_filter} AND contains(basket, fruit)"))
356+
.set_expression_attribute_values(Some(wid_values.clone()))
316357
.send()
317358
.await?;
318359

319360
let attribute_values = scan_response.items.unwrap();
320361
// Validate only 1 item was returned: item1
321362
assert_eq!(attribute_values.len(), 1);
322-
let returned_item = &attribute_values[0];
323-
// Validate the item has the expected attributes
324-
assert_eq!(returned_item["work_id"], item1["work_id"]);
363+
assert_eq!(attribute_values[0]["work_id"], item1["work_id"]);
325364

326365
// 14. Test the third type of Set operation :
327366
// Select records where the fruit attribute exists in a particular set
@@ -330,80 +369,73 @@ pub async fn put_and_query_with_beacon(branch_key_id: &str) -> Result<(), crate:
330369
"orange".to_string(),
331370
"grape".to_string(),
332371
];
333-
let expression_attribute_values =
334-
HashMap::from([(":value".to_string(), AttributeValue::Ss(basket3))]);
372+
let mut expr_vals = wid_values.clone();
373+
expr_vals.insert(":value".to_string(), AttributeValue::Ss(basket3));
335374

336375
let scan_response = ddb
337376
.scan()
338377
.table_name(ddb_table_name)
339-
.filter_expression("contains(:value, fruit)")
340-
.set_expression_attribute_values(Some(expression_attribute_values.clone()))
378+
.filter_expression(format!("{wid_filter} AND contains(:value, fruit)"))
379+
.set_expression_attribute_values(Some(expr_vals))
341380
.send()
342381
.await?;
343382

344383
let attribute_values = scan_response.items.unwrap();
345-
// Validate only 1 item was returned: item1
384+
// Validate only 1 item was returned: item2
346385
assert_eq!(attribute_values.len(), 1);
347-
let returned_item = &attribute_values[0];
348-
// Validate the item has the expected attributes
349-
assert_eq!(returned_item["work_id"], item2["work_id"]);
386+
assert_eq!(attribute_values[0]["work_id"], item2["work_id"]);
350387

351388
// 15. Test a Shared search. Select records where the dessert attribute matches the fruit attribute
352389
let scan_response = ddb
353390
.scan()
354391
.table_name(ddb_table_name)
355-
.filter_expression("dessert = fruit")
392+
.filter_expression(format!("{wid_filter} AND dessert = fruit"))
393+
.set_expression_attribute_values(Some(wid_values.clone()))
356394
.send()
357395
.await?;
358396

359397
let attribute_values = scan_response.items.unwrap();
360-
// Validate only 1 item was returned: item1
398+
// Validate only 1 item was returned: item2
361399
assert_eq!(attribute_values.len(), 1);
362-
let returned_item = &attribute_values[0];
363-
// Validate the item has the expected attributes
364-
assert_eq!(returned_item["work_id"], item2["work_id"]);
400+
assert_eq!(attribute_values[0]["work_id"], item2["work_id"]);
365401

366-
// 15. Test the AsSet attribute 'veggies' :
402+
// 16. Test the AsSet attribute 'veggies' :
367403
// Select records where the veggies attribute holds a particular value
368-
let expression_attribute_values =
369-
HashMap::from([(":value".to_string(), AttributeValue::S("peas".to_string()))]);
404+
let mut expr_vals = wid_values.clone();
405+
expr_vals.insert(":value".to_string(), AttributeValue::S("peas".to_string()));
370406

371407
let scan_response = ddb
372408
.scan()
373409
.table_name(ddb_table_name)
374-
.filter_expression("contains(veggies, :value)")
375-
.set_expression_attribute_values(Some(expression_attribute_values.clone()))
410+
.filter_expression(format!("{wid_filter} AND contains(veggies, :value)"))
411+
.set_expression_attribute_values(Some(expr_vals))
376412
.send()
377413
.await?;
378414

379415
let attribute_values = scan_response.items.unwrap();
380-
// Validate only 1 item was returned: item1
416+
// Validate only 1 item was returned: item2
381417
assert_eq!(attribute_values.len(), 1);
382-
let returned_item = &attribute_values[0];
383-
// Validate the item has the expected attributes
384-
assert_eq!(returned_item["work_id"], item2["work_id"]);
418+
assert_eq!(attribute_values[0]["work_id"], item2["work_id"]);
385419

386-
// 16. Test the compound beacon 'work_unit' :
387-
let expression_attribute_values = HashMap::from([(
420+
// 17. Test the compound beacon 'work_unit' :
421+
let mut expr_vals = wid_values.clone();
422+
expr_vals.insert(
388423
":value".to_string(),
389-
AttributeValue::S("I-1.T-small".to_string()),
390-
)]);
424+
AttributeValue::S(format!("I-{}.T-small", item1["work_id"].as_s().unwrap())),
425+
);
391426

392427
let scan_response = ddb
393428
.scan()
394429
.table_name(ddb_table_name)
395-
.filter_expression("work_unit = :value")
396-
.set_expression_attribute_values(Some(expression_attribute_values.clone()))
430+
.filter_expression(format!("{wid_filter} AND work_unit = :value"))
431+
.set_expression_attribute_values(Some(expr_vals))
397432
.send()
398433
.await?;
399434

400435
let attribute_values = scan_response.items.unwrap();
401436
// Validate only 1 item was returned: item1
402437
assert_eq!(attribute_values.len(), 1);
403-
let returned_item = &attribute_values[0];
404-
// Validate the item has the expected attributes
405-
assert_eq!(returned_item["work_id"], item1["work_id"]);
438+
assert_eq!(attribute_values[0]["work_id"], item1["work_id"]);
406439

407-
println!("beacon_styles_searchable_encryption successful.");
408440
Ok(())
409441
}

0 commit comments

Comments
 (0)