From 0323ebea586c2c3136647c22b9a4f83b3c01db0f Mon Sep 17 00:00:00 2001 From: Gordon Lam <73506701+yeelam-gordon@users.noreply.github.com> Date: Mon, 7 Jul 2025 02:35:09 -0700 Subject: [PATCH] Fix Random unitttest failure (#40390) The test `Win32ProgramRepositoryMustCallOnAppRenamedForLnkAppsWhenRenamedEventIsRaised` was experiencing random failures due to object identity mismatches in the repository's hash-based storage system. ## Root Cause The test was manually creating `Win32Program` objects: ```csharp Win32Program olditem = new Win32Program { Name = "oldpath", ExecutableName = oldpath, FullPath = linkingTo, }; ``` However, the `DoOnAppRenamedAsync` method creates the `oldApp` object for removal using a different approach for .lnk files: ```csharp oldApp = new Win32Program() { Name = Path.GetFileNameWithoutExtension(e.OldName), ExecutableName = Path.GetFileName(e.OldName), FullPath = newApp?.FullPath ?? oldPath }; ``` Since the repository uses `GetHashCode()` (based on `Name`, `ExecutableName`, and `FullPath`) to identify objects for removal, any subtle differences in these properties would cause the `Remove()` operation to fail, leading to test assertion failures. ## Fix Changed the test to use `Win32Program.GetAppFromPath()` instead of manual object creation: ```csharp Win32Program olditem = Win32Program.GetAppFromPath(oldFullPath); Win32Program newitem = Win32Program.GetAppFromPath(newFullPath); ``` This mirrors the approach used in the working `Win32ProgramRepositoryMustCallOnAppRenamedForUrlAppsWhenRenamedEventIsRaised` test and ensures that test objects are created using the same code path as the production code, eliminating hash code mismatches. ## Why This Was Random The test failure appeared random because it depended on subtle differences in object creation that could vary based on timing, mock setup, or other environmental factors. By using the same object creation method as the production code, the test becomes deterministic. --- .../Storage/Win32ProgramRepositoryTest.cs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Program.UnitTests/Storage/Win32ProgramRepositoryTest.cs b/src/modules/launcher/Plugins/Microsoft.Plugin.Program.UnitTests/Storage/Win32ProgramRepositoryTest.cs index 48e86e9850..554ad46882 100644 --- a/src/modules/launcher/Plugins/Microsoft.Plugin.Program.UnitTests/Storage/Win32ProgramRepositoryTest.cs +++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Program.UnitTests/Storage/Win32ProgramRepositoryTest.cs @@ -363,7 +363,7 @@ namespace Microsoft.Plugin.Program.UnitTests.Storage RenamedEventArgs e = new RenamedEventArgs(WatcherChangeTypes.Renamed, directory, path, oldpath); string oldFullPath = directory + "\\" + oldpath; - string fullPath = directory + "\\" + path; + string newFullPath = directory + "\\" + path; string linkingTo = Directory.GetCurrentDirectory(); // ShellLinkHelper must be mocked for lnk applications @@ -372,19 +372,8 @@ namespace Microsoft.Plugin.Program.UnitTests.Storage Win32Program.ShellLinkHelper = mockShellLink.Object; // old item and new item are the actual items when they are in existence - Win32Program olditem = new Win32Program - { - Name = "oldpath", - ExecutableName = oldpath, - FullPath = linkingTo, - }; - - Win32Program newitem = new Win32Program - { - Name = "path", - ExecutableName = path, - FullPath = linkingTo, - }; + Win32Program olditem = Win32Program.GetAppFromPath(oldFullPath); + Win32Program newitem = Win32Program.GetAppFromPath(newFullPath); win32ProgramRepository.Add(olditem);