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 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/BrowserStackLocal.csproj b/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj index 7711dbb..688943d 100644 --- a/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj +++ b/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj @@ -2,14 +2,14 @@ BrowserStack BrowserStackLocal - net20;netstandard2.0 + net7.0 false 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 @@ -18,9 +18,6 @@ - - - diff --git a/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs b/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs index 40ed6c1..4134cc2 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; + + private static string userAgent = ""; + private 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() { @@ -84,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); @@ -102,14 +119,19 @@ public virtual void addBinaryArguments(string binaryArguments) this.binaryArguments = binaryArguments; } - public BrowserStackTunnel() + public BrowserStackTunnel(string userAgentParam) { + 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."); @@ -121,7 +143,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 +165,58 @@ public void modifyBinaryPermission() } } + 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 } + }; + + if (isFallbackEnabled) + { + data["error_message"] = downloadFailureException.Message; + } + + var jsonData = JsonConvert.SerializeObject(data); + var content = new StringContent(jsonData, Encoding.UTF8, "application/json"); + + 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(); + + var responseString = response.Content.ReadAsStringAsync().Result; + + var jsonResponse = JObject.Parse(responseString); + + if (jsonResponse["error"] != null) + { + throw new Exception((string)jsonResponse["error"]); + } + + sourceUrl = jsonResponse["data"]?["endpoint"]?.ToString(); + return sourceUrl; + } + } + public void downloadBinary() { string binaryDirectory = Path.Combine(this.binaryAbsolute, ".."); - //string binaryAbsolute = Path.Combine(binaryDirectory, binaryName); Directory.CreateDirectory(binaryDirectory); using (var client = new WebClient()) { - client.DownloadFile(downloadURL, this.binaryAbsolute); + client.DownloadFile(sourceUrl + "/" + binaryName, this.binaryAbsolute); } if (!File.Exists(binaryAbsolute)) diff --git a/BrowserStackLocal/BrowserStackLocal/Local.cs b/BrowserStackLocal/BrowserStackLocal/Local.cs index 5398c08..6c57251 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,59 @@ 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) + + private void DownloadVerifyAndRunBinary() { tunnel.basePathsIndex = -1; + tunnel.addBinaryPath(customBinaryPath, accessKey, isFallbackEnabled, downloadFailureException); + try + { + while (true) + { + bool except = false; + try + { + tunnel.Run(accessKey, folder, customLogPath, "start"); + } + catch (System.ComponentModel.Win32Exception) + { + except = true; + } + catch (Exception e) + { + except = true; + Console.WriteLine(e.ToString()); + } + if (except) + { + tunnel.fallbackPaths(); + } + else + { + break; + } + } + } + catch (Exception err) + { + if (!isFallbackEnabled) + { + isFallbackEnabled = true; + downloadFailureException = err; + DownloadVerifyAndRunBinary(); + } + else + { + throw err; + } + } + } + + public void start(List> options) + { foreach (KeyValuePair pair in options) { string key = pair.Key; @@ -174,33 +225,9 @@ public void start(List> options) argumentString += "-logFile \"" + customLogPath + "\" "; argumentString += "--source \"c-sharp:" + bindingVersion + "\" "; - tunnel.addBinaryPath(customBinaryPath); tunnel.addBinaryArguments(argumentString); - while (true) - { - bool except = false; - try - { - tunnel.Run(accessKey, folder, customLogPath, "start"); - } - catch (System.ComponentModel.Win32Exception) - { - except = true; - } - catch (Exception e) - { - except = true; - Console.WriteLine(e.ToString()); - } - if (except) - { - tunnel.fallbackPaths(); - } - else - { - break; - } - } + + DownloadVerifyAndRunBinary(); } public void stop() 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 + 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..28e410f 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("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); 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