From 0141897d889f997762d2115a1de8d1561a45974d Mon Sep 17 00:00:00 2001 From: RohitM-IN Date: Sat, 24 Jun 2023 19:59:14 +0530 Subject: [PATCH 1/6] update core to 0.0.0.2 alpha --- SeleniumManager.Core/SeleniumManager.Core.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SeleniumManager.Core/SeleniumManager.Core.csproj b/SeleniumManager.Core/SeleniumManager.Core.csproj index 6d42404..f04ad3c 100644 --- a/SeleniumManager.Core/SeleniumManager.Core.csproj +++ b/SeleniumManager.Core/SeleniumManager.Core.csproj @@ -15,7 +15,7 @@ This include managing Queues, Parallel Tests, etc. MIT License True 0.0.0.1 - 0.0.0.1-alpha + 0.0.0.2-alpha From 1b4ba415ad6bbf076ee90b041e098e575d57ea08 Mon Sep 17 00:00:00 2001 From: RohitM-IN Date: Sat, 1 Jul 2023 18:36:10 +0530 Subject: [PATCH 2/6] Cleaned up some code --- .../DataContract/ConfigurationSettings.cs | 1 + SeleniumManager.Core/DataContract/Options.cs | 65 +++++++++++ SeleniumManager.Core/SeleniumManager.cs | 105 ++++++++++-------- SeleniumManager.Tests/BrowsingTest.cs | 22 ++-- 4 files changed, 141 insertions(+), 52 deletions(-) create mode 100644 SeleniumManager.Core/DataContract/Options.cs diff --git a/SeleniumManager.Core/DataContract/ConfigurationSettings.cs b/SeleniumManager.Core/DataContract/ConfigurationSettings.cs index d9846bf..ccb0aa3 100644 --- a/SeleniumManager.Core/DataContract/ConfigurationSettings.cs +++ b/SeleniumManager.Core/DataContract/ConfigurationSettings.cs @@ -14,5 +14,6 @@ public class ConfigurationSettings public string Secret { get; set; } public int MaxConcurrency { get; set; } public Endpoints Endpoints { get; set; } + public Options Options { get; set; } = new Options(); } } diff --git a/SeleniumManager.Core/DataContract/Options.cs b/SeleniumManager.Core/DataContract/Options.cs new file mode 100644 index 0000000..9a50358 --- /dev/null +++ b/SeleniumManager.Core/DataContract/Options.cs @@ -0,0 +1,65 @@ +using OpenQA.Selenium; +using OpenQA.Selenium.Chrome; +using OpenQA.Selenium.Chromium; +using OpenQA.Selenium.Edge; +using OpenQA.Selenium.Firefox; +using OpenQA.Selenium.IE; +using OpenQA.Selenium.Safari; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SeleniumManager.Core.DataContract +{ + public class Options + { + public ChromeOptions chromeOptions { get; set; } = GetChromeOptions(); + public FirefoxOptions firefoxOptions { get; set; } = GetFirefoxOptions(); + public EdgeOptions edgeOptions { get; set; } = GetEdgeOptions(); + public InternetExplorerOptions internetExplorerOptions { get; set; } = GetInternetExplorerOptions(); + public SafariOptions safariOptions { get; set; } = GetSafariOptions(); + + public static ChromeOptions GetChromeOptions() + { + var chromeOptions = new ChromeOptions(); +#if !DEBUG + chromeOptions.AddArgument("headless"); +#endif + chromeOptions.AddArgument("disable-gpu"); + chromeOptions.AddArgument("no-sandbox"); + chromeOptions.AddArgument("--blink-settings=imagesEnabled=false"); + return chromeOptions; + } + + public static FirefoxOptions GetFirefoxOptions() + { + var firefoxOptions = new FirefoxOptions(); +#if !DEBUG + firefoxOptions.AddArgument("headless"); +#endif + firefoxOptions.AddArgument("disable-gpu"); + firefoxOptions.AddArgument("no-sandbox"); + firefoxOptions.AddArgument("--blink-settings=imagesEnabled=false"); + return firefoxOptions; + } + + public static EdgeOptions GetEdgeOptions() + { + var edgeOptions = new EdgeOptions(); +#if !DEBUG + edgeOptions.AddArgument("headless"); +#endif + edgeOptions.AddArgument("disable-gpu"); + edgeOptions.AddArgument("no-sandbox"); + edgeOptions.AddArgument("--blink-settings=imagesEnabled=false"); + return edgeOptions; + } + + public static InternetExplorerOptions GetInternetExplorerOptions() => new InternetExplorerOptions(); + + public static SafariOptions GetSafariOptions() => new SafariOptions(); + + } +} diff --git a/SeleniumManager.Core/SeleniumManager.cs b/SeleniumManager.Core/SeleniumManager.cs index 8812bc9..f3d404c 100644 --- a/SeleniumManager.Core/SeleniumManager.cs +++ b/SeleniumManager.Core/SeleniumManager.cs @@ -36,7 +36,7 @@ public SeleniumManager(ConfigManager configManager) { _configSettings = configManager.configSettings; httpClient = new HttpClient(); - _semaphore = new SemaphoreSlim(GetAvailableInstances().Result); + _semaphore = new SemaphoreSlim(GetAvailableInstances().Result,1000); _queue = new ConcurrentQueue>(); } @@ -61,14 +61,16 @@ public virtual Task EnqueueAction(Func action) catch (Exception ex) { // Set the exception as the task completion exception - tcs.SetException(ex); + tcs.SetException(ex); + throw new Exception("Error Occoured inside Action", ex); } finally { + // Dispose the driver if not already done driver?.Dispose(); - _semaphore.Release(); } }); + TryExecuteNext(); return tcs.Task; } @@ -85,6 +87,9 @@ public async void TryExecuteNext() IWebDriver _driver = CreateDriverInstance("Chrome"); action(_driver); + // Release driver + _driver.Dispose(); + // Release the semaphore to allow other threads to acquire it _semaphore.Release(); @@ -93,18 +98,21 @@ public async void TryExecuteNext() } catch (Exception ex) { - // Handle any exceptions that occurred during action execution - // Release the semaphore even if an exception occurs _semaphore.Release(); // Recursively call TryExecuteNext to process the next action in the queue TryExecuteNext(); - throw; + + throw new Exception("There was error while performing the delegate action", ex); + } + finally + { + _semaphore.Release(); } } } - public async Task GetAvailableInstances() + public virtual async Task GetAvailableInstances() { var nodeStatus = await GetStatus(); @@ -115,7 +123,7 @@ public async Task GetAvailableInstances() return AvailableSessions; } - public async Task GetHeartBeat() + public virtual async Task GetHeartBeat() { var nodeStatus = await GetStatus(); @@ -124,10 +132,52 @@ public async Task GetAvailableInstances() return nodeStatus; } + public virtual IWebDriver CreateDriverInstance(string browserName) + { + IWebDriver driver; + + switch (GetAvailableDriverName(browserName).ToLower()) + { + case "firefox": + driver = new RemoteWebDriver(new Uri(_configSettings.GridHost.ToString()), _configSettings.Options.firefoxOptions); + + break; + case "chrome": + driver = new RemoteWebDriver(new Uri(_configSettings.GridHost.ToString()), _configSettings.Options.chromeOptions); + break; + case "edge": + driver = new RemoteWebDriver(new Uri(_configSettings.GridHost.ToString()), _configSettings.Options.edgeOptions); + break; + case "safari": + driver = new RemoteWebDriver(new Uri(_configSettings.GridHost.ToString()), _configSettings.Options.safariOptions); + break; + case "ie": + driver = new RemoteWebDriver(new Uri(_configSettings.GridHost.ToString()), _configSettings.Options.internetExplorerOptions); + break; + default: + throw new ArgumentException("Browser not supported yet!"); + } + + return driver; + } + + public string GetAvailableDriverName(string browserName) + { + var data = GetHeartBeat(); + if(data != null) + { + // TODO:check for availablity + + // return if available + return browserName; + } + + throw new Exception("Cannot Get Heart Beat"); + } + #endregion #region Private Methods - private async Task GetStatus() { try @@ -143,8 +193,7 @@ public async Task GetAvailableInstances() } catch (Exception ex) { - Console.WriteLine("Error :"+ex.Message+" Trace: "+ex.StackTrace); - throw; + throw new Exception("There was en error while getting status", ex); } } @@ -177,40 +226,6 @@ private void ResetValues() AvailableSessions = FreeSessions = TotalSessions = ConcurrentSessions = 0; } - private async void TryExecuateNext() - { - await _semaphore.WaitAsync(); - - - - } - - public virtual IWebDriver CreateDriverInstance(string browserName) - { - IWebDriver driver; - - switch (browserName.ToLower()) - { - case "firefox": - var firefoxOptions = new FirefoxOptions(); - driver = new RemoteWebDriver(new Uri(_configSettings.GridHost.ToString()), firefoxOptions); - - break; - case "chrome": - var chromeOptions = new ChromeOptions(); - driver = new RemoteWebDriver(new Uri(_configSettings.GridHost.ToString()), chromeOptions); - break; - case "edge": - var edgeOptions = new EdgeOptions(); - driver = new RemoteWebDriver(new Uri(_configSettings.GridHost.ToString()), edgeOptions); - break; - default: - throw new ArgumentException("Browser not supported"); - } - - return driver; - } - #endregion } diff --git a/SeleniumManager.Tests/BrowsingTest.cs b/SeleniumManager.Tests/BrowsingTest.cs index a0b4044..c9bd219 100644 --- a/SeleniumManager.Tests/BrowsingTest.cs +++ b/SeleniumManager.Tests/BrowsingTest.cs @@ -52,12 +52,21 @@ public async Task ParallelTestBrouse() } [TestMethod] - public void TestBrouseFail() + public async Task TestBrouseFail() { - _seleniumManager.EnqueueAction(BrouseWebsiteFail); + try + { + await _seleniumManager.EnqueueAction(BrouseWebsiteFail); - // Start processing the actions - _seleniumManager.TryExecuteNext(); + // Start processing the actions + _seleniumManager.TryExecuteNext(); + + } + catch (Exception ex) + { + Console.WriteLine("Error Message: \n" +ex.Message); + Console.WriteLine("StackTrace: \n" + ex.StackTrace); + } } private string BrouseGoogleWebsite(IWebDriver driver) @@ -66,8 +75,7 @@ private string BrouseGoogleWebsite(IWebDriver driver) try { driver.Url = "https://www.google.com/"; - - //driver.Dispose(); + Console.WriteLine(driver.Title + " Process ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId); } catch (Exception ex) @@ -86,7 +94,7 @@ private string BrouseWebsite(IWebDriver driver) driver.Url = "https://dev.azure.com/Rohit-IN/Selenium%20Manager/"; driver.FindElement(By.XPath("//a[@aria-label='Repos']")).Click(); - + Console.WriteLine(driver.Title); driver.Dispose(); } From 9da7cecd308e55231150faaa1e36125966d21f0c Mon Sep 17 00:00:00 2001 From: RohitM-IN Date: Sat, 1 Jul 2023 22:47:01 +0530 Subject: [PATCH 3/6] Update Tests --- SeleniumManager.Tests/BrowsingTest.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/SeleniumManager.Tests/BrowsingTest.cs b/SeleniumManager.Tests/BrowsingTest.cs index c9bd219..b19cddb 100644 --- a/SeleniumManager.Tests/BrowsingTest.cs +++ b/SeleniumManager.Tests/BrowsingTest.cs @@ -22,9 +22,9 @@ public void init() } [TestMethod] - public void TestBrouse() + public async Task TestBrouse() { - _seleniumManager.EnqueueAction(BrouseWebsite); + var data = await _seleniumManager.EnqueueAction(BrouseWebsite); // Start processing the actions _seleniumManager.TryExecuteNext(); @@ -40,7 +40,7 @@ public async Task ParallelTestBrouse() { Task task = Task.Run(async () => { - await _seleniumManager.EnqueueAction(BrouseGoogleWebsite); + var data = await _seleniumManager.EnqueueAction(BrouseGoogleWebsite); _seleniumManager.TryExecuteNext(); Thread.Sleep(2000); }); @@ -56,7 +56,7 @@ public async Task TestBrouseFail() { try { - await _seleniumManager.EnqueueAction(BrouseWebsiteFail); + var data = await _seleniumManager.EnqueueAction(BrouseWebsiteFail); // Start processing the actions _seleniumManager.TryExecuteNext(); @@ -78,12 +78,12 @@ private string BrouseGoogleWebsite(IWebDriver driver) Console.WriteLine(driver.Title + " Process ID:" + System.Threading.Thread.CurrentThread.ManagedThreadId); } - catch (Exception ex) + catch (Exception) { throw; } - return null; + return string.Empty; } private string BrouseWebsite(IWebDriver driver) @@ -98,12 +98,12 @@ private string BrouseWebsite(IWebDriver driver) driver.Dispose(); } - catch (Exception ex) + catch (Exception) { throw; } - return null; + return string.Empty; } private string BrouseWebsiteFail(IWebDriver driver) { @@ -115,7 +115,7 @@ private string BrouseWebsiteFail(IWebDriver driver) { throw new NoSuchElementException("Element not found."); } - return null; + return string.Empty; } } From e02ae360a55acc9dd50cf936fdc36d7c3c7573af Mon Sep 17 00:00:00 2001 From: RohitM-IN Date: Sun, 16 Jul 2023 14:55:03 +0530 Subject: [PATCH 4/6] Auto manage Browsers based on dictonary not fail proof need to work more on it --- .gitignore | 3 +- .../SeleniumManager.ConsoleApp.csproj | 6 +- .../Configuration/config.json | 3 +- SeleniumManager.Core/DataContract/Browser.cs | 17 +++ SeleniumManager.Core/SeleniumManager.cs | 144 +++++++++++++++--- SeleniumManager.Tests/BrowsingTest.cs | 7 +- 6 files changed, 154 insertions(+), 26 deletions(-) create mode 100644 SeleniumManager.Core/DataContract/Browser.cs diff --git a/.gitignore b/.gitignore index 9491a2f..07bb6bb 100644 --- a/.gitignore +++ b/.gitignore @@ -360,4 +360,5 @@ MigrationBackup/ .ionide/ # Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file +FodyWeavers.xsd +/SeleniumManager.ConsoleApp/myconfig.toml diff --git a/SeleniumManager.ConsoleApp/SeleniumManager.ConsoleApp.csproj b/SeleniumManager.ConsoleApp/SeleniumManager.ConsoleApp.csproj index 50a0e6c..327a07f 100644 --- a/SeleniumManager.ConsoleApp/SeleniumManager.ConsoleApp.csproj +++ b/SeleniumManager.ConsoleApp/SeleniumManager.ConsoleApp.csproj @@ -1,4 +1,4 @@ - + Exe @@ -7,6 +7,10 @@ enable + + + + Always diff --git a/SeleniumManager.Core/Configuration/config.json b/SeleniumManager.Core/Configuration/config.json index cc42f63..35376e3 100644 --- a/SeleniumManager.Core/Configuration/config.json +++ b/SeleniumManager.Core/Configuration/config.json @@ -7,7 +7,8 @@ "MicrosoftEdge" ], "Exclude": [ - "internet explorer" + "InternetExplorer", + "Safari" ], "endpoints": { "status": "/status" diff --git a/SeleniumManager.Core/DataContract/Browser.cs b/SeleniumManager.Core/DataContract/Browser.cs new file mode 100644 index 0000000..9828462 --- /dev/null +++ b/SeleniumManager.Core/DataContract/Browser.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SeleniumManager.Core.DataContract +{ + public class Browser + { + public string Name { get; set; } + public int TotalInstance { get; set; } = 0; + public int AvailableInstance { get; set; } = 0; + public bool IsExcluded { get; set; } = false; + } +} + \ No newline at end of file diff --git a/SeleniumManager.Core/SeleniumManager.cs b/SeleniumManager.Core/SeleniumManager.cs index f3d404c..1c9185e 100644 --- a/SeleniumManager.Core/SeleniumManager.cs +++ b/SeleniumManager.Core/SeleniumManager.cs @@ -1,4 +1,5 @@ -using OpenQA.Selenium; +using Newtonsoft.Json.Linq; +using OpenQA.Selenium; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Edge; using OpenQA.Selenium.Firefox; @@ -20,6 +21,7 @@ public class SeleniumManager: ISeleniumManager #region Declerations private readonly SemaphoreSlim _semaphore; + private readonly SemaphoreSlim _availableStereotypesSemaphore = new SemaphoreSlim(1, 1); private readonly ConcurrentQueue> _queue; private readonly ConfigurationSettings _configSettings; private readonly HttpClient httpClient; @@ -29,6 +31,15 @@ public class SeleniumManager: ISeleniumManager public int ConcurrentSessions { get; private set; } = 0; public int AvailableSessions { get; private set; } = 0; public int TotalSessions { get; private set; } = 0; + public Dictionary MaxStereotypes { get; private set; } = new(); + public Dictionary ConcurrentStereotypes { get; private set; } = new(); + public Dictionary AvailableStereotypes { get; private set; } = new(); + public DateTime LastSessionDetails { get; private set; } + enum AdjustType + { + Create = 1, + Destroy = 2 + } #endregion #region Constructor @@ -80,19 +91,19 @@ public async void TryExecuteNext() if (_queue.TryDequeue(out var action)) { + string browserName = ""; // TODO: make it like get the driver first and then process the action try { // for now only using chrome for testing - IWebDriver _driver = CreateDriverInstance("Chrome"); + IWebDriver _driver = CreateDriverInstance(); + ICapabilities capabilities = ((RemoteWebDriver)_driver).Capabilities; + browserName = capabilities.GetCapability("browserName").ToString(); action(_driver); - + // Release driver _driver.Dispose(); - // Release the semaphore to allow other threads to acquire it - _semaphore.Release(); - // Recursively call TryExecuteNext to process the next action in the queue TryExecuteNext(); } @@ -108,7 +119,12 @@ public async void TryExecuteNext() } finally { - _semaphore.Release(); + _semaphore.Release(); + await _availableStereotypesSemaphore.WaitAsync(); + if (!string.IsNullOrEmpty(browserName)) + AdjustInstance(browserName.ToLower(), AdjustType.Destroy); + _availableStereotypesSemaphore.Release(); + } } } @@ -132,11 +148,11 @@ public virtual async Task GetAvailableInstances() return nodeStatus; } - public virtual IWebDriver CreateDriverInstance(string browserName) + public virtual IWebDriver CreateDriverInstance(string? browserName = null) { IWebDriver driver; - - switch (GetAvailableDriverName(browserName).ToLower()) + browserName = GetAvailableDriverName(browserName); + switch (browserName.ToLower()) { case "firefox": driver = new RemoteWebDriver(new Uri(_configSettings.GridHost.ToString()), _configSettings.Options.firefoxOptions); @@ -145,7 +161,7 @@ public virtual IWebDriver CreateDriverInstance(string browserName) case "chrome": driver = new RemoteWebDriver(new Uri(_configSettings.GridHost.ToString()), _configSettings.Options.chromeOptions); break; - case "edge": + case "microsoftedge": driver = new RemoteWebDriver(new Uri(_configSettings.GridHost.ToString()), _configSettings.Options.edgeOptions); break; case "safari": @@ -157,24 +173,32 @@ public virtual IWebDriver CreateDriverInstance(string browserName) default: throw new ArgumentException("Browser not supported yet!"); } - return driver; } - public string GetAvailableDriverName(string browserName) + public string GetAvailableDriverName(string? browserName) { - var data = GetHeartBeat(); - if(data != null) + // check if last session was gotten in last 1 min get from config default 1 min + if ((DateTime.Now - LastSessionDetails) > TimeSpan.FromSeconds(60)) { - // TODO:check for availablity + var data = GetHeartBeat().Result; + if (data != null) + getSessions(data); + else + throw new Exception("Cannot Get Heart Beat"); + } - // return if available + // Check if the requested browser is available + if (!string.IsNullOrEmpty(browserName) && IsBrowserAvailable(browserName)) return browserName; - } - throw new Exception("Cannot Get Heart Beat"); - } + // If the requested browser is not available, find the best available browser based on statistics + string bestBrowser = FindBestAvailableBrowser().Result; + // Return the best available browser + return bestBrowser; + } + #endregion #region Private Methods @@ -206,6 +230,9 @@ private void getSessions(dynamic nodeStatus) } MaxSessions = 0; ResetValues(); + MaxStereotypes = new Dictionary(); + ConcurrentStereotypes = new Dictionary(); + AvailableStereotypes = new Dictionary(); foreach (var node in nodeStatus.value.nodes) { @@ -213,12 +240,22 @@ private void getSessions(dynamic nodeStatus) foreach (var slot in node.slots) { TotalSessions++; + MaxStereotypes.TryAdd((string)slot.stereotype.browserName, 0); + ConcurrentStereotypes.TryAdd((string)slot.stereotype.browserName, 0); + if (slot.session == null) FreeSessions++; + else + ConcurrentStereotypes[(string)slot.stereotype.browserName]++; + MaxStereotypes[(string)slot.stereotype.browserName]++; } } + _availableStereotypesSemaphore.Wait(); + AvailableStereotypes = MaxStereotypes.ToDictionary(kv => kv.Key, kv => kv.Value - (ConcurrentStereotypes.TryGetValue(kv.Key, out var usedVal) ? usedVal : 0)); + _availableStereotypesSemaphore.Release(); ConcurrentSessions = TotalSessions - FreeSessions; AvailableSessions = MaxSessions - ConcurrentSessions; + LastSessionDetails = DateTime.Now; } private void ResetValues() @@ -226,6 +263,73 @@ private void ResetValues() AvailableSessions = FreeSessions = TotalSessions = ConcurrentSessions = 0; } + private bool IsBrowserAvailable(string browserName) + { + AvailableStereotypes.TryGetValue(browserName, out var _maxSessions); + if(_maxSessions == 0 ) + return false; + return true; + } + + private async Task FindBestAvailableBrowser() + { + var statistics = new Dictionary() + { + { "Chrome", 8 }, + { "MicrosoftEdge", 8 }, + { "Firefox", 0 }, + { "Internet Explorer", 0 } + }; + + foreach (var kvp in statistics.OrderByDescending(x => x.Value)) + { + await _availableStereotypesSemaphore.WaitAsync(); + var browserName = kvp.Key; + var maxInstances = kvp.Value; + ConcurrentStereotypes.TryGetValue(kvp.Key.ToLower(), out var concurrentInstances); + AvailableStereotypes.TryGetValue(kvp.Key.ToLower(), out var availableInstances); + + if (maxInstances >= concurrentInstances && !string.IsNullOrEmpty(browserName)) + { + + AdjustInstance(browserName.ToLower(), AdjustType.Create); + + _availableStereotypesSemaphore.Release(); + return browserName.ToString(); + } + _availableStereotypesSemaphore.Release(); + continue; + + } + + // If no available browser is found, return the browser with the highest instances count + return statistics.OrderByDescending(x => x.Value).FirstOrDefault().Key ?? "Chrome"; + } + + private void AdjustInstance(string key,AdjustType type) + { + switch (type) + { + case AdjustType.Create: + if(ConcurrentStereotypes.ContainsKey(key)) + ConcurrentStereotypes[key]++; + + if(AvailableStereotypes.ContainsKey(key)) + AvailableStereotypes[key]--; + + break; + case AdjustType.Destroy: + if (ConcurrentStereotypes.ContainsKey(key)) + ConcurrentStereotypes[key]--; + + if (AvailableStereotypes.ContainsKey(key)) + AvailableStereotypes[key]++; + + break; + default: + break; + } + } #endregion } diff --git a/SeleniumManager.Tests/BrowsingTest.cs b/SeleniumManager.Tests/BrowsingTest.cs index b19cddb..3bdca2a 100644 --- a/SeleniumManager.Tests/BrowsingTest.cs +++ b/SeleniumManager.Tests/BrowsingTest.cs @@ -40,14 +40,15 @@ public async Task ParallelTestBrouse() { Task task = Task.Run(async () => { - var data = await _seleniumManager.EnqueueAction(BrouseGoogleWebsite); - _seleniumManager.TryExecuteNext(); - Thread.Sleep(2000); + // Enqueue the action and wait for its completion + await _seleniumManager.EnqueueAction(BrouseGoogleWebsite); + Thread.Sleep(3000); }); tasks.Add(task); } + // Wait for all tasks to complete await Task.WhenAll(tasks); } From c61d19dc8e44ad277f67efe4d3c07eff9fb876fb Mon Sep 17 00:00:00 2001 From: RohitM-IN Date: Sun, 16 Jul 2023 17:44:45 +0530 Subject: [PATCH 5/6] now statistics will load from configuration and that will be always in the ratio --- .../Configuration/config.json | 6 +++ .../DataContract/ConfigurationSettings.cs | 1 + SeleniumManager.Core/SeleniumManager.cs | 9 +--- SeleniumManager.Core/Utils/RatioDictionary.cs | 49 +++++++++++++++++++ 4 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 SeleniumManager.Core/Utils/RatioDictionary.cs diff --git a/SeleniumManager.Core/Configuration/config.json b/SeleniumManager.Core/Configuration/config.json index 35376e3..bbfdeb7 100644 --- a/SeleniumManager.Core/Configuration/config.json +++ b/SeleniumManager.Core/Configuration/config.json @@ -1,6 +1,12 @@ { "Gridhost": "http://127.0.0.1:4444", "Secret": "", + "statistics": { + "Chrome": 2, + "MicrosoftEdge": 1, + "Firefox": 0, + "Internet Explorer": 0 + }, "drivers": [ "chrome", "firefox", diff --git a/SeleniumManager.Core/DataContract/ConfigurationSettings.cs b/SeleniumManager.Core/DataContract/ConfigurationSettings.cs index ccb0aa3..b47f092 100644 --- a/SeleniumManager.Core/DataContract/ConfigurationSettings.cs +++ b/SeleniumManager.Core/DataContract/ConfigurationSettings.cs @@ -10,6 +10,7 @@ namespace SeleniumManager.Core.DataContract public class ConfigurationSettings { public string GridHost { get; set; } + public Dictionary statistics { get; set; } public List Drivers { get; set; } public string Secret { get; set; } public int MaxConcurrency { get; set; } diff --git a/SeleniumManager.Core/SeleniumManager.cs b/SeleniumManager.Core/SeleniumManager.cs index 1c9185e..8819550 100644 --- a/SeleniumManager.Core/SeleniumManager.cs +++ b/SeleniumManager.Core/SeleniumManager.cs @@ -6,6 +6,7 @@ using OpenQA.Selenium.Remote; using SeleniumManager.Core.DataContract; using SeleniumManager.Core.Interface; +using SeleniumManager.Core.Utils; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -273,13 +274,7 @@ private bool IsBrowserAvailable(string browserName) private async Task FindBestAvailableBrowser() { - var statistics = new Dictionary() - { - { "Chrome", 8 }, - { "MicrosoftEdge", 8 }, - { "Firefox", 0 }, - { "Internet Explorer", 0 } - }; + var statistics = RatioDictionary.GetRatioDictionary(_configSettings.statistics, MaxSessions); foreach (var kvp in statistics.OrderByDescending(x => x.Value)) { diff --git a/SeleniumManager.Core/Utils/RatioDictionary.cs b/SeleniumManager.Core/Utils/RatioDictionary.cs new file mode 100644 index 0000000..3842fb8 --- /dev/null +++ b/SeleniumManager.Core/Utils/RatioDictionary.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SeleniumManager.Core.Utils +{ + public class RatioDictionary + { + public static Dictionary GetRatioDictionary(Dictionary dict, int maxNumber) + { + Dictionary share = new Dictionary(); + foreach (KeyValuePair item in dict) + { + share[item.Key] = (int)(item.Value * maxNumber / sum(dict.Values)); + } + + int remainingValue = maxNumber - sum(share.Values); + if (remainingValue > 0) + { + string highestValueKey = ""; + int highestValue = 0; + foreach (KeyValuePair item in share) + { + if (item.Value > highestValue) + { + highestValue = item.Value; + highestValueKey = item.Key; + } + } + + share[highestValueKey] += remainingValue; + } + + return share; + } + + private static int sum(IEnumerable values) + { + int sum = 0; + foreach (int value in values) + { + sum += value; + } + return sum; + } + } +} From f913b277d9f68285ae7d9d818391482e4dfc761a Mon Sep 17 00:00:00 2001 From: RohitM-IN Date: Sun, 16 Jul 2023 17:53:08 +0530 Subject: [PATCH 6/6] update to 0.0.0.3-alpha --- SeleniumManager.Core/SeleniumManager.Core.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SeleniumManager.Core/SeleniumManager.Core.csproj b/SeleniumManager.Core/SeleniumManager.Core.csproj index f04ad3c..133f9fe 100644 --- a/SeleniumManager.Core/SeleniumManager.Core.csproj +++ b/SeleniumManager.Core/SeleniumManager.Core.csproj @@ -14,8 +14,8 @@ This include managing Queues, Parallel Tests, etc. MIT License True - 0.0.0.1 - 0.0.0.2-alpha + 0.0.0.3 + 0.0.0.3-alpha