Skip to content

Commit

Permalink
Thread safe evicting of elements
Browse files Browse the repository at this point in the history
Prevent stale enumerators while evicting unavailable elements or windows. Closes #42.
  • Loading branch information
aristotelos committed May 14, 2024
1 parent bbb1fb7 commit 3f75529
Showing 1 changed file with 12 additions and 9 deletions.
21 changes: 12 additions & 9 deletions src/FlaUI.WebDriver/Session.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using FlaUI.Core;
using FlaUI.Core.AutomationElements;
using FlaUI.UIA3;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;

namespace FlaUI.WebDriver
Expand All @@ -27,8 +28,8 @@ public Session(Application? app, bool isAppOwnedBySession)
public UIA3Automation Automation { get; }
public Application? App { get; }
public InputState InputState { get; }
private Dictionary<string, KnownElement> KnownElementsByElementReference { get; } = new Dictionary<string, KnownElement>();
private Dictionary<string, KnownWindow> KnownWindowsByWindowHandle { get; } = new Dictionary<string, KnownWindow>();
private ConcurrentDictionary<string, KnownElement> KnownElementsByElementReference { get; } = new ConcurrentDictionary<string, KnownElement>();
private ConcurrentDictionary<string, KnownWindow> KnownWindowsByWindowHandle { get; } = new ConcurrentDictionary<string, KnownWindow>();
public TimeSpan ImplicitWaitTimeout => TimeSpan.FromMilliseconds(TimeoutsConfiguration.ImplicitWaitTimeoutMs);
public TimeSpan PageLoadTimeout => TimeSpan.FromMilliseconds(TimeoutsConfiguration.PageLoadTimeoutMs);
public TimeSpan? ScriptTimeout => TimeoutsConfiguration.ScriptTimeoutMs.HasValue ? TimeSpan.FromMilliseconds(TimeoutsConfiguration.ScriptTimeoutMs.Value) : null;
Expand Down Expand Up @@ -83,7 +84,7 @@ public KnownElement GetOrAddKnownElement(AutomationElement element)
if (result == null)
{
result = new KnownElement(element, elementRuntimeId);
KnownElementsByElementReference.Add(result.ElementReference, result);
KnownElementsByElementReference.TryAdd(result.ElementReference, result);
}
return result;
}
Expand All @@ -104,7 +105,7 @@ public KnownWindow GetOrAddKnownWindow(Window window)
if (result == null)
{
result = new KnownWindow(window, windowRuntimeId);
KnownWindowsByWindowHandle.Add(result.WindowHandle, result);
KnownWindowsByWindowHandle.TryAdd(result.WindowHandle, result);
}
return result;
}
Expand All @@ -123,27 +124,29 @@ public void RemoveKnownWindow(Window window)
var item = KnownWindowsByWindowHandle.Values.FirstOrDefault(knownElement => knownElement.Window.Equals(window));
if (item != null)
{
KnownWindowsByWindowHandle.Remove(item.WindowHandle);
KnownWindowsByWindowHandle.TryRemove(item.WindowHandle, out _);
}
}

public void EvictUnavailableElements()
{
// Evict unavailable elements to prevent slowing down
var unavailableElements = KnownElementsByElementReference.Where(item => !item.Value.Element.IsAvailable).Select(item => item.Key).ToArray();
// (use ToArray to prevent concurrency issues while enumerating)
var unavailableElements = KnownElementsByElementReference.ToArray().Where(item => !item.Value.Element.IsAvailable).Select(item => item.Key);
foreach (var unavailableElementKey in unavailableElements)
{
KnownElementsByElementReference.Remove(unavailableElementKey);
KnownElementsByElementReference.TryRemove(unavailableElementKey, out _);
}
}

public void EvictUnavailableWindows()
{
// Evict unavailable windows to prevent slowing down
var unavailableWindows = KnownWindowsByWindowHandle.Where(item => !item.Value.Window.IsAvailable).Select(item => item.Key).ToArray();
// (use ToArray to prevent concurrency issues while enumerating)
var unavailableWindows = KnownWindowsByWindowHandle.ToArray().Where(item => !item.Value.Window.IsAvailable).Select(item => item.Key).ToArray();
foreach (var unavailableWindowKey in unavailableWindows)
{
KnownWindowsByWindowHandle.Remove(unavailableWindowKey);
KnownWindowsByWindowHandle.TryRemove(unavailableWindowKey, out _);
}
}

Expand Down

0 comments on commit 3f75529

Please sign in to comment.