diff --git a/.travis.yml b/.travis.yml index 559c799..b56bdce 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,9 @@ language: php +php: + - '5.5' + before_install: - true && `base64 --decode <<< ZXhwb3J0IEJST1dTRVJTVEFDS19BQ0NFU1NfS0VZPUh5VmZydXJvb3dYb041eGhLZEs2Cg==` + - true && composer install diff --git a/README.md b/README.md index cc76816..f307c97 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # browserstack-local-php +[![Build Status](https://travis-ci.org/browserstack/browserstack-local-php.svg?branch=master)](https://travis-ci.org/browserstack/browserstack-local-php) + ## Setup Installation is possible using [Composer](https://getcomposer.org/). @@ -52,6 +54,6 @@ Test the installation by running a simple test file, check out example.php in th Testing is possible using [PHPUnit](https://phpunit.de/). To run the tests, run the command: - `phpunit tests/LocalTest.php` + `phpunit` diff --git a/example.php b/example.php index 8d6225f..1d77952 100644 --- a/example.php +++ b/example.php @@ -10,8 +10,12 @@ $me = new Local(); $me->isRunning(); +echo "starting"; $args = array("v" => 1); $me->start($args); +echo "started"; echo $me->isRunning(); +echo "stopping"; $me->stop(); +echo "stopped"; echo $me->isRunning(); diff --git a/lib/Local.php b/lib/Local.php index 5c262e7..399729e 100644 --- a/lib/Local.php +++ b/lib/Local.php @@ -13,6 +13,7 @@ class Local { private $handle = NULL; private $pipes = array(); private $loghandle = NULL; + public $pid = NULL; public function __construct() { $this->key = getenv("BROWSERSTACK_ACCESS_KEY"); @@ -27,7 +28,7 @@ public function isRunning() { return False; $status = proc_get_status($this->handle); - return $status["running"]; + return is_null($status["running"]) ? false : $status["running"]; } public function add_args($arg_key, $value = NULL) { @@ -73,24 +74,29 @@ public function start($arguments) { $this->binary_path = $this->binary->binary_path(); $descriptorspec = array( - 0 => array("pipe", "r"), // stdin is a pipe that the child will read from - 1 => array("pipe", "w"), // stdout is a pipe that the child will write to - 2 => array("file", "/tmp/error-output.txt", "a") // stderr is a file to write to + 0 => array("pipe", "r"), + 1 => array("pipe", "w"), + 2 => array("pipe", "w") ); $call = $this->command(); system('echo "" > '. $this->logfile); $this->handle = proc_open($call, $descriptorspec, $this->pipes); + $status = proc_get_status($this->handle); + $this->pid = $status['pid']; + $this->loghandle = fopen($this->logfile,"r"); while (true) { $buffer = fread($this->loghandle, 1024); if (preg_match("/Error:[^\n]+/i", $buffer, $match)) { + $this->stop(); throw new LocalException($match[0]); - proc_terminate($this->handle); break; } - elseif (preg_match("/\bPress Ctrl-C to exit\b/i", $buffer, $match)) + elseif (preg_match("/\bPress Ctrl-C to exit\b/i", $buffer, $match)){ + fclose($this->loghandle); break; + } //flush(); sleep(1); @@ -101,12 +107,28 @@ public function stop() { fclose($this->loghandle); if (is_null($this->handle)) return; - else + else { + while(fgets($this->pipes[0])); + fclose($this->pipes[0]); + fclose($this->pipes[1]); + fclose($this->pipes[2]); + + if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') + exec('kill -15 ' . $this->pid); + proc_terminate($this->handle); + while($this->isRunning()) + sleep(1); + } } public function command() { - $command = "$this->binary_path -logFile $this->logfile $this->folder_flag $this->key $this->folder_path $this->force_local_flag $this->local_identifier_flag $this->only_flag $this->only_automate_flag $this->proxy_host $this->proxy_port $this->proxy_user $this->proxy_pass $this->force_flag $this->verbose_flag $this->hosts"; + $exec = "exec"; + // TODO to test on windows + if(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') + $exec = "call"; + + $command = "$exec $this->binary_path -logFile $this->logfile $this->folder_flag $this->key $this->folder_path $this->force_local_flag $this->local_identifier_flag $this->only_flag $this->only_automate_flag $this->proxy_host $this->proxy_port $this->proxy_user $this->proxy_pass $this->force_flag $this->verbose_flag $this->hosts"; $command = preg_replace('/\s+/S', " ", $command); return $command; } diff --git a/lib/LocalBinary.php b/lib/LocalBinary.php index 591c34b..8f780e4 100644 --- a/lib/LocalBinary.php +++ b/lib/LocalBinary.php @@ -50,14 +50,14 @@ private function server_home() { private function platform_url(){ if (PHP_OS == "Darwin") - return "https://s3.amazonaws.com/browserStack/browserstack-local/BrowserStackLocal-darwin-x64"; + return 'https://s3.amazonaws.com/bs-automate-prod/local/BrowserStackLocal-darwin-x64'; else if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') - return "https://s3.amazonaws.com/browserStack/browserstack-local/BrowserStackLocal.exe"; + return 'https://s3.amazonaws.com/bs-automate-prod/local/BrowserStackLocal-win32.exe'; if ((strtoupper(PHP_OS)) == "LINUX") { if (PHP_INT_SIZE * 8 == 64) - return "https://s3.amazonaws.com/browserStack/browserstack-local/BrowserStackLocal-linux-x64"; + return 'https://s3.amazonaws.com/bs-automate-prod/local/BrowserStackLocal-linux-x64'; else - return "https://s3.amazonaws.com/browserStack/browserstack-local/BrowserStackLocal-linux-ia32"; + return 'https://s3.amazonaws.com/bs-automate-prod/local/BrowserStackLocal-linux-ia32'; } } @@ -65,8 +65,18 @@ public function download_binary($path) { $url = $this->platform_url(); if (!file_exists($path)) mkdir($path, 0777, true); + + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + $data = curl_exec ($ch); + curl_close ($ch); + + $file = fopen($path . '/BrowserStackLocal', "w+"); + fputs($file, $data); + fclose($file); - file_put_contents($path . '/BrowserStackLocal', fopen($url, 'r')); + chmod($path . '/BrowserStackLocal', 0755); return $path . "/BrowserStackLocal"; } @@ -74,8 +84,7 @@ private function get_available_dirs() { $arrlength = count($this->possible_binary_paths); for($x = 0; $x < $arrlength; $x++) { $path = $this->possible_binary_paths[$x]; - $localpath = $path . "/BrowserStackLocal"; - if(file_exists($localpath) || $this->make_path($path)) + if(file_exists($path) || $this->make_path($path)) return $path; } throw new LocalException("Error trying to download BrowserStack Local binary"); diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..c5544cc --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,8 @@ + + + + tests + + + + diff --git a/tests/LocalTest.php b/tests/LocalTest.php index 00c484f..f5b9a04 100644 --- a/tests/LocalTest.php +++ b/tests/LocalTest.php @@ -1,5 +1,4 @@ bs_local = new Local(); } + public function tearDown(){ + $this->bs_local->stop(); + } + public function test_verbose() { $this->bs_local->add_args('v'); $this->assertContains('-v',$this->bs_local->command()); @@ -65,30 +68,32 @@ public function test_hosts() { $this->assertContains('localhost,8080,0',$this->bs_local->command()); } + public function test_isRunning() { + $this->assertFalse($this->bs_local->isRunning()); + $this->bs_local->start(array('v' => true)); + $this->assertTrue($this->bs_local->isRunning()); + $this->bs_local->stop(); + $this->assertFalse($this->bs_local->isRunning()); + $this->bs_local->start(array('v' => true)); + $this->assertTrue($this->bs_local->isRunning()); + } + + public function test_checkPid() { + $this->assertFalse($this->bs_local->isRunning()); + $this->bs_local->start(array('v' => true)); + $this->assertTrue($this->bs_local->pid > 0); + } + public function test_multiple_binary() { $this->bs_local->start(array('v' => true)); $bs_local_2 = new Local(); try { $bs_local_2->start(array('v' => true)); + $this->fail("Expected Exception has not been raised."); } catch (LocalException $ex) { $emessage = $ex->getMessage(); $this->assertEquals(trim($emessage), 'Error: Either another browserstack local client is running on your machine or some server is listening on port 45691'); - $bs_local_2->stop(); - $this->bs_local->stop(); - sleep(2); return; } - $this->fail("Expected Exception has not been raised."); - $this->bs_local->stop(); - sleep(2); - } - - public function test_isRunning() { - $this->assertFalse($this->bs_local->isRunning()); - $this->bs_local->start(array('v' => true)); - $this->assertTrue($this->bs_local->isRunning()); - $this->bs_local->stop(); - sleep(2); - $this->assertFalse($this->bs_local->isRunning()); } }