Skip to content

Commit 095d77f

Browse files
rolfbjarneCopilot
andauthored
[tests] Fix flaky RecordTest.DeskCase_83099_InmutableDictionary on macOS CI (#24908)
The test fails intermittently when the keychain has stale entries from previous runs, causing Query to return ItemNotFound while Add returns DuplicateItem. Fix the flakiness with three changes: - Clean up any stale keychain entry before the test starts - In SaveUserPassword, handle the DuplicateItem race by removing the stale entry and retrying the add - Wrap the test body in try/finally to ensure cleanup on failure - Fix the missing $ in TEST 3's interpolated string assertion Fixes #24860 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 94e4aa7 commit 095d77f

1 file changed

Lines changed: 43 additions & 18 deletions

File tree

tests/monotouch-test/Security/RecordTest.cs

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -310,29 +310,38 @@ public void DeskCase_83099_InmutableDictionary ()
310310
{
311311
var testUsername = "testusername";
312312

313-
//TEST 1: Save a keychain value
314-
var test1 = SaveUserPassword (testUsername, "testValue1", out var queryCode, out var addCode, out var updateCode);
315-
Assert.IsTrue (test1, $"Password could not be saved to keychain. queryCode: {queryCode} addCode: {addCode} updateCode: {updateCode}");
313+
// Clean up any stale keychain entries from previous test runs to avoid
314+
// the keychain returning ItemNotFound on query but DuplicateItem on add.
315+
ForceRemoveUserPassword (testUsername);
316316

317-
//TEST 2: Get the saved keychain value
318-
var test2 = GetUserPassword (testUsername);
319-
Assert.IsTrue (StringUtil.StringsEqual (test2, "testValue1", false));
317+
try {
318+
//TEST 1: Save a keychain value
319+
var test1 = SaveUserPassword (testUsername, "testValue1", out var queryCode, out var addCode, out var updateCode);
320+
Assert.IsTrue (test1, $"Password could not be saved to keychain. queryCode: {queryCode} addCode: {addCode} updateCode: {updateCode}");
321+
322+
//TEST 2: Get the saved keychain value
323+
var test2 = GetUserPassword (testUsername);
324+
Assert.IsTrue (StringUtil.StringsEqual (test2, "testValue1", false));
320325

321-
//TEST 3: Update the keychain value
322-
var test3 = SaveUserPassword (testUsername, "testValue2", out queryCode, out addCode, out updateCode);
323-
Assert.IsTrue (test3, "Password could not be saved to keychain. queryCode: {queryCode} addCode: {addCode} updateCode: {updateCode}");
326+
//TEST 3: Update the keychain value
327+
var test3 = SaveUserPassword (testUsername, "testValue2", out queryCode, out addCode, out updateCode);
328+
Assert.IsTrue (test3, $"Password could not be saved to keychain. queryCode: {queryCode} addCode: {addCode} updateCode: {updateCode}");
324329

325-
//TEST 4: Get the updated keychain value
326-
var test4 = GetUserPassword (testUsername);
327-
Assert.IsTrue (StringUtil.StringsEqual (test4, "testValue2", false));
330+
//TEST 4: Get the updated keychain value
331+
var test4 = GetUserPassword (testUsername);
332+
Assert.IsTrue (StringUtil.StringsEqual (test4, "testValue2", false));
328333

329-
//TEST 5: Clear the keychain values
330-
var test5 = ClearUserPassword (testUsername);
331-
Assert.IsTrue (test5, "Password could not be cleared from keychain");
334+
//TEST 5: Clear the keychain values
335+
var test5 = ClearUserPassword (testUsername);
336+
Assert.IsTrue (test5, "Password could not be cleared from keychain");
332337

333-
//TEST 6: Verify no keychain value
334-
var test6 = GetUserPassword (testUsername);
335-
Assert.IsNull (test6, "No password should exist here");
338+
//TEST 6: Verify no keychain value
339+
var test6 = GetUserPassword (testUsername);
340+
Assert.IsNull (test6, "No password should exist here");
341+
} finally {
342+
// Always clean up to avoid leaving stale entries for subsequent runs
343+
ForceRemoveUserPassword (testUsername);
344+
}
336345
}
337346

338347
public static string GetUserPassword (string username)
@@ -367,6 +376,13 @@ record = CreateSecRecord (SecKind.InternetPassword,
367376
);
368377
addCode = SecKeyChain.Add (record);
369378
success = (addCode == SecStatusCode.Success);
379+
// Handle inconsistent keychain state: query returned ItemNotFound
380+
// but add returned DuplicateItem. Force-remove and retry.
381+
if (addCode == SecStatusCode.DuplicateItem) {
382+
SecKeyChain.Remove (searchRecord);
383+
addCode = SecKeyChain.Add (record);
384+
success = (addCode == SecStatusCode.Success);
385+
}
370386
}
371387
if (queryCode == SecStatusCode.Success && record is not null) {
372388
record.ValueData = NSData.FromString (password);
@@ -376,6 +392,15 @@ record = CreateSecRecord (SecKind.InternetPassword,
376392
return success;
377393
}
378394

395+
public static void ForceRemoveUserPassword (string username)
396+
{
397+
var searchRecord = CreateSecRecord (SecKind.InternetPassword,
398+
server: "Test1",
399+
account: username.ToLower ()
400+
);
401+
SecKeyChain.Remove (searchRecord);
402+
}
403+
379404
public static bool ClearUserPassword (string username)
380405
{
381406
var success = false;

0 commit comments

Comments
 (0)