diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..269fa7e --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +BrowserStackLocal/BrowserStackLocal Unit Tests/bin +BrowserStackLocal/BrowserStackLocal Unit Tests/obj +BrowserStackLocal/BrowserStackLocal/bin +BrowserStackLocal/BrowserStackLocal/obj +BrowserStackLocal/packages +BrowserStackLocal/.vs \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index d9270a0..4178183 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: csharp -solution: BrowserStack/BrowserStack.sln +solution: BrowserStackLocal/BrowserStackLocal.sln before_install: - sudo apt-get install nunit-console after_script: - - nunit-console BrowserStack/BrowserStack\ Unit\ Tests/bin/Release/BrowserStack\ Unit\ Tests.dll + - nunit-console BrowserStackLocal/BrowserStackLocal\ Unit\ Tests/bin/Release/BrowserStackLocal\ Unit\ Tests.dll diff --git a/BrowserStack.dll b/BrowserStack.dll deleted file mode 100644 index 01a56bd..0000000 Binary files a/BrowserStack.dll and /dev/null differ diff --git a/BrowserStackLocal.0.1.0.0.nupkg b/BrowserStackLocal.0.1.0.0.nupkg new file mode 100644 index 0000000..fc8f66b Binary files /dev/null and b/BrowserStackLocal.0.1.0.0.nupkg differ diff --git a/BrowserStack/BrowserStack Unit Tests/BrowserStack Unit Tests.csproj b/BrowserStackLocal/BrowserStackLocal Unit Tests/BrowserStackLocal Unit Tests.csproj similarity index 96% rename from BrowserStack/BrowserStack Unit Tests/BrowserStack Unit Tests.csproj rename to BrowserStackLocal/BrowserStackLocal Unit Tests/BrowserStackLocal Unit Tests.csproj index d459c6d..8434c68 100644 --- a/BrowserStack/BrowserStack Unit Tests/BrowserStack Unit Tests.csproj +++ b/BrowserStackLocal/BrowserStackLocal Unit Tests/BrowserStackLocal Unit Tests.csproj @@ -6,8 +6,8 @@ {FF1ABB6F-4A2C-48F4-B4DB-47DAD566D2F9} Library Properties - BrowserStack_Unit_Tests - BrowserStack Unit Tests + BrowserStackLocal_Unit_Tests + BrowserStackLocal Unit Tests v4.5 512 {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} @@ -81,9 +81,9 @@ - + {f58e1c9a-5910-4da8-b531-9f4a6b0ae8c8} - BrowserStack + BrowserStackLocal diff --git a/BrowserStack/BrowserStack Unit Tests/BrowserStackTunnelTests.cs b/BrowserStackLocal/BrowserStackLocal Unit Tests/BrowserStackTunnelTests.cs similarity index 100% rename from BrowserStack/BrowserStack Unit Tests/BrowserStackTunnelTests.cs rename to BrowserStackLocal/BrowserStackLocal Unit Tests/BrowserStackTunnelTests.cs diff --git a/BrowserStack/BrowserStack Unit Tests/LocalTests.cs b/BrowserStackLocal/BrowserStackLocal Unit Tests/LocalTests.cs similarity index 98% rename from BrowserStack/BrowserStack Unit Tests/LocalTests.cs rename to BrowserStackLocal/BrowserStackLocal Unit Tests/LocalTests.cs index 2a90666..828a76e 100644 --- a/BrowserStack/BrowserStack Unit Tests/LocalTests.cs +++ b/BrowserStackLocal/BrowserStackLocal Unit Tests/LocalTests.cs @@ -177,7 +177,7 @@ public void TestWorksWithCustomOptions() local.start(options); tunnelMock.Verify(mock => mock.addBinaryPath(""), Times.Once); tunnelMock.Verify(mock => mock.addBinaryArguments( - It.IsRegex("-customBoolKey1.*customBoolKey2.*-customKey1.*'customValue1'.*-customKey2.*'customValue2'") + It.IsRegex("-customBoolKey1.*-customBoolKey2.*-customKey1.*customValue1.*-customKey2.*customValue2") ), Times.Once()); tunnelMock.Verify(mock => mock.Run("dummyKey", "", logAbsolute), Times.Once()); local.stop(); diff --git a/BrowserStack/BrowserStack Unit Tests/Properties/AssemblyInfo.cs b/BrowserStackLocal/BrowserStackLocal Unit Tests/Properties/AssemblyInfo.cs similarity index 86% rename from BrowserStack/BrowserStack Unit Tests/Properties/AssemblyInfo.cs rename to BrowserStackLocal/BrowserStackLocal Unit Tests/Properties/AssemblyInfo.cs index 5d161bf..deddef4 100644 --- a/BrowserStack/BrowserStack Unit Tests/Properties/AssemblyInfo.cs +++ b/BrowserStackLocal/BrowserStackLocal Unit Tests/Properties/AssemblyInfo.cs @@ -5,11 +5,11 @@ // General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. -[assembly: AssemblyTitle("BrowserStack Unit Tests")] +[assembly: AssemblyTitle("BrowserStackLocal Unit Tests")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("BrowserStack Unit Tests")] +[assembly: AssemblyProduct("BrowserStackLocal Unit Tests")] [assembly: AssemblyCopyright("Copyright © 2016")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] @@ -32,5 +32,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("0.1.0")] +[assembly: AssemblyFileVersion("0.1.0")] diff --git a/BrowserStack/BrowserStack Unit Tests/packages.config b/BrowserStackLocal/BrowserStackLocal Unit Tests/packages.config similarity index 100% rename from BrowserStack/BrowserStack Unit Tests/packages.config rename to BrowserStackLocal/BrowserStackLocal Unit Tests/packages.config diff --git a/BrowserStack/BrowserStack.sln b/BrowserStackLocal/BrowserStackLocal.sln similarity index 85% rename from BrowserStack/BrowserStack.sln rename to BrowserStackLocal/BrowserStackLocal.sln index 1bedd62..4a8b9b1 100644 --- a/BrowserStack/BrowserStack.sln +++ b/BrowserStackLocal/BrowserStackLocal.sln @@ -1,28 +1,28 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BrowserStack", "BrowserStack\BrowserStack.csproj", "{F58E1C9A-5910-4DA8-B531-9F4A6B0AE8C8}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BrowserStack Unit Tests", "BrowserStack Unit Tests\BrowserStack Unit Tests.csproj", "{FF1ABB6F-4A2C-48F4-B4DB-47DAD566D2F9}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {F58E1C9A-5910-4DA8-B531-9F4A6B0AE8C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F58E1C9A-5910-4DA8-B531-9F4A6B0AE8C8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F58E1C9A-5910-4DA8-B531-9F4A6B0AE8C8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F58E1C9A-5910-4DA8-B531-9F4A6B0AE8C8}.Release|Any CPU.Build.0 = Release|Any CPU - {FF1ABB6F-4A2C-48F4-B4DB-47DAD566D2F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {FF1ABB6F-4A2C-48F4-B4DB-47DAD566D2F9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {FF1ABB6F-4A2C-48F4-B4DB-47DAD566D2F9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FF1ABB6F-4A2C-48F4-B4DB-47DAD566D2F9}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BrowserStackLocal", "BrowserStackLocal\BrowserStackLocal.csproj", "{F58E1C9A-5910-4DA8-B531-9F4A6B0AE8C8}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BrowserStackLocal Unit Tests", "BrowserStackLocal Unit Tests\BrowserStackLocal Unit Tests.csproj", "{FF1ABB6F-4A2C-48F4-B4DB-47DAD566D2F9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F58E1C9A-5910-4DA8-B531-9F4A6B0AE8C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F58E1C9A-5910-4DA8-B531-9F4A6B0AE8C8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F58E1C9A-5910-4DA8-B531-9F4A6B0AE8C8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F58E1C9A-5910-4DA8-B531-9F4A6B0AE8C8}.Release|Any CPU.Build.0 = Release|Any CPU + {FF1ABB6F-4A2C-48F4-B4DB-47DAD566D2F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FF1ABB6F-4A2C-48F4-B4DB-47DAD566D2F9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FF1ABB6F-4A2C-48F4-B4DB-47DAD566D2F9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FF1ABB6F-4A2C-48F4-B4DB-47DAD566D2F9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/BrowserStack/BrowserStack/BrowserStack.csproj b/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj similarity index 88% rename from BrowserStack/BrowserStack/BrowserStack.csproj rename to BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj index d475640..83217af 100644 --- a/BrowserStack/BrowserStack/BrowserStack.csproj +++ b/BrowserStackLocal/BrowserStackLocal/BrowserStackLocal.csproj @@ -1,75 +1,71 @@ - - - - - Debug - AnyCPU - {F58E1C9A-5910-4DA8-B531-9F4A6B0AE8C8} - Library - Properties - BrowserStack - BrowserStack - v4.5 - 512 - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AnyCPU - - - - ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll - True - - - ..\packages\log4net.2.0.5\lib\net45-full\log4net.dll - True - - - ..\packages\NUnit.3.0.1\lib\net45\nunit.framework.dll - True - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + Debug + AnyCPU + {F58E1C9A-5910-4DA8-B531-9F4A6B0AE8C8} + Library + Properties + BrowserStack + BrowserStackLocal + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AnyCPU + + + + ..\packages\log4net.2.0.5\lib\net45-full\log4net.dll + True + + + ..\packages\NUnit.3.0.1\lib\net45\nunit.framework.dll + True + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BrowserStack/BrowserStack/BrowserStackTunnel.cs b/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs similarity index 96% rename from BrowserStack/BrowserStack/BrowserStackTunnel.cs rename to BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs index b7f2440..a957480 100644 --- a/BrowserStack/BrowserStack/BrowserStackTunnel.cs +++ b/BrowserStackLocal/BrowserStackLocal/BrowserStackTunnel.cs @@ -1,297 +1,297 @@ -using System; -using System.IO; -using System.Collections.Generic; -using System.Diagnostics; -using System.Text; -using System.Text.RegularExpressions; -using System.Net; - -using System.Security.AccessControl; -using System.Security.Principal; -using System.Threading; - -namespace BrowserStack -{ - public enum LocalState { Idle, Connecting, Connected, Error, Disconnected }; - - public class BrowserStackTunnel : IDisposable - { - static readonly string binaryName = "BrowserStackLocal.exe"; - static readonly string downloadURL = "https://s3.amazonaws.com/browserStack/browserstack-local/BrowserStackLocal.exe"; - public static readonly string[] basePaths = new string[] { - Path.Combine(Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%"), ".browserstack"), - Directory.GetCurrentDirectory(), - Path.GetTempPath() }; - - int basePathsIndex = -1; - protected string binaryAbsolute = ""; - protected string binaryArguments = ""; - public AutoResetEvent connectingEvent = new AutoResetEvent(false); - - protected StringBuilder output; - public LocalState localState; - protected string logFilePath = ""; - protected FileSystemWatcher logfileWatcher; - - Job job = null; - Process process = null; - - private static Dictionary stateMatchers = new Dictionary() { - { LocalState.Connected, new Regex(@"Press Ctrl-C to exit.*", RegexOptions.Multiline) }, - { LocalState.Error, new Regex(@"\s*\*\*\* Error:\s+(.*).*", RegexOptions.Multiline) } - }; - - public virtual void addBinaryPath(string binaryAbsolute) - { - if (binaryAbsolute == null || binaryAbsolute.Trim().Length == 0) - { - binaryAbsolute = Path.Combine(basePaths[++basePathsIndex], binaryName); - } - this.binaryAbsolute = binaryAbsolute; - } - - public virtual void addBinaryArguments(string binaryArguments) - { - if (binaryArguments == null) - { - binaryArguments = ""; - } - this.binaryArguments = binaryArguments; - } - - public BrowserStackTunnel() - { - localState = LocalState.Idle; - output = new StringBuilder(); - } - - public virtual void fallbackPaths() - { - if (basePathsIndex >= basePaths.Length - 1) - { - throw new Exception("No More Paths to try. Please specify a binary path in options."); - } - basePathsIndex++; - binaryAbsolute = Path.Combine(basePaths[basePathsIndex], binaryName); - } - public void downloadBinary() - { - string binaryDirectory = Path.Combine(this.binaryAbsolute, ".."); - //string binaryAbsolute = Path.Combine(binaryDirectory, binaryName); - - Directory.CreateDirectory(binaryDirectory); - - using (var client = new WebClient()) - { - Local.logger.Info("Downloading BrowserStackLocal.."); - client.DownloadFile(downloadURL, this.binaryAbsolute); - Local.logger.Info("Binary Downloaded."); - } - - if (!File.Exists(binaryAbsolute)) - { - Local.logger.Error("Error accessing downloaded zip. Please check file permissions."); - throw new Exception("Error accessing file " + binaryAbsolute); - } - - DirectoryInfo dInfo = new DirectoryInfo(binaryAbsolute); - DirectorySecurity dSecurity = dInfo.GetAccessControl(); - dSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow)); - dInfo.SetAccessControl(dSecurity); - } - - public virtual void Run(string accessKey, string folder, string logFilePath) - { - string arguments = ""; - if (folder != null && folder.Trim().Length != 0) - { - arguments = "-f " + accessKey + " " + folder + " " + binaryArguments; - } - else - { - arguments = accessKey + " " + binaryArguments; - } - if (!File.Exists(binaryAbsolute)) - { - Local.logger.Warn("BrowserStackLocal binary was not found at " + binaryAbsolute); - downloadBinary(); - } - - if (process != null) - { - process.Close(); - } - - if (File.Exists(logFilePath)) - { - File.WriteAllText(logFilePath, string.Empty); - } - Local.logger.Info("BrowserStackLocal binary is located at " + binaryAbsolute); - Local.logger.Info("Starting Binary with arguments " + arguments.Replace(accessKey, "")); - ProcessStartInfo processStartInfo = new ProcessStartInfo() - { - FileName = binaryAbsolute, - Arguments = arguments, - CreateNoWindow = true, - WindowStyle = ProcessWindowStyle.Hidden, - RedirectStandardOutput = true, - RedirectStandardError = true, - RedirectStandardInput = true, - UseShellExecute = false - }; - - process = new Process(); - process.StartInfo = processStartInfo; - process.EnableRaisingEvents = true; - DataReceivedEventHandler o = new DataReceivedEventHandler((s, e) => - { - if (e.Data != null) - { - output.Append(e.Data); - - foreach (KeyValuePair kv in stateMatchers) - { - Match m = kv.Value.Match(e.Data); - if (m.Success) - { - if (localState != kv.Key) - TunnelStateChanged(localState, kv.Key); - - localState = kv.Key; - output.Clear(); - Local.logger.Info("TunnelState: " + localState.ToString()); - break; - } - } - } - }); - - process.OutputDataReceived += o; - process.ErrorDataReceived += o; - process.Exited += ((s, e) => - { - Kill(); - process = null; - }); - - process.Start(); - - job = new Job(); - job.AddProcess(process.Handle); - - process.BeginOutputReadLine(); - process.BeginErrorReadLine(); - - TunnelStateChanged(LocalState.Idle, LocalState.Connecting); - - AppDomain.CurrentDomain.ProcessExit += new EventHandler((s, e) => Kill()); - - new Thread(() => - { - Thread.CurrentThread.IsBackground = true; - readFile(logFilePath); - }).Start(); - connectingEvent.WaitOne(); - } - - private void readFile(string filename) - { - logFilePath = filename; - if (File.Exists(filename)) - { - readAlreadyPresentFile(filename); - } - else - { - logfileWatcher = new FileSystemWatcher(new FileInfo(filename).Directory.FullName); - logfileWatcher.Created += readAlreadyPresentFile; - logfileWatcher.Changed += readAlreadyPresentFile; - logfileWatcher.EnableRaisingEvents = true; - } - } - - private void readAlreadyPresentFile(object sender, FileSystemEventArgs e) - { - if (e.FullPath.Equals(logFilePath)) - { - readAlreadyPresentFile(e.FullPath); - } - } - - private void readAlreadyPresentFile(string filename) - { - using (FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) - { - byte[] bytes = new byte[1024]; - StringBuilder output = new StringBuilder(); - while (true) - { - fs.Read(bytes, 0, 1024); - output.Append(Encoding.Default.GetString(bytes)); - - foreach (KeyValuePair kv in stateMatchers) - { - Match m = kv.Value.Match(output.ToString()); - if (m.Success) - { - if (localState != kv.Key) - TunnelStateChanged(localState, kv.Key); - - localState = kv.Key; - output.Clear(); - break; - } - } - } - } - } - - private void TunnelStateChanged(LocalState prevState, LocalState state) - { - if (state != LocalState.Connecting) - { - connectingEvent.Set(); - } - } - - public bool IsConnected() - { - return (localState == LocalState.Connected); - } - - public virtual void Kill() - { - try - { - if (process != null) - process.Kill(); - process = null; - if (job != null) - job.Close(); - job = null; - } - catch (Exception e) - { - Local.logger.Error("Error killing: " + e.Message); - } - finally - { - if (localState != LocalState.Disconnected) - TunnelStateChanged(localState, LocalState.Disconnected); - - localState = LocalState.Disconnected; - } - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected virtual void Dispose(bool disposing) - { - Kill(); - } - } -} +using System; +using System.IO; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text; +using System.Text.RegularExpressions; +using System.Net; + +using System.Security.AccessControl; +using System.Security.Principal; +using System.Threading; + +namespace BrowserStack +{ + public enum LocalState { Idle, Connecting, Connected, Error, Disconnected }; + + public class BrowserStackTunnel : IDisposable + { + static readonly string binaryName = "BrowserStackLocal.exe"; + static readonly string downloadURL = "https://s3.amazonaws.com/browserStack/browserstack-local/BrowserStackLocal.exe"; + public static readonly string[] basePaths = new string[] { + Path.Combine(Environment.ExpandEnvironmentVariables("%HOMEDRIVE%%HOMEPATH%"), ".browserstack"), + Directory.GetCurrentDirectory(), + Path.GetTempPath() }; + + int basePathsIndex = -1; + protected string binaryAbsolute = ""; + protected string binaryArguments = ""; + public AutoResetEvent connectingEvent = new AutoResetEvent(false); + + protected StringBuilder output; + public LocalState localState; + protected string logFilePath = ""; + protected FileSystemWatcher logfileWatcher; + + Job job = null; + Process process = null; + + private static Dictionary stateMatchers = new Dictionary() { + { LocalState.Connected, new Regex(@"Press Ctrl-C to exit.*", RegexOptions.Multiline) }, + { LocalState.Error, new Regex(@"\s*\*\*\* Error:\s+(.*).*", RegexOptions.Multiline) } + }; + + public virtual void addBinaryPath(string binaryAbsolute) + { + if (binaryAbsolute == null || binaryAbsolute.Trim().Length == 0) + { + binaryAbsolute = Path.Combine(basePaths[++basePathsIndex], binaryName); + } + this.binaryAbsolute = binaryAbsolute; + } + + public virtual void addBinaryArguments(string binaryArguments) + { + if (binaryArguments == null) + { + binaryArguments = ""; + } + this.binaryArguments = binaryArguments; + } + + public BrowserStackTunnel() + { + localState = LocalState.Idle; + output = new StringBuilder(); + } + + public virtual void fallbackPaths() + { + if (basePathsIndex >= basePaths.Length - 1) + { + throw new Exception("No More Paths to try. Please specify a binary path in options."); + } + basePathsIndex++; + binaryAbsolute = Path.Combine(basePaths[basePathsIndex], binaryName); + } + public void downloadBinary() + { + string binaryDirectory = Path.Combine(this.binaryAbsolute, ".."); + //string binaryAbsolute = Path.Combine(binaryDirectory, binaryName); + + Directory.CreateDirectory(binaryDirectory); + + using (var client = new WebClient()) + { + Local.logger.Info("Downloading BrowserStackLocal.."); + client.DownloadFile(downloadURL, this.binaryAbsolute); + Local.logger.Info("Binary Downloaded."); + } + + if (!File.Exists(binaryAbsolute)) + { + Local.logger.Error("Error accessing downloaded zip. Please check file permissions."); + throw new Exception("Error accessing file " + binaryAbsolute); + } + + DirectoryInfo dInfo = new DirectoryInfo(binaryAbsolute); + DirectorySecurity dSecurity = dInfo.GetAccessControl(); + dSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow)); + dInfo.SetAccessControl(dSecurity); + } + + public virtual void Run(string accessKey, string folder, string logFilePath) + { + string arguments = ""; + if (folder != null && folder.Trim().Length != 0) + { + arguments = "-f " + accessKey + " " + folder + " " + binaryArguments; + } + else + { + arguments = accessKey + " " + binaryArguments; + } + if (!File.Exists(binaryAbsolute)) + { + Local.logger.Warn("BrowserStackLocal binary was not found at " + binaryAbsolute); + downloadBinary(); + } + + if (process != null) + { + process.Close(); + } + + if (File.Exists(logFilePath)) + { + File.WriteAllText(logFilePath, string.Empty); + } + Local.logger.Info("BrowserStackLocal binary is located at " + binaryAbsolute); + Local.logger.Info("Starting Binary with arguments " + arguments.Replace(accessKey, "")); + ProcessStartInfo processStartInfo = new ProcessStartInfo() + { + FileName = binaryAbsolute, + Arguments = arguments, + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden, + RedirectStandardOutput = true, + RedirectStandardError = true, + RedirectStandardInput = true, + UseShellExecute = false + }; + + process = new Process(); + process.StartInfo = processStartInfo; + process.EnableRaisingEvents = true; + DataReceivedEventHandler o = new DataReceivedEventHandler((s, e) => + { + if (e.Data != null) + { + output.Append(e.Data); + + foreach (KeyValuePair kv in stateMatchers) + { + Match m = kv.Value.Match(e.Data); + if (m.Success) + { + if (localState != kv.Key) + TunnelStateChanged(localState, kv.Key); + + localState = kv.Key; + output.Clear(); + Local.logger.Info("TunnelState: " + localState.ToString()); + break; + } + } + } + }); + + process.OutputDataReceived += o; + process.ErrorDataReceived += o; + process.Exited += ((s, e) => + { + Kill(); + process = null; + }); + + process.Start(); + + job = new Job(); + job.AddProcess(process.Handle); + + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + + TunnelStateChanged(LocalState.Idle, LocalState.Connecting); + + AppDomain.CurrentDomain.ProcessExit += new EventHandler((s, e) => Kill()); + + new Thread(() => + { + Thread.CurrentThread.IsBackground = true; + readFile(logFilePath); + }).Start(); + connectingEvent.WaitOne(); + } + + private void readFile(string filename) + { + logFilePath = filename; + if (File.Exists(filename)) + { + readAlreadyPresentFile(filename); + } + else + { + logfileWatcher = new FileSystemWatcher(new FileInfo(filename).Directory.FullName); + logfileWatcher.Created += readAlreadyPresentFile; + logfileWatcher.Changed += readAlreadyPresentFile; + logfileWatcher.EnableRaisingEvents = true; + } + } + + private void readAlreadyPresentFile(object sender, FileSystemEventArgs e) + { + if (e.FullPath.Equals(logFilePath)) + { + readAlreadyPresentFile(e.FullPath); + } + } + + private void readAlreadyPresentFile(string filename) + { + using (FileStream fs = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + byte[] bytes = new byte[1024]; + StringBuilder output = new StringBuilder(); + while (true) + { + fs.Read(bytes, 0, 1024); + output.Append(Encoding.Default.GetString(bytes)); + + foreach (KeyValuePair kv in stateMatchers) + { + Match m = kv.Value.Match(output.ToString()); + if (m.Success) + { + if (localState != kv.Key) + TunnelStateChanged(localState, kv.Key); + + localState = kv.Key; + output.Clear(); + break; + } + } + } + } + } + + private void TunnelStateChanged(LocalState prevState, LocalState state) + { + if (state != LocalState.Connecting) + { + connectingEvent.Set(); + } + } + + public bool IsConnected() + { + return (localState == LocalState.Connected); + } + + public virtual void Kill() + { + try + { + if (process != null) + process.Kill(); + process = null; + if (job != null) + job.Close(); + job = null; + } + catch (Exception e) + { + Local.logger.Error("Error killing: " + e.Message); + } + finally + { + if (localState != LocalState.Disconnected) + TunnelStateChanged(localState, LocalState.Disconnected); + + localState = LocalState.Disconnected; + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + Kill(); + } + } +} diff --git a/BrowserStack/BrowserStack/Job.cs b/BrowserStackLocal/BrowserStackLocal/Job.cs similarity index 96% rename from BrowserStack/BrowserStack/Job.cs rename to BrowserStackLocal/BrowserStackLocal/Job.cs index 5ca0200..123c4c4 100644 --- a/BrowserStack/BrowserStack/Job.cs +++ b/BrowserStackLocal/BrowserStackLocal/Job.cs @@ -1,126 +1,126 @@ -using System; -using System.Runtime.InteropServices; - -namespace BrowserStack -{ - public class Job : IDisposable - { - [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] - static extern IntPtr CreateJobObject(IntPtr a, string lpName); - - [DllImport("kernel32.dll")] - static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength); - - [DllImport("kernel32.dll", SetLastError = true)] - static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process); - - [DllImport("kernel32.dll", SetLastError = true)] - static extern bool CloseHandle(IntPtr hObject); - - private IntPtr handle; - private bool disposed; - - public Job() - { - handle = CreateJobObject(IntPtr.Zero, null); - - var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION - { - LimitFlags = 0x2000 - }; - - var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION - { - BasicLimitInformation = info - }; - - int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); - IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length); - Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); - - if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) - throw new Exception(string.Format("Unable to set information. Error: {0}", Marshal.GetLastWin32Error())); - } - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (disposed) - return; - - if (disposing) { } - - Close(); - disposed = true; - } - - public void Close() - { - CloseHandle(handle); - handle = IntPtr.Zero; - } - - public bool AddProcess(IntPtr processHandle) - { - return AssignProcessToJobObject(handle, processHandle); - } - - } - - #region Helper classes - - [StructLayout(LayoutKind.Sequential)] - struct IO_COUNTERS - { - public UInt64 ReadOperationCount; - public UInt64 WriteOperationCount; - public UInt64 OtherOperationCount; - public UInt64 ReadTransferCount; - public UInt64 WriteTransferCount; - public UInt64 OtherTransferCount; - } - - - [StructLayout(LayoutKind.Sequential)] - struct JOBOBJECT_BASIC_LIMIT_INFORMATION - { - public Int64 PerProcessUserTimeLimit; - public Int64 PerJobUserTimeLimit; - public UInt32 LimitFlags; - public UIntPtr MinimumWorkingSetSize; - public UIntPtr MaximumWorkingSetSize; - public UInt32 ActiveProcessLimit; - public UIntPtr Affinity; - public UInt32 PriorityClass; - public UInt32 SchedulingClass; - } - - [StructLayout(LayoutKind.Sequential)] - struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION - { - public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; - public IO_COUNTERS IoInfo; - public UIntPtr ProcessMemoryLimit; - public UIntPtr JobMemoryLimit; - public UIntPtr PeakProcessMemoryUsed; - public UIntPtr PeakJobMemoryUsed; - } - - public enum JobObjectInfoType - { - AssociateCompletionPortInformation = 7, - BasicLimitInformation = 2, - BasicUIRestrictions = 4, - EndOfJobTimeInformation = 6, - ExtendedLimitInformation = 9, - SecurityLimitInformation = 5, - GroupInformation = 11 - } - - #endregion +using System; +using System.Runtime.InteropServices; + +namespace BrowserStack +{ + public class Job : IDisposable + { + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + static extern IntPtr CreateJobObject(IntPtr a, string lpName); + + [DllImport("kernel32.dll")] + static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, UInt32 cbJobObjectInfoLength); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool CloseHandle(IntPtr hObject); + + private IntPtr handle; + private bool disposed; + + public Job() + { + handle = CreateJobObject(IntPtr.Zero, null); + + var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION + { + LimitFlags = 0x2000 + }; + + var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION + { + BasicLimitInformation = info + }; + + int length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); + IntPtr extendedInfoPtr = Marshal.AllocHGlobal(length); + Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); + + if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, (uint)length)) + throw new Exception(string.Format("Unable to set information. Error: {0}", Marshal.GetLastWin32Error())); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (disposed) + return; + + if (disposing) { } + + Close(); + disposed = true; + } + + public void Close() + { + CloseHandle(handle); + handle = IntPtr.Zero; + } + + public bool AddProcess(IntPtr processHandle) + { + return AssignProcessToJobObject(handle, processHandle); + } + + } + + #region Helper classes + + [StructLayout(LayoutKind.Sequential)] + struct IO_COUNTERS + { + public UInt64 ReadOperationCount; + public UInt64 WriteOperationCount; + public UInt64 OtherOperationCount; + public UInt64 ReadTransferCount; + public UInt64 WriteTransferCount; + public UInt64 OtherTransferCount; + } + + + [StructLayout(LayoutKind.Sequential)] + struct JOBOBJECT_BASIC_LIMIT_INFORMATION + { + public Int64 PerProcessUserTimeLimit; + public Int64 PerJobUserTimeLimit; + public UInt32 LimitFlags; + public UIntPtr MinimumWorkingSetSize; + public UIntPtr MaximumWorkingSetSize; + public UInt32 ActiveProcessLimit; + public UIntPtr Affinity; + public UInt32 PriorityClass; + public UInt32 SchedulingClass; + } + + [StructLayout(LayoutKind.Sequential)] + struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION + { + public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; + public IO_COUNTERS IoInfo; + public UIntPtr ProcessMemoryLimit; + public UIntPtr JobMemoryLimit; + public UIntPtr PeakProcessMemoryUsed; + public UIntPtr PeakJobMemoryUsed; + } + + public enum JobObjectInfoType + { + AssociateCompletionPortInformation = 7, + BasicLimitInformation = 2, + BasicUIRestrictions = 4, + EndOfJobTimeInformation = 6, + ExtendedLimitInformation = 9, + SecurityLimitInformation = 5, + GroupInformation = 11 + } + + #endregion } \ No newline at end of file diff --git a/BrowserStack/BrowserStack/Local.cs b/BrowserStackLocal/BrowserStackLocal/Local.cs similarity index 96% rename from BrowserStack/BrowserStack/Local.cs rename to BrowserStackLocal/BrowserStackLocal/Local.cs index 130221e..276ace8 100644 --- a/BrowserStack/BrowserStack/Local.cs +++ b/BrowserStackLocal/BrowserStackLocal/Local.cs @@ -1,190 +1,190 @@ -using log4net; -using log4net.Appender; -using log4net.Core; -using log4net.Filter; -using log4net.Layout; -using log4net.Repository.Hierarchy; -using System; -using System.Collections.Generic; -using System.IO; -using System.Text.RegularExpressions; - -namespace BrowserStack -{ - public class Local - { - private Hierarchy hierarchy; - private string folder = ""; - private string accessKey = ""; - private string customLogPath = ""; - private string argumentString = ""; - private string customBinaryPath = ""; - private PatternLayout patternLayout; - protected BrowserStackTunnel tunnel = null; - public static ILog logger = LogManager.GetLogger("Local"); - private static KeyValuePair emptyStringPair = new KeyValuePair(); - - private static List> valueCommands = new List>() { - new KeyValuePair("localIdentifier", "-localIdentifier"), - new KeyValuePair("hosts", ""), - new KeyValuePair("proxyHost", "-proxyHost"), - new KeyValuePair("proxyPort", "-proxyPort"), - new KeyValuePair("proxyUser", "-proxyUser"), - new KeyValuePair("proxyPass", "-proxyPass"), - }; - - private static List> booleanCommands = new List>() { - new KeyValuePair("v", "-vvv"), - new KeyValuePair("force", "-force"), - new KeyValuePair("forcelocal", "-forcelocal"), - new KeyValuePair("forceproxy", "-forceproxy"), - new KeyValuePair("onlyAutomate", "-onlyAutomate"), - }; - private readonly string LOG4NET_CONFIG_FILE_PATH = Path.Combine(Directory.GetCurrentDirectory(), "log_config.xml"); - - public bool isRunning() - { - if (tunnel == null) return false; - return tunnel.IsConnected(); - } - - private void addArgs(string key, string value) - { - KeyValuePair result; - key = key.Trim(); - - if (key.Equals("key")) - { - accessKey = value; - } - else if (key.Equals("f")) - { - folder = value; - } - else if (key.Equals("binarypath")) - { - customBinaryPath = value; - } - else if (key.Equals("logfile")) - { - customLogPath = value; - } - else if (key.Equals("verbose")) - { - - } - else - { - result = valueCommands.Find(pair => pair.Key == key); - if (!result.Equals(emptyStringPair)) - { - argumentString += result.Value + " " + value + " "; - return; - } - - result = booleanCommands.Find(pair => pair.Key == key); - if (!result.Equals(emptyStringPair)) - { - if (value.Trim().ToLower() == "true") - { - argumentString += result.Value + " "; - return; - } - } - - if (value.Trim().ToLower() == "true") - { - argumentString += "-" + key + " "; - } - else - { - argumentString += "-" + key + " " + value + " "; - } - } - } - private void setupLogging() - { - hierarchy = (Hierarchy)LogManager.GetRepository(); - - patternLayout = new PatternLayout(); - patternLayout.ConversionPattern = "%date [%thread] %-5level %logger - %message%newline"; - patternLayout.ActivateOptions(); - - ConsoleAppender consoleAppender = new ConsoleAppender(); - consoleAppender.Threshold = Level.Info; - consoleAppender.Layout = patternLayout; - consoleAppender.ActivateOptions(); - - LoggerMatchFilter loggerMatchFilter = new LoggerMatchFilter(); - loggerMatchFilter.LoggerToMatch = "Local"; - loggerMatchFilter.AcceptOnMatch = true; - consoleAppender.AddFilter(loggerMatchFilter); - consoleAppender.AddFilter(new DenyAllFilter()); - - hierarchy.Root.AddAppender(consoleAppender); - - hierarchy.Root.Level = Level.All; - hierarchy.Configured = true; - } - - public Local() - { - setupLogging(); - tunnel = new BrowserStackTunnel(); - } - 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; - tunnel.addBinaryPath(customBinaryPath); - tunnel.addBinaryArguments(argumentString); - while (true) { - bool except = false; - try { - tunnel.Run(accessKey, folder, customLogPath); - } catch (Exception) - { - logger.Warn("Running Local failed. Falling back to backup path."); - except = true; - } - if (except) - { - tunnel.fallbackPaths(); - } else - { - break; - } - } - } - - public void stop() - { - if (tunnel != null) - { - tunnel.Kill(); - } - } - } -} +using log4net; +using log4net.Appender; +using log4net.Core; +using log4net.Filter; +using log4net.Layout; +using log4net.Repository.Hierarchy; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; + +namespace BrowserStack +{ + public class Local + { + private Hierarchy hierarchy; + private string folder = ""; + private string accessKey = ""; + private string customLogPath = ""; + private string argumentString = ""; + private string customBinaryPath = ""; + private PatternLayout patternLayout; + protected BrowserStackTunnel tunnel = null; + public static ILog logger = LogManager.GetLogger("Local"); + private static KeyValuePair emptyStringPair = new KeyValuePair(); + + private static List> valueCommands = new List>() { + new KeyValuePair("localIdentifier", "-localIdentifier"), + new KeyValuePair("hosts", ""), + new KeyValuePair("proxyHost", "-proxyHost"), + new KeyValuePair("proxyPort", "-proxyPort"), + new KeyValuePair("proxyUser", "-proxyUser"), + new KeyValuePair("proxyPass", "-proxyPass"), + }; + + private static List> booleanCommands = new List>() { + new KeyValuePair("v", "-vvv"), + new KeyValuePair("force", "-force"), + new KeyValuePair("forcelocal", "-forcelocal"), + new KeyValuePair("forceproxy", "-forceproxy"), + new KeyValuePair("onlyAutomate", "-onlyAutomate"), + }; + private readonly string LOG4NET_CONFIG_FILE_PATH = Path.Combine(Directory.GetCurrentDirectory(), "log_config.xml"); + + public bool isRunning() + { + if (tunnel == null) return false; + return tunnel.IsConnected(); + } + + private void addArgs(string key, string value) + { + KeyValuePair result; + key = key.Trim(); + + if (key.Equals("key")) + { + accessKey = value; + } + else if (key.Equals("f")) + { + folder = value; + } + else if (key.Equals("binarypath")) + { + customBinaryPath = value; + } + else if (key.Equals("logfile")) + { + customLogPath = value; + } + else if (key.Equals("verbose")) + { + + } + else + { + result = valueCommands.Find(pair => pair.Key == key); + if (!result.Equals(emptyStringPair)) + { + argumentString += result.Value + " " + value + " "; + return; + } + + result = booleanCommands.Find(pair => pair.Key == key); + if (!result.Equals(emptyStringPair)) + { + if (value.Trim().ToLower() == "true") + { + argumentString += result.Value + " "; + return; + } + } + + if (value.Trim().ToLower() == "true") + { + argumentString += "-" + key + " "; + } + else + { + argumentString += "-" + key + " " + value + " "; + } + } + } + private void setupLogging() + { + hierarchy = (Hierarchy)LogManager.GetRepository(); + + patternLayout = new PatternLayout(); + patternLayout.ConversionPattern = "%date [%thread] %-5level %logger - %message%newline"; + patternLayout.ActivateOptions(); + + ConsoleAppender consoleAppender = new ConsoleAppender(); + consoleAppender.Threshold = Level.Info; + consoleAppender.Layout = patternLayout; + consoleAppender.ActivateOptions(); + + LoggerMatchFilter loggerMatchFilter = new LoggerMatchFilter(); + loggerMatchFilter.LoggerToMatch = "Local"; + loggerMatchFilter.AcceptOnMatch = true; + consoleAppender.AddFilter(loggerMatchFilter); + consoleAppender.AddFilter(new DenyAllFilter()); + + hierarchy.Root.AddAppender(consoleAppender); + + hierarchy.Root.Level = Level.All; + hierarchy.Configured = true; + } + + public Local() + { + setupLogging(); + tunnel = new BrowserStackTunnel(); + } + 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; + tunnel.addBinaryPath(customBinaryPath); + tunnel.addBinaryArguments(argumentString); + while (true) { + bool except = false; + try { + tunnel.Run(accessKey, folder, customLogPath); + } catch (Exception) + { + logger.Warn("Running Local failed. Falling back to backup path."); + except = true; + } + if (except) + { + tunnel.fallbackPaths(); + } else + { + break; + } + } + } + + public void stop() + { + if (tunnel != null) + { + tunnel.Kill(); + } + } + } +} diff --git a/BrowserStack/BrowserStack/Properties/AssemblyInfo.cs b/BrowserStackLocal/BrowserStackLocal/Properties/AssemblyInfo.cs similarity index 79% rename from BrowserStack/BrowserStack/Properties/AssemblyInfo.cs rename to BrowserStackLocal/BrowserStackLocal/Properties/AssemblyInfo.cs index 561509f..0b95849 100644 --- a/BrowserStack/BrowserStack/Properties/AssemblyInfo.cs +++ b/BrowserStackLocal/BrowserStackLocal/Properties/AssemblyInfo.cs @@ -1,36 +1,36 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("BrowserStack")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("BrowserStack")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("f58e1c9a-5910-4da8-b531-9f4a6b0ae8c8")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("BrowserStackLocal")] +[assembly: AssemblyDescription("C# Bindings for BrowserStack Local")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("BrowserStack")] +[assembly: AssemblyProduct("BrowserStackLocal")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("f58e1c9a-5910-4da8-b531-9f4a6b0ae8c8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("0.1.0.0")] +[assembly: AssemblyFileVersion("0.1.0.0")] diff --git a/BrowserStack/BrowserStack/packages.config b/BrowserStackLocal/BrowserStackLocal/packages.config similarity index 59% rename from BrowserStack/BrowserStack/packages.config rename to BrowserStackLocal/BrowserStackLocal/packages.config index 411fa8c..011d0c6 100644 --- a/BrowserStack/BrowserStack/packages.config +++ b/BrowserStackLocal/BrowserStackLocal/packages.config @@ -1,5 +1,4 @@  - - \ No newline at end of file + diff --git a/BrowserStackExample/BrowserStackExample.sln b/BrowserStackLocalExample/BrowserStackExample.sln similarity index 97% rename from BrowserStackExample/BrowserStackExample.sln rename to BrowserStackLocalExample/BrowserStackExample.sln index a20b5bf..bc373c8 100644 --- a/BrowserStackExample/BrowserStackExample.sln +++ b/BrowserStackLocalExample/BrowserStackExample.sln @@ -1,22 +1,22 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BrowserStackExample", "BrowserStackExample\BrowserStackExample.csproj", "{9297DCCC-AE88-4E12-934A-B2BEA4864B49}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9297DCCC-AE88-4E12-934A-B2BEA4864B49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9297DCCC-AE88-4E12-934A-B2BEA4864B49}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9297DCCC-AE88-4E12-934A-B2BEA4864B49}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9297DCCC-AE88-4E12-934A-B2BEA4864B49}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BrowserStackExample", "BrowserStackExample\BrowserStackExample.csproj", "{9297DCCC-AE88-4E12-934A-B2BEA4864B49}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9297DCCC-AE88-4E12-934A-B2BEA4864B49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9297DCCC-AE88-4E12-934A-B2BEA4864B49}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9297DCCC-AE88-4E12-934A-B2BEA4864B49}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9297DCCC-AE88-4E12-934A-B2BEA4864B49}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/BrowserStackExample/BrowserStackExample/BrowserStackExample.csproj b/BrowserStackLocalExample/BrowserStackExample/BrowserStackExample.csproj similarity index 97% rename from BrowserStackExample/BrowserStackExample/BrowserStackExample.csproj rename to BrowserStackLocalExample/BrowserStackExample/BrowserStackExample.csproj index 6c1c4a2..7748f1b 100644 --- a/BrowserStackExample/BrowserStackExample/BrowserStackExample.csproj +++ b/BrowserStackLocalExample/BrowserStackExample/BrowserStackExample.csproj @@ -1,94 +1,94 @@ - - - - - Debug - AnyCPU - {9297DCCC-AE88-4E12-934A-B2BEA4864B49} - Exe - Properties - BrowserStackExample - BrowserStackExample - v4.5 - 512 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - ..\..\BrowserStack\BrowserStack\bin\Debug\BrowserStack.dll - - - - - - - - - - - - ..\packages\Selenium.WebDriver.2.52.0\lib\net40\WebDriver.dll - True - - - - - - - - - - - - False - Microsoft .NET Framework 4.5 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 - false - - - - + + + + + Debug + AnyCPU + {9297DCCC-AE88-4E12-934A-B2BEA4864B49} + Exe + Properties + BrowserStackExample + BrowserStackExample + v4.5 + 512 + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\BrowserStack\BrowserStack\bin\Debug\BrowserStack.dll + + + + + + + + + + + + ..\packages\Selenium.WebDriver.2.52.0\lib\net40\WebDriver.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/BrowserStackExample/BrowserStackExample/Example.cs b/BrowserStackLocalExample/BrowserStackExample/Example.cs similarity index 97% rename from BrowserStackExample/BrowserStackExample/Example.cs rename to BrowserStackLocalExample/BrowserStackExample/Example.cs index f3cf910..89bd745 100644 --- a/BrowserStackExample/BrowserStackExample/Example.cs +++ b/BrowserStackLocalExample/BrowserStackExample/Example.cs @@ -1,53 +1,53 @@ -using System; -using BrowserStack; -using System.Collections.Generic; -using OpenQA.Selenium; -using OpenQA.Selenium.Remote; - -namespace BrowserStackExample -{ - class Example - { - static void Main(string[] args) - { - Local local = new Local(); - - List> options = 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"), - }; - local.start(options); - - // Run WebDriver Tests - IWebDriver driver; - DesiredCapabilities capability = DesiredCapabilities.Firefox(); - 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"); - - driver = new RemoteWebDriver( - new Uri("http://hub.browserstack.com/wd/hub/"), capability - ); - driver.Navigate().GoToUrl("http://www.google.com"); - Console.WriteLine(driver.Title); - - IWebElement query = driver.FindElement(By.Name("q")); - query.SendKeys("Browserstack"); - query.Submit(); - Console.WriteLine(driver.Title); - - driver.Quit(); - local.stop(); - Console.WriteLine("Test Completed."); - Console.ReadLine(); - } - } -} +using System; +using BrowserStack; +using System.Collections.Generic; +using OpenQA.Selenium; +using OpenQA.Selenium.Remote; + +namespace BrowserStackExample +{ + class Example + { + static void Main(string[] args) + { + Local local = new Local(); + + List> options = 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"), + }; + local.start(options); + + // Run WebDriver Tests + IWebDriver driver; + DesiredCapabilities capability = DesiredCapabilities.Firefox(); + 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"); + + driver = new RemoteWebDriver( + new Uri("http://hub.browserstack.com/wd/hub/"), capability + ); + driver.Navigate().GoToUrl("http://www.google.com"); + Console.WriteLine(driver.Title); + + IWebElement query = driver.FindElement(By.Name("q")); + query.SendKeys("Browserstack"); + query.Submit(); + Console.WriteLine(driver.Title); + + driver.Quit(); + local.stop(); + Console.WriteLine("Test Completed."); + Console.ReadLine(); + } + } +} diff --git a/BrowserStackExample/BrowserStackExample/Properties/AssemblyInfo.cs b/BrowserStackLocalExample/BrowserStackExample/Properties/AssemblyInfo.cs similarity index 97% rename from BrowserStackExample/BrowserStackExample/Properties/AssemblyInfo.cs rename to BrowserStackLocalExample/BrowserStackExample/Properties/AssemblyInfo.cs index 39be242..b4a8a7c 100644 --- a/BrowserStackExample/BrowserStackExample/Properties/AssemblyInfo.cs +++ b/BrowserStackLocalExample/BrowserStackExample/Properties/AssemblyInfo.cs @@ -1,36 +1,36 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("ConsoleApplication1")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("ConsoleApplication1")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("9297dccc-ae88-4e12-934a-b2bea4864b49")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ConsoleApplication1")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ConsoleApplication1")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("9297dccc-ae88-4e12-934a-b2bea4864b49")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/BrowserStackExample/BrowserStackExample/packages.config b/BrowserStackLocalExample/BrowserStackExample/packages.config similarity index 100% rename from BrowserStackExample/BrowserStackExample/packages.config rename to BrowserStackLocalExample/BrowserStackExample/packages.config diff --git a/MIT-LICENSE.txt b/MIT-LICENSE.txt new file mode 100644 index 0000000..e070d10 --- /dev/null +++ b/MIT-LICENSE.txt @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2016 BrowserStack + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/README.md b/README.md index ffa1094..d1e7f82 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/browserstack/browserstack-local-csharp.svg?branch=master)](https://travis-ci.org/browserstack/browserstack-local-csharp) -A simple C-sharp wrapper for BrowserStack Local Binary. +C# bindings for BrowserStack Local. ## Setup @@ -111,6 +111,10 @@ bsLocalArgs.Add(new KeyValuePair("logfile", "/browserstack/logs. To run the test suite run the nunit tests from Visual Studio. +### Packaging + +To pack using nuget, run `nuget pack BrowserStackLocal\BrowserStackLocal\BrowserStackLocal.csproj -Prop Configuration=Release` + ### Reporting bugs You can submit bug reports either in the Github issue tracker.