@@ -1287,8 +1287,17 @@ def update_schedule_typed_attrs(
12871287 assert desc .typed_search_attributes [text_attr_key ] == "some-schedule-attr1"
12881288
12891289
1290+ @pytest .mark .parametrize (
1291+ "test_case" ,
1292+ [
1293+ "none-is-noop" ,
1294+ "empty-but-non-none-clears" ,
1295+ "all-new-values-overwrites" ,
1296+ "partial-new-values-overwrites-and-drops" ,
1297+ ],
1298+ )
12901299async def test_schedule_search_attribute_update (
1291- client : Client , env : WorkflowEnvironment
1300+ client : Client , env : WorkflowEnvironment , test_case : str
12921301):
12931302 if env .supports_time_skipping :
12941303 pytest .skip ("Java test server doesn't support schedules" )
@@ -1319,31 +1328,102 @@ async def test_schedule_search_attribute_update(
13191328 ),
13201329 )
13211330
1322- # Do update of search attributes
1323- def update_schedule_search_attributes (
1331+ def update_search_attributes (
13241332 input : ScheduleUpdateInput ,
13251333 ) -> Optional [ScheduleUpdate ]:
1326- # Make sure the search attributes are present in all forms
1334+ # Make sure the initial search attributes are present
13271335 assert input .description .search_attributes [key_1 .name ] == [val_1 ]
1336+ assert input .description .search_attributes [key_2 .name ] == [val_2 ]
13281337 assert input .description .typed_search_attributes [key_1 ] == val_1
1338+ assert input .description .typed_search_attributes [key_2 ] == val_2
1339+
1340+ if test_case == "none-is-noop" :
1341+ print ("none-is-noop" )
1342+ # Passing None makes no changes
1343+ return ScheduleUpdate (input .description .schedule , search_attributes = None )
1344+ elif test_case == "empty-but-non-none-clears" :
1345+ print ("empty-but-non-none-clears" )
1346+ # Pass empty but non-None to clear all attributes
1347+ return ScheduleUpdate (
1348+ input .description .schedule , search_attributes = TypedSearchAttributes ([])
1349+ )
1350+ elif test_case == "all-new-values-overwrites" :
1351+ print ("all-new-values-overwrites" )
1352+ # Pass all new values to overwrite existing
1353+ return ScheduleUpdate (
1354+ input .description .schedule ,
1355+ search_attributes = TypedSearchAttributes (
1356+ [
1357+ SearchAttributePair (key_1 , val_1 + "-new" ),
1358+ SearchAttributePair (key_2 , val_2 + "-new" ),
1359+ ]
1360+ ),
1361+ )
1362+ elif test_case == "partial-new-values-overwrites-and-drops" :
1363+ print ("partial-new-values-overwrites-and-drops" )
1364+ # Only update key_1, which should drop key_2
1365+ input .description .typed_search_attributes .updated
1366+ return ScheduleUpdate (
1367+ input .description .schedule ,
1368+ search_attributes = TypedSearchAttributes (
1369+ [
1370+ SearchAttributePair (key_1 , val_1 + "-new" ),
1371+ ]
1372+ ),
1373+ )
1374+ else :
1375+ raise ValueError (f"Invalid test case: { test_case } " )
13291376
1330- return ScheduleUpdate (
1331- input .description .schedule ,
1332- search_attributes = input .description .typed_search_attributes .updated (
1333- SearchAttributePair (key_1 , val_1 + "-updated" )
1334- ),
1377+ await handle .update (update_search_attributes )
1378+
1379+ async def none_is_noop_expectations ():
1380+ desc = await handle .describe ()
1381+ return (
1382+ desc .search_attributes [key_1 .name ] == [val_1 ]
1383+ and desc .search_attributes [key_2 .name ] == [val_2 ]
1384+ and desc .typed_search_attributes [key_1 ] == val_1
1385+ and desc .typed_search_attributes [key_2 ] == val_2
13351386 )
13361387
1337- await handle .update (update_schedule_search_attributes )
1388+ async def empty_but_non_none_clears_expectations ():
1389+ desc = await handle .describe ()
1390+ return (
1391+ desc .search_attributes [key_1 .name ] == []
1392+ and desc .search_attributes [key_2 .name ] == []
1393+ and len (desc .typed_search_attributes ) == 0
1394+ and len (desc .search_attributes ) == 0
1395+ )
13381396
1339- async def check_fn ():
1397+ async def all_new_values_overwrite_expectations ():
13401398 desc = await handle .describe ()
13411399 return (
1342- desc .typed_search_attributes [key_1 ],
1343- desc .search_attributes [key_1 .name ],
1400+ desc .search_attributes [key_1 .name ] == [val_1 + "-new" ]
1401+ and desc .search_attributes [key_2 .name ] == [val_2 + "-new" ]
1402+ and desc .typed_search_attributes [key_1 ] == val_1 + "-new"
1403+ and desc .typed_search_attributes [key_2 ] == val_2 + "-new"
13441404 )
13451405
1346- await assert_eq_eventually ((val_1 + "-updated" , [val_1 + "-updated" ]), check_fn )
1406+ async def partial_new_values_overwrites_and_drops_expectations ():
1407+ desc = await handle .describe ()
1408+ return (
1409+ desc .search_attributes [key_1 .name ] == [val_1 + "-new" ]
1410+ and desc .typed_search_attributes [key_1 ] == val_1 + "-new"
1411+ and key_2 .name not in desc .search_attributes
1412+ and key_2 not in desc .typed_search_attributes
1413+ )
1414+
1415+ if test_case == "none-is-noop" : # 🟢
1416+ await assert_eq_eventually (True , none_is_noop_expectations )
1417+ elif test_case == "empty-but-non-none-clears" : # 🔴
1418+ await assert_eq_eventually (True , empty_but_non_none_clears_expectations )
1419+ elif test_case == "all-new-values-overwrites" : # 🟢
1420+ await assert_eq_eventually (True , all_new_values_overwrite_expectations )
1421+ elif test_case == "partial-new-values-overwrites-and-drops" : # 🟢
1422+ await assert_eq_eventually (
1423+ True , partial_new_values_overwrites_and_drops_expectations
1424+ )
1425+ else :
1426+ raise ValueError (f"Invalid test case: { test_case } " )
13471427
13481428
13491429async def assert_no_schedules (client : Client ) -> None :
0 commit comments