From 0e6e34a82e1cc8dfa7a2dda80de1ccae3a8e8d28 Mon Sep 17 00:00:00 2001 From: amaanbs Date: Fri, 13 Jun 2025 11:32:29 +0530 Subject: [PATCH 01/11] Change Binary Download Distribution --- .../BrowserStackLocal/BrowserStackTunnel.cs | 72 ++++++++++++++++--- BrowserStackLocal/BrowserStackLocal/Local.cs | 66 +++++++++++------ 2 files changed, 110 insertions(+), 28 deletions(-) diff --git a/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs b/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs index 40ed6c1..c9e5837 100644 --- a/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs +++ b/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs @@ -8,6 +8,12 @@ using System.Security.Principal; using Newtonsoft.Json.Linq; + +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using Newtonsoft.Json; + namespace BrowserStack { public enum LocalState { Idle, Connecting, Connected, Error, Disconnected }; @@ -16,7 +22,11 @@ public class BrowserStackTunnel : IDisposable { static readonly string uname = Util.GetUName(); static readonly string binaryName = GetBinaryName(); - static readonly string downloadURL = "https://www.browserstack.com/local-testing/downloads/binaries/" + binaryName; + + static readonly string userAgent = ""; + static readonly string sourceUrl = null; + private bool isFallbackEnabled = false; + private Exception downloadFailureException = null; static readonly string homepath = !IsWindows() ? Environment.GetFolderPath(Environment.SpecialFolder.Personal) : @@ -41,7 +51,7 @@ static bool IsDarwin(string osName) { return osName.Contains("darwin"); } - + static bool IsWindows() { @@ -102,8 +112,9 @@ public virtual void addBinaryArguments(string binaryArguments) this.binaryArguments = binaryArguments; } - public BrowserStackTunnel() + public BrowserStackTunnel(string userAgent) { + userAgent = userAgent; localState = LocalState.Idle; output = new StringBuilder(); } @@ -121,7 +132,7 @@ public virtual void fallbackPaths() public void modifyBinaryPermission() { if (!IsWindows()) - { + { try { using (Process proc = Process.Start("/bin/bash", $"-c \"chmod 0755 {this.binaryAbsolute}\"")) @@ -143,16 +154,59 @@ public void modifyBinaryPermission() } } - public void downloadBinary() + private string fetchSourceUrl(string accessKey) + { + var url = "https://local.browserstack.com/binary/api/v1/endpoint"; + + using (var client = new HttpClient()) + { + var data = new Dictionary + { + { "auth_token", accessKey } + }; + client.DefaultRequestHeaders.Add("Content-Type", "application/json"); + client.DefaultRequestHeaders.Add("user-agent", userAgent); + + if (isFallbackEnabled) + { + data["error_message"] = downloadFailureException.Message; + client.DefaultRequestHeaders.Add("X-Local-Fallback-Cloudflare", "true"); + } + + string jsonData = JsonConvert.SerializeObject(data); + var content = new StringContent(jsonData, Encoding.UTF8, "application/json"); + + HttpResponseMessage response = await client.PostAsync(url, content); + + response.EnsureSuccessStatusCode(); + + string responseString = await response.Content.ReadAsStringAsync(); + + dynamic jsonResponse = JsonConvert.DeserializeObject(responseString); + + Console.WriteLine("Response JSON:"); + Console.WriteLine(jsonResponse); + + if (jsonResponse.error != null) + { + throw new Exception(jsonResponse.error); + } + return jsonResponse.data.endpoint; + } + } + + public void downloadBinary(string accessKey) { string binaryDirectory = Path.Combine(this.binaryAbsolute, ".."); //string binaryAbsolute = Path.Combine(binaryDirectory, binaryName); + string sourceDownloadUrl = fetchSourceUrl(accessKey); + Directory.CreateDirectory(binaryDirectory); using (var client = new WebClient()) { - client.DownloadFile(downloadURL, this.binaryAbsolute); + client.DownloadFile(sourceDownloadUrl + "/" + binaryName, this.binaryAbsolute); } if (!File.Exists(binaryAbsolute)) @@ -163,7 +217,7 @@ public void downloadBinary() modifyBinaryPermission(); } - public virtual void Run(string accessKey, string folder, string logFilePath, string processType) + public virtual void Run(string accessKey, string folder, string logFilePath, string processType, bool fallbackEnabled, Exception failureException) { string arguments = "-d " + processType + " "; if (folder != null && folder.Trim().Length != 0) @@ -176,7 +230,9 @@ public virtual void Run(string accessKey, string folder, string logFilePath, str } if (!File.Exists(binaryAbsolute)) { - downloadBinary(); + isFallbackEnabled = fallbackEnabled; + downloadFailureException = failureException; + downloadBinary(accessKey); } if (process != null) diff --git a/BrowserStackLocal/BrowserStackLocal/Local.cs b/BrowserStackLocal/BrowserStackLocal/Local.cs index 5398c08..9fa65ff 100644 --- a/BrowserStackLocal/BrowserStackLocal/Local.cs +++ b/BrowserStackLocal/BrowserStackLocal/Local.cs @@ -14,6 +14,9 @@ public class Local private string argumentString = ""; private string customBinaryPath = ""; private string bindingVersion = ""; + private string userAgent = "browserstack-local-csharp"; + private bool isFallbackEnabled = false; + private Exception downloadFailureException = null; protected BrowserStackTunnel tunnel = null; private static KeyValuePair emptyStringPair = new KeyValuePair(); @@ -144,11 +147,11 @@ public static string GetVersionStringFromAssemblyEmbedded(string pAssemblyDispla public Local() { bindingVersion = GetVersionStringFromAssemblyEmbedded("BrowserStackLocal"); - tunnel = new BrowserStackTunnel(); + userAgent = userAgent + "/" + bindingVersion; + tunnel = new BrowserStackTunnel(userAgent); } public void start(List> options) { - tunnel.basePathsIndex = -1; foreach (KeyValuePair pair in options) { string key = pair.Key; @@ -174,38 +177,61 @@ public void start(List> options) argumentString += "-logFile \"" + customLogPath + "\" "; argumentString += "--source \"c-sharp:" + bindingVersion + "\" "; - tunnel.addBinaryPath(customBinaryPath); tunnel.addBinaryArguments(argumentString); - while (true) + + DownloadVerifyAndRunBinary(); + } + + private void DownloadVerifyAndRunBinary() + { + tunnel.basePathsIndex = -1; + tunnel.addBinaryPath(customBinaryPath); + try { - bool except = false; - try - { - tunnel.Run(accessKey, folder, customLogPath, "start"); - } - catch (System.ComponentModel.Win32Exception) - { - except = true; - } - catch (Exception e) + while (true) { - except = true; - Console.WriteLine(e.ToString()); + bool except = false; + try + { + tunnel.Run(accessKey, folder, customLogPath, "start", isFallbackEnabled, downloadFailureException); + } + catch (System.ComponentModel.Win32Exception) + { + except = true; + } + catch (Exception e) + { + except = true; + Console.WriteLine(e.ToString()); + } + if (except) + { + tunnel.fallbackPaths(); + } + else + { + break; + } } - if (except) + } + catch (Exception err) + { + if (!isFallbackEnabled) { - tunnel.fallbackPaths(); + isFallbackEnabled = true; + downloadFailureException = err; + downloadVerifyAndRunBinary(); } else { - break; + throw err; } } } public void stop() { - tunnel.Run(accessKey, folder, customLogPath, "stop"); + tunnel.Run(accessKey, folder, customLogPath, "stop", isFallbackEnabled, downloadFailureException); tunnel.Kill(); } } From c5c24818b1acb3a62b701f0ae47972ab50d75863 Mon Sep 17 00:00:00 2001 From: amaanbs Date: Tue, 17 Jun 2025 12:54:34 +0530 Subject: [PATCH 02/11] Fixes --- .../BrowserStackTunnelTests.cs | 10 +-- .../LocalTests.cs | 12 ++-- .../BrowserStackLocal/BrowserStackTunnel.cs | 58 ++++++++------- BrowserStackLocal/BrowserStackLocal/Local.cs | 71 ++++++++++--------- 4 files changed, 80 insertions(+), 71 deletions(-) diff --git a/BrowserStackLocal/BrowserStackLocal Unit Tests/BrowserStackTunnelTests.cs b/BrowserStackLocal/BrowserStackLocal Unit Tests/BrowserStackTunnelTests.cs index 2a32216..ad13e95 100644 --- a/BrowserStackLocal/BrowserStackLocal Unit Tests/BrowserStackTunnelTests.cs +++ b/BrowserStackLocal/BrowserStackLocal Unit Tests/BrowserStackTunnelTests.cs @@ -30,14 +30,14 @@ public void TestInitialState() public void TestBinaryPathIsSet() { tunnel = new TunnelClass(); - tunnel.addBinaryPath("dummyPath"); + tunnel.addBinaryPath("dummyPath", ""); Assert.AreEqual(tunnel.getBinaryAbsolute(), "dummyPath"); } [TestMethod] public void TestBinaryPathOnNull() { tunnel = new TunnelClass(); - tunnel.addBinaryPath(null); + tunnel.addBinaryPath(null, ""); string expectedPath = Path.Combine(homepath, ".browserstack"); expectedPath = Path.Combine(expectedPath, binaryName); Assert.AreEqual(tunnel.getBinaryAbsolute(), expectedPath); @@ -46,7 +46,7 @@ public void TestBinaryPathOnNull() public void TestBinaryPathOnEmpty() { tunnel = new TunnelClass(); - tunnel.addBinaryPath(""); + tunnel.addBinaryPath("", ""); string expectedPath = Path.Combine(homepath, ".browserstack"); expectedPath = Path.Combine(expectedPath, binaryName); Assert.AreEqual(tunnel.getBinaryAbsolute(), expectedPath); @@ -56,7 +56,7 @@ public void TestBinaryPathOnFallback() { string expectedPath = "dummyPath"; tunnel = new TunnelClass(); - tunnel.addBinaryPath("dummyPath"); + tunnel.addBinaryPath("dummyPath", ""); Assert.AreEqual(tunnel.getBinaryAbsolute(), expectedPath); tunnel.fallbackPaths(); @@ -78,7 +78,7 @@ public void TestBinaryPathOnFallback() public void TestBinaryPathOnNoMoreFallback() { tunnel = new TunnelClass(); - tunnel.addBinaryPath("dummyPath"); + tunnel.addBinaryPath("dummyPath", ""); tunnel.fallbackPaths(); tunnel.fallbackPaths(); tunnel.fallbackPaths(); diff --git a/BrowserStackLocal/BrowserStackLocal Unit Tests/LocalTests.cs b/BrowserStackLocal/BrowserStackLocal Unit Tests/LocalTests.cs index ff03d1e..8be3eb6 100644 --- a/BrowserStackLocal/BrowserStackLocal Unit Tests/LocalTests.cs +++ b/BrowserStackLocal/BrowserStackLocal Unit Tests/LocalTests.cs @@ -107,7 +107,7 @@ public void TestWorksForBinaryPath() tunnelMock.Setup(mock => mock.Run("dummyKey", "", logAbsolute, "start")); local.setTunnel(tunnelMock.Object); local.start(options); - tunnelMock.Verify(mock => mock.addBinaryPath("dummyPath"), Times.Once); + tunnelMock.Verify(mock => mock.addBinaryPath("dummyPath", ""), Times.Once); tunnelMock.Verify(mock => mock.addBinaryArguments(It.IsRegex("-logFile \"" + logAbsolute + "\" .*")), Times.Once()); tunnelMock.Verify(mock => mock.Run("dummyKey", "", logAbsolute, "start"), Times.Once()); local.stop(); @@ -129,7 +129,7 @@ public void TestWorksWithBooleanOptions() tunnelMock.Setup(mock => mock.Run("dummyKey", "", logAbsolute, "start")); local.setTunnel(tunnelMock.Object); local.start(options); - tunnelMock.Verify(mock => mock.addBinaryPath(""), Times.Once); + tunnelMock.Verify(mock => mock.addBinaryPath("", ""), Times.Once); tunnelMock.Verify(mock => mock.addBinaryArguments(It.IsRegex("-vvv.*-force.*-forcelocal.*-forceproxy.*-onlyAutomate.*")), Times.Once()); tunnelMock.Verify(mock => mock.Run("dummyKey", "", logAbsolute, "start"), Times.Once()); local.stop(); @@ -152,7 +152,7 @@ public void TestWorksWithValueOptions() tunnelMock.Setup(mock =>mock.Run("dummyKey", "", logAbsolute, "start")); local.setTunnel(tunnelMock.Object); local.start(options); - tunnelMock.Verify(mock => mock.addBinaryPath(""), Times.Once); + tunnelMock.Verify(mock => mock.addBinaryPath("", ""), Times.Once); tunnelMock.Verify(mock => mock.addBinaryArguments( It.IsRegex("-localIdentifier.*dummyIdentifier.*dummyHost.*-proxyHost.*dummyHost.*-proxyPort.*dummyPort.*-proxyUser.*dummyUser.*-proxyPass.*dummyPass.*") ), Times.Once()); @@ -175,7 +175,7 @@ public void TestWorksWithCustomOptions() tunnelMock.Setup(mock => mock.Run("dummyKey", "", logAbsolute, "start")); local.setTunnel(tunnelMock.Object); local.start(options); - tunnelMock.Verify(mock => mock.addBinaryPath(""), Times.Once); + tunnelMock.Verify(mock => mock.addBinaryPath("", ""), Times.Once); tunnelMock.Verify(mock => mock.addBinaryArguments( It.IsRegex("-customBoolKey1.*-customBoolKey2.*-customKey1.*customValue1.*-customKey2.*customValue2.*") ), Times.Once()); @@ -200,7 +200,7 @@ public void TestCallsFallbackOnFailure() }); local.setTunnel(tunnelMock.Object); local.start(options); - tunnelMock.Verify(mock => mock.addBinaryPath(""), Times.Once); + tunnelMock.Verify(mock => mock.addBinaryPath("", ""), Times.Once); tunnelMock.Verify(mock => mock.addBinaryArguments(It.IsRegex("-logFile \"" + logAbsolute + "\" .*")), Times.Once()); tunnelMock.Verify(mock => mock.Run("dummyKey", "", logAbsolute, "start"), Times.Exactly(2)); tunnelMock.Verify(mock => mock.fallbackPaths(), Times.Once()); @@ -219,7 +219,7 @@ public void TestKillsTunnel() local.setTunnel(tunnelMock.Object); local.start(options); local.stop(); - tunnelMock.Verify(mock => mock.addBinaryPath(""), Times.Once); + tunnelMock.Verify(mock => mock.addBinaryPath("", ""), Times.Once); tunnelMock.Verify(mock => mock.addBinaryArguments(It.IsRegex("-logFile \"" + logAbsolute + "\" .*")), Times.Once()); tunnelMock.Verify(mock => mock.Run("dummyKey", "", logAbsolute, "start"), Times.Once()); } diff --git a/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs b/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs index c9e5837..e366afb 100644 --- a/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs +++ b/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs @@ -23,8 +23,8 @@ public class BrowserStackTunnel : IDisposable static readonly string uname = Util.GetUName(); static readonly string binaryName = GetBinaryName(); - static readonly string userAgent = ""; - static readonly string sourceUrl = null; + private static string userAgent = ""; + private string sourceUrl = null; private bool isFallbackEnabled = false; private Exception downloadFailureException = null; @@ -94,8 +94,15 @@ static string GetBinaryName() return "BrowserStackLocal.exe"; } - public virtual void addBinaryPath(string binaryAbsolute) + public virtual void addBinaryPath(string binaryAbsolute, string accessKey, bool fallbackEnabled = false, Exception failureException = null) { + if (basePathsIndex == -1) + { + /* Called at most twice (primary & a fallback) */ + isFallbackEnabled = fallbackEnabled; + downloadFailureException = failureException; + fetchSourceUrl(accessKey); + } if (binaryAbsolute == null || binaryAbsolute.Trim().Length == 0) { binaryAbsolute = Path.Combine(basePaths[++basePathsIndex], binaryName); @@ -112,15 +119,19 @@ public virtual void addBinaryArguments(string binaryArguments) this.binaryArguments = binaryArguments; } - public BrowserStackTunnel(string userAgent) + public BrowserStackTunnel(string userAgentParam) { - userAgent = userAgent; + userAgent = userAgentParam; localState = LocalState.Idle; output = new StringBuilder(); } public virtual void fallbackPaths() { + if (File.Exists(binaryAbsolute)) + { + File.Delete(binaryAbsolute); + } if (basePathsIndex >= basePaths.Length - 1) { throw new Exception("Binary not found or failed to launch. Make sure that BrowserStackLocal is not already running."); @@ -164,49 +175,48 @@ private string fetchSourceUrl(string accessKey) { { "auth_token", accessKey } }; - client.DefaultRequestHeaders.Add("Content-Type", "application/json"); - client.DefaultRequestHeaders.Add("user-agent", userAgent); if (isFallbackEnabled) { data["error_message"] = downloadFailureException.Message; - client.DefaultRequestHeaders.Add("X-Local-Fallback-Cloudflare", "true"); } - string jsonData = JsonConvert.SerializeObject(data); + var jsonData = JsonConvert.SerializeObject(data); var content = new StringContent(jsonData, Encoding.UTF8, "application/json"); - HttpResponseMessage response = await client.PostAsync(url, content); + client.DefaultRequestHeaders.Add("User-Agent", userAgent); + if (isFallbackEnabled) + { + client.DefaultRequestHeaders.Add("X-Local-Fallback-Cloudflare", "true"); + } + + var response = client.PostAsync(url, content).Result; response.EnsureSuccessStatusCode(); - string responseString = await response.Content.ReadAsStringAsync(); - - dynamic jsonResponse = JsonConvert.DeserializeObject(responseString); + var responseString = response.Content.ReadAsStringAsync().Result; - Console.WriteLine("Response JSON:"); - Console.WriteLine(jsonResponse); + var jsonResponse = JObject.Parse(responseString); - if (jsonResponse.error != null) + if (jsonResponse["error"] != null) { - throw new Exception(jsonResponse.error); + throw new Exception((string)jsonResponse["error"]); } - return jsonResponse.data.endpoint; + + sourceUrl = jsonResponse["data"]?["endpoint"]?.ToString(); + return sourceUrl; } } public void downloadBinary(string accessKey) { string binaryDirectory = Path.Combine(this.binaryAbsolute, ".."); - //string binaryAbsolute = Path.Combine(binaryDirectory, binaryName); - - string sourceDownloadUrl = fetchSourceUrl(accessKey); Directory.CreateDirectory(binaryDirectory); using (var client = new WebClient()) { - client.DownloadFile(sourceDownloadUrl + "/" + binaryName, this.binaryAbsolute); + client.DownloadFile(sourceUrl + "/" + binaryName, this.binaryAbsolute); } if (!File.Exists(binaryAbsolute)) @@ -217,7 +227,7 @@ public void downloadBinary(string accessKey) modifyBinaryPermission(); } - public virtual void Run(string accessKey, string folder, string logFilePath, string processType, bool fallbackEnabled, Exception failureException) + public virtual void Run(string accessKey, string folder, string logFilePath, string processType) { string arguments = "-d " + processType + " "; if (folder != null && folder.Trim().Length != 0) @@ -230,8 +240,6 @@ public virtual void Run(string accessKey, string folder, string logFilePath, str } if (!File.Exists(binaryAbsolute)) { - isFallbackEnabled = fallbackEnabled; - downloadFailureException = failureException; downloadBinary(accessKey); } diff --git a/BrowserStackLocal/BrowserStackLocal/Local.cs b/BrowserStackLocal/BrowserStackLocal/Local.cs index 9fa65ff..6c57251 100644 --- a/BrowserStackLocal/BrowserStackLocal/Local.cs +++ b/BrowserStackLocal/BrowserStackLocal/Local.cs @@ -150,42 +150,11 @@ public Local() userAgent = userAgent + "/" + bindingVersion; tunnel = new BrowserStackTunnel(userAgent); } - public void start(List> options) - { - foreach (KeyValuePair pair in options) - { - string key = pair.Key; - string value = pair.Value; - addArgs(key, value); - } - - if (accessKey == null || accessKey.Trim().Length == 0) - { - accessKey = Environment.GetEnvironmentVariable("BROWSERSTACK_ACCESS_KEY"); - if (accessKey == null || accessKey.Trim().Length == 0) - { - throw new Exception("BROWSERSTACK_ACCESS_KEY cannot be empty. " + - "Specify one by adding key to options or adding to the environment variable BROWSERSTACK_ACCESS_KEY."); - } - Regex.Replace(this.accessKey, @"\s+", ""); - } - - if (customLogPath == null || customLogPath.Trim().Length == 0) - { - customLogPath = Path.Combine(BrowserStackTunnel.basePaths[1], "local.log"); - } - - argumentString += "-logFile \"" + customLogPath + "\" "; - argumentString += "--source \"c-sharp:" + bindingVersion + "\" "; - tunnel.addBinaryArguments(argumentString); - - DownloadVerifyAndRunBinary(); - } private void DownloadVerifyAndRunBinary() { tunnel.basePathsIndex = -1; - tunnel.addBinaryPath(customBinaryPath); + tunnel.addBinaryPath(customBinaryPath, accessKey, isFallbackEnabled, downloadFailureException); try { while (true) @@ -193,7 +162,7 @@ private void DownloadVerifyAndRunBinary() bool except = false; try { - tunnel.Run(accessKey, folder, customLogPath, "start", isFallbackEnabled, downloadFailureException); + tunnel.Run(accessKey, folder, customLogPath, "start"); } catch (System.ComponentModel.Win32Exception) { @@ -220,7 +189,7 @@ private void DownloadVerifyAndRunBinary() { isFallbackEnabled = true; downloadFailureException = err; - downloadVerifyAndRunBinary(); + DownloadVerifyAndRunBinary(); } else { @@ -229,9 +198,41 @@ private void DownloadVerifyAndRunBinary() } } + public void start(List> options) + { + foreach (KeyValuePair pair in options) + { + string key = pair.Key; + string value = pair.Value; + addArgs(key, value); + } + + if (accessKey == null || accessKey.Trim().Length == 0) + { + accessKey = Environment.GetEnvironmentVariable("BROWSERSTACK_ACCESS_KEY"); + if (accessKey == null || accessKey.Trim().Length == 0) + { + throw new Exception("BROWSERSTACK_ACCESS_KEY cannot be empty. " + + "Specify one by adding key to options or adding to the environment variable BROWSERSTACK_ACCESS_KEY."); + } + Regex.Replace(this.accessKey, @"\s+", ""); + } + + if (customLogPath == null || customLogPath.Trim().Length == 0) + { + customLogPath = Path.Combine(BrowserStackTunnel.basePaths[1], "local.log"); + } + + argumentString += "-logFile \"" + customLogPath + "\" "; + argumentString += "--source \"c-sharp:" + bindingVersion + "\" "; + tunnel.addBinaryArguments(argumentString); + + DownloadVerifyAndRunBinary(); + } + public void stop() { - tunnel.Run(accessKey, folder, customLogPath, "stop", isFallbackEnabled, downloadFailureException); + tunnel.Run(accessKey, folder, customLogPath, "stop"); tunnel.Kill(); } } From 01ad6feb52af4270cfcff7a4f61282ae9e1d3d9b Mon Sep 17 00:00:00 2001 From: amaanbs Date: Tue, 17 Jun 2025 13:08:41 +0530 Subject: [PATCH 03/11] Minor change --- BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs b/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs index e366afb..4134cc2 100644 --- a/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs +++ b/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs @@ -208,7 +208,7 @@ private string fetchSourceUrl(string accessKey) } } - public void downloadBinary(string accessKey) + public void downloadBinary() { string binaryDirectory = Path.Combine(this.binaryAbsolute, ".."); @@ -240,7 +240,7 @@ public virtual void Run(string accessKey, string folder, string logFilePath, str } if (!File.Exists(binaryAbsolute)) { - downloadBinary(accessKey); + downloadBinary(); } if (process != null) From 79d48d01c1c0c664b79c3dc75a8901a098d5c4bb Mon Sep 17 00:00:00 2001 From: amaanbs Date: Wed, 18 Jun 2025 18:17:54 +0530 Subject: [PATCH 04/11] Remove dotnet 2 support --- BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj b/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj index 7711dbb..b0f902f 100644 --- a/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj +++ b/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj @@ -2,7 +2,7 @@ BrowserStack BrowserStackLocal - net20;netstandard2.0 + netstandard2.0 false BrowserStackLocal BrowserStackLocal From 227ad4a5b0f507fea7b2ba3f3f9b87d29763f0af Mon Sep 17 00:00:00 2001 From: amaanbs Date: Thu, 19 Jun 2025 13:21:24 +0530 Subject: [PATCH 05/11] Version bump --- .../BrowserStackLocal/BrowserStackLocal.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj b/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj index 7711dbb..0e1dab9 100644 --- a/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj +++ b/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj @@ -7,9 +7,9 @@ BrowserStackLocal BrowserStackLocal C# Bindings for BrowserStack Local - 2.4.0 - 2.4.0 - 2.4.0 + 3.0.0 + 3.0.0 + 3.0.0 BrowserStack BrowserStack Copyright © 2016 From c3233eb10127d581823d871d68437f017c945157 Mon Sep 17 00:00:00 2001 From: amaanbs Date: Thu, 19 Jun 2025 20:52:16 +0530 Subject: [PATCH 06/11] Targetr dotnet v7 --- BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj b/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj index 7711dbb..8bcaa42 100644 --- a/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj +++ b/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj @@ -2,7 +2,7 @@ BrowserStack BrowserStackLocal - net20;netstandard2.0 + net7.0 false BrowserStackLocal BrowserStackLocal From 8398ea10a351af5ed2702ede2ff56f3f583f5007 Mon Sep 17 00:00:00 2001 From: "Yash D. Saraf" Date: Thu, 19 Jun 2025 21:14:01 +0530 Subject: [PATCH 07/11] Update CI workflow to use dotnet v7 --- .github/workflows/cd.yml | 2 +- .github/workflows/ci.yml | 2 +- .../BrowserStackLocal/BrowserStackLocal.csproj | 3 --- .../BrowserStackLocalIntegrationTests.csproj | 13 ++++--------- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 348f841..d88089e 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -25,7 +25,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: 3.1.301 + dotnet-version: 7.0.20 - name: Run Integration Tests env: BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ee677c..08cbcf8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: 3.1.301 + dotnet-version: 7.0.20 - name: Run Integration Tests env: BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }} diff --git a/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj b/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj index 71156ce..688943d 100644 --- a/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj +++ b/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj @@ -18,9 +18,6 @@ - - - diff --git a/BrowserStackLocal/BrowserStackLocalIntegrationTests/BrowserStackLocalIntegrationTests.csproj b/BrowserStackLocal/BrowserStackLocalIntegrationTests/BrowserStackLocalIntegrationTests.csproj index 1330776..54542d7 100644 --- a/BrowserStackLocal/BrowserStackLocalIntegrationTests/BrowserStackLocalIntegrationTests.csproj +++ b/BrowserStackLocal/BrowserStackLocalIntegrationTests/BrowserStackLocalIntegrationTests.csproj @@ -1,7 +1,7 @@ - net45;netcoreapp3.1 + net7.0 false @@ -12,16 +12,11 @@ - + - ..\BrowserStackLocal\bin\$(Configuration)\net20\BrowserStackLocal.dll - - - - - ..\BrowserStackLocal\bin\$(Configuration)\netstandard2.0\BrowserStackLocal.dll + ..\BrowserStackLocal\bin\$(Configuration)\net7.0\BrowserStackLocal.dll - \ No newline at end of file + From 4bb99811f151e9278a55c9e14e96990ac0a1eb22 Mon Sep 17 00:00:00 2001 From: "Yash D. Saraf" Date: Thu, 19 Jun 2025 21:14:01 +0530 Subject: [PATCH 08/11] Update CI workflow to use dotnet v7 --- .github/workflows/cd.yml | 4 ++-- .github/workflows/ci.yml | 4 ++-- .../BrowserStackLocal Unit Tests.csproj | 13 ++++--------- .../BrowserStackLocal/BrowserStackLocal.csproj | 3 --- .../BrowserStackLocalIntegrationTests.csproj | 13 ++++--------- 5 files changed, 12 insertions(+), 25 deletions(-) diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 348f841..8486139 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -23,9 +23,9 @@ jobs: msbuild BrowserStackLocalIntegrationTests -t:restore -p:Configuration=Release msbuild BrowserStackLocalIntegrationTests -t:build -p:Configuration=Release - name: Setup .NET Core - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: - dotnet-version: 3.1.301 + dotnet-version: 7.0.410 - name: Run Integration Tests env: BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ee677c..c7f79c6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,9 +23,9 @@ jobs: msbuild BrowserStackLocalIntegrationTests -t:restore -p:Configuration=Release msbuild BrowserStackLocalIntegrationTests -t:build -p:Configuration=Release - name: Setup .NET Core - uses: actions/setup-dotnet@v1 + uses: actions/setup-dotnet@v3 with: - dotnet-version: 3.1.301 + dotnet-version: 7.0.410 - name: Run Integration Tests env: BROWSERSTACK_USERNAME: ${{ secrets.BROWSERSTACK_USERNAME }} diff --git a/BrowserStackLocal/BrowserStackLocal Unit Tests/BrowserStackLocal Unit Tests.csproj b/BrowserStackLocal/BrowserStackLocal Unit Tests/BrowserStackLocal Unit Tests.csproj index cdc5f3d..75629c6 100644 --- a/BrowserStackLocal/BrowserStackLocal Unit Tests/BrowserStackLocal Unit Tests.csproj +++ b/BrowserStackLocal/BrowserStackLocal Unit Tests/BrowserStackLocal Unit Tests.csproj @@ -2,7 +2,7 @@ BrowserStackLocal_Unit_Tests BrowserStackLocal Unit Tests - net45;netcoreapp3.1 + net7.0 false BrowserStackLocal Unit Tests BrowserStackLocal Unit Tests @@ -18,15 +18,10 @@ - + - ..\BrowserStackLocal\bin\Debug\net20\BrowserStackLocal.dll - - - - - ..\BrowserStackLocal\bin\Debug\netstandard2.0\BrowserStackLocal.dll + ..\BrowserStackLocal\bin\$(Configuration)\net7.0\BrowserStackLocal.dll - \ No newline at end of file + diff --git a/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj b/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj index 71156ce..688943d 100644 --- a/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj +++ b/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj @@ -18,9 +18,6 @@ - - - diff --git a/BrowserStackLocal/BrowserStackLocalIntegrationTests/BrowserStackLocalIntegrationTests.csproj b/BrowserStackLocal/BrowserStackLocalIntegrationTests/BrowserStackLocalIntegrationTests.csproj index 1330776..54542d7 100644 --- a/BrowserStackLocal/BrowserStackLocalIntegrationTests/BrowserStackLocalIntegrationTests.csproj +++ b/BrowserStackLocal/BrowserStackLocalIntegrationTests/BrowserStackLocalIntegrationTests.csproj @@ -1,7 +1,7 @@ - net45;netcoreapp3.1 + net7.0 false @@ -12,16 +12,11 @@ - + - ..\BrowserStackLocal\bin\$(Configuration)\net20\BrowserStackLocal.dll - - - - - ..\BrowserStackLocal\bin\$(Configuration)\netstandard2.0\BrowserStackLocal.dll + ..\BrowserStackLocal\bin\$(Configuration)\net7.0\BrowserStackLocal.dll - \ No newline at end of file + From 71c2b5ae7910ba60554157e170943873a7bc43bd Mon Sep 17 00:00:00 2001 From: amaanbs Date: Thu, 19 Jun 2025 22:30:56 +0530 Subject: [PATCH 09/11] Fix example tests --- .../BrowserStackExample.csproj | 85 +++---------------- .../BrowserStackExample/Example.cs | 51 ++++++----- 2 files changed, 44 insertions(+), 92 deletions(-) diff --git a/BrowserStackLocalExample/BrowserStackExample/BrowserStackExample.csproj b/BrowserStackLocalExample/BrowserStackExample/BrowserStackExample.csproj index f4bb522..fc2e2b6 100644 --- a/BrowserStackLocalExample/BrowserStackExample/BrowserStackExample.csproj +++ b/BrowserStackLocalExample/BrowserStackExample/BrowserStackExample.csproj @@ -1,94 +1,37 @@ - - - + + - Debug - AnyCPU {9297DCCC-AE88-4E12-934A-B2BEA4864B49} Exe - Properties + net7.0 BrowserStackExample BrowserStackExample - v4.5 - 512 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true + enable + enable + false AnyCPU - true - full - false bin\Debug\ DEBUG;TRACE - prompt 4 AnyCPU - pdbonly - true bin\Release\ TRACE - prompt 4 + + + + + - ..\..\BrowserStackLocal\BrowserStackLocal\bin\Debug\net20\BrowserStackLocal.dll - - - - - - - - - - - - ..\packages\Selenium.WebDriver.2.52.0\lib\net40\WebDriver.dll + ..\..\BrowserStackLocal\BrowserStackLocal\bin\Debug\net7.0\BrowserStackLocal.dll True - - - - - - - False - Microsoft .NET Framework 4.5 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 - false - - - - - - - - \ No newline at end of file + + diff --git a/BrowserStackLocalExample/BrowserStackExample/Example.cs b/BrowserStackLocalExample/BrowserStackExample/Example.cs index 9eac3e3..d9502e2 100644 --- a/BrowserStackLocalExample/BrowserStackExample/Example.cs +++ b/BrowserStackLocalExample/BrowserStackExample/Example.cs @@ -2,6 +2,7 @@ using BrowserStack; using System.Collections.Generic; using OpenQA.Selenium; +using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Remote; namespace BrowserStackExample @@ -10,36 +11,44 @@ class Example { static void Main(string[] args) { + // Start BrowserStack Local Local local = new Local(); - - List> options = new List>() { + var bsLocalArgs = new List>() + { new KeyValuePair("key", BROWSERSTACK_ACCESS_KEY), - //new KeyValuePair("localIdentifier", "identifier"), - //new KeyValuePair("f", "C:\\Users\\Admin\\Desktop\\"), - new KeyValuePair("onlyAutomate", "true"), - new KeyValuePair("verbose", "true"), new KeyValuePair("forcelocal", "true"), - new KeyValuePair("binarypath", "C:\\Users\\Admin\\Desktop\\BrowserStackLocal.exe"), - new KeyValuePair("logfile", "C:\\Users\\Admin\\Desktop\\local.log"), + new KeyValuePair("verbose", "true"), + // new KeyValuePair("binarypath", "C:\\Users\\Admin\\Desktop\\BrowserStackLocal.exe"), + // new KeyValuePair("logfile", "C:\\Users\\Admin\\Desktop\\local.log"), }; - local.start(options); - - // Run WebDriver Tests - IWebDriver driver; - DesiredCapabilities capability = DesiredCapabilities.Chrome(); - capability.SetCapability("browserstack.user", BROWSERSTACK_USERNAME); - capability.SetCapability("browserstack.key", BROWSERSTACK_ACCESS_KEY); - //capability.SetCapability("browserstack.localIdentifier", "identifier"); - capability.SetCapability("browserstack.local", true); - capability.SetCapability("build", "build"); + local.start(bsLocalArgs); - driver = new RemoteWebDriver( - new Uri("http://hub.browserstack.com/wd/hub/"), capability + // Define BrowserStack capabilities + var browserstackOptions = new Dictionary + { + { "userName", BROWSERSTACK_USERNAME }, + { "accessKey", BROWSERSTACK_ACCESS_KEY }, + { "local", "true" }, + { "build", "build" } + }; + + // Set up ChromeOptions + ChromeOptions chromeOptions = new ChromeOptions(); + chromeOptions.BrowserVersion = "latest"; + chromeOptions.PlatformName = "Windows 10"; + chromeOptions.AddAdditionalOption("bstack:options", browserstackOptions); + + // Launch Remote WebDriver + IWebDriver driver = new RemoteWebDriver( + new Uri("https://hub.browserstack.com/wd/hub"), + chromeOptions ); + + // Run your test driver.Navigate().GoToUrl("http://www.google.com"); Console.WriteLine(driver.Title); - IWebElement query = driver.FindElement(By.Name("q")); + var query = driver.FindElement(By.Name("q")); query.SendKeys("Browserstack"); query.Submit(); Console.WriteLine(driver.Title); From 1e8729bde49537f1383342ea4e741106f13dd53c Mon Sep 17 00:00:00 2001 From: amaanbs Date: Thu, 19 Jun 2025 22:36:31 +0530 Subject: [PATCH 10/11] Minor fix --- BrowserStackLocalExample/BrowserStackExample/Example.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BrowserStackLocalExample/BrowserStackExample/Example.cs b/BrowserStackLocalExample/BrowserStackExample/Example.cs index d9502e2..28e410f 100644 --- a/BrowserStackLocalExample/BrowserStackExample/Example.cs +++ b/BrowserStackLocalExample/BrowserStackExample/Example.cs @@ -18,8 +18,8 @@ static void Main(string[] args) new KeyValuePair("key", BROWSERSTACK_ACCESS_KEY), new KeyValuePair("forcelocal", "true"), new KeyValuePair("verbose", "true"), - // new KeyValuePair("binarypath", "C:\\Users\\Admin\\Desktop\\BrowserStackLocal.exe"), - // new KeyValuePair("logfile", "C:\\Users\\Admin\\Desktop\\local.log"), + new KeyValuePair("binarypath", "C:\\Users\\Admin\\Desktop\\BrowserStackLocal.exe"), + new KeyValuePair("logfile", "C:\\Users\\Admin\\Desktop\\local.log"), }; local.start(bsLocalArgs); From 46e30df9bdabf968f2f9962c6bbc10cc0c63d4da Mon Sep 17 00:00:00 2001 From: amaanbs Date: Thu, 19 Jun 2025 22:42:42 +0530 Subject: [PATCH 11/11] Bump Selenium pkg --- BrowserStackLocalExample/BrowserStackExample/packages.config | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BrowserStackLocalExample/BrowserStackExample/packages.config b/BrowserStackLocalExample/BrowserStackExample/packages.config index d4dee4a..d085f87 100644 --- a/BrowserStackLocalExample/BrowserStackExample/packages.config +++ b/BrowserStackLocalExample/BrowserStackExample/packages.config @@ -1,4 +1,4 @@  - - \ No newline at end of file + + pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy