[🐛 Bug]: [dotnet] BiDi logs potentially missing with race condition
Description
It appears that not all console logs are sent over the BiDi web socket and there is some kind of race condition when closing down the connection.
If I want to make sure that I receive all the log entries before the browser closes, it appears that I need to add a time based delay, which results in flaky and/or slow tests.
I've attached a simple example that demonstrates the logs are not send to OnEntryAddedAsync unless I add a time-based delay.
Am I doing something wrong here?
Reproducible Code
// <PackageReference Include="Selenium.WebDriver" Version="4.38.0" />
using System.Collections.Concurrent;
using OpenQA.Selenium.BiDi;
using OpenQA.Selenium.Chrome;
var options = new ChromeOptions { UseWebSocketUrl = true };
using var driver = new ChromeDriver(options);
await using var biDi = await driver.AsBiDiAsync();
var logs = new ConcurrentBag<string?>();
await using var logSubscription = await biDi.Log.OnEntryAddedAsync(entry => logs.Add(entry.Text));
driver.Navigate().GoToUrl("about:blank");
driver.ExecuteScript("console.log('Test log.');");
//Uncommenting this line will "fix" the issue.
//await Task.Delay(1000);
if(!logs.SequenceEqual(["Test log."]))
throw new Exception("Logs missing.");
Console.WriteLine("Logs present.");
@bartecargo, thank you for creating this issue. We will troubleshoot it as soon as we can.
Selenium Triage Team: remember to follow the Triage Guide
Absolutely right! There is a race condition when we should gracefully shutdown... You are doing everything right.
Selenium should wait until all "interesting" events are dispatched:
await using var logSubscription = await biDi.Log.OnEntryAddedAsync(entry => logs.Add(entry.Text));
// when this subscription is disposing, we should make sure there are no more events to be dispatched to this subscription
We should fix this particular case, we are able to do it.
But please be prepared that you might "loose" events in another cases, and Selenium cannot help.
As a workaround I can propose you to not dispose subscription temporary:
- await using var logSubscription = await biDi.Log.OnEntryAddedAsync(entry => logs.Add(entry.Text));
+ await biDi.Log.OnEntryAddedAsync(entry => logs.Add(entry.Text));
It is safe, no memory leakage. But the subscription lives until bidi object is disposed. When Selenium disposes bidi object it makes sure all events are dispatched.