Due to integration restrictions, I'm forced to register people through a headless browser because the platform doesn't have an API.
I'm able to get this done on my symfony through selenium and PHP Unit. The callenge is that selenium has to be running all through which I don't believe is ideal.
This is my command:
xvfb-run --server-args="-screen 0, 1366x768x24" selenium-standalone start
I was hoping using Symfony process class, I could run the command as in below:
public function fillFormAndSubmit($inputs,$url,$form)
{
$process = new Process('/usr/bin/xvfb-run --server-args="-screen 0, 1366x768x24" selenium-standalone start');
//$process = new Process('echo Tecmint is a community of Linux Nerds > /tmp/xvfb-run.log 2> /tmp/xvfb.err');
$process->run();
usleep(3000000);
// executes after the command finishes
if (!$process->isSuccessful()) {
throw new ProcessFailedException($process);
}
$this->webDriver->get($url);
$body = $this->webDriver->findElement(\WebDriverBy::cssSelector('body'))->sendKeys(array(\WebDriverKeys::CONTROL, 't'));
$form = $this->webDriver->findElement(\WebDriverBy::className($form));
foreach ($inputs as $input) {
if($input['type'] == 'select')
{
//PHPUnit_Extensions_Selenium2TestCase_Element_Select::fromElement($input['id'])->selectOptionByValue($input['value']);
//PHPUnit_Extensions_Selenium2TestCase_Element_Select::fromElement($this->byId('selectMenu'))->selectOptionByValue('t3');
//$this->select($this->byId($input['id']))->selectOptionByValue($input['value']);
$select = new \WebDriverSelect($form->findElement(\WebDriverBy::id($input['id'])));
$select->selectByValue($input['value']);
}
elseif($input['type'] == 'checkbox')
{
$form->findElement(\WebDriverBy::id($input['id']))->click();
}
else {
//echo $input['id'];
$form->findElement(\WebDriverBy::id($input['id']))->sendKeys($input['value']);
}
}
$form->submit();
echo shell_exec('pkill -f selenium-standalone');
//$this->waitForUserInput();
}
However, the shell command doesn't fire when I try to run the service on-demand. Is there a better way of doing this? If not, anyone with an idea of how to get it to work?
Related
I am trying to build an angular project from a Laravel project.
When I run an exec command from Laravel I got env: node: No such file or directory
Steps to reproduce :
create Laravel project: laravel new laravel-bug
create angular project: ng new angular-bug
In the Laravel file routes/web.php, in the / route, add:
use Symfony\Component\Process\Process;
$process = new Process('cd /path/to/angular-bug && ng build');
$process->run(function ($type, $buffer) {
if (Process::ERR === $type) {
echo 'ERR > '.$buffer;
} else {
echo 'OUT > '.$buffer;
}
});
This will output the result, which for me is env: node: No such file or directory
Any ideas ?
I've had this issue before when node wasn't in the path of the web server user. The second argument to the Process::run() method is an array of environment variables. Use it to set a path.
<?php
use Symfony\Component\Process\Process;
$env = ["PATH" => "/sbin;/bin:/usr/sbin:/usr/bin:/path/to/node/if/its/different"];
$process = new Process('cd /path/to/angular-bug && ng build');
$process->run(function ($type, $buffer) {
if (Process::ERR === $type) {
echo 'ERR > '.$buffer;
} else {
echo 'OUT > '.$buffer;
}
}, $env);
The problem is that somewhere in this build process something is just calling node and expecting it will be in the path. (I think I experienced it when running npm.) This is not a great thing to do, and the software should be aware of where it’s located due to a compile-time setting or information from the package management system, or it should attempt to locate it.
I installed gearman extension and gearman command line tool also. I tried to reverse a string using gearman from simple php file.
Example:
$gmclient= new GearmanClient();
$gmclient->addServer();
$result = $gmclient->doNormal("reverse", "Test the reverse string");
echo "Success: $result\n";
output:
Success: gnirts esrever eht tseT
In the same way i tried to run exec('ls -l') , I am able to execute using simple php files from cakephp application from webroot directory. filepath: cakephp/app/webroot/worker.php, cakephp/app/webroot/client.php.
worker.php
<?php
$worker= new GearmanWorker();
$worker->addServer();
$worker->addFunction("exec", "executeScript");
while ($worker->work());
function executeScript($job)
{
$param = $job->workload();
$t = exec($param);
return $t;
}
?>
client.php
<?php
$client= new GearmanClient();
$client->addServer();
$cmd = 'ls -l';
print $client->do("exec", $cmd);
?>
How to implement the same type of execution using View, Controller from cakephp?
Workflow: Post data from View to Controller using ajax method and execute "exec() from gearman" , send output back to View as response of ajax POST methhod.
Why are you using exec?! That brings a huge security risk. Use DirectoryIterator instead.
Your client code should be part of the controller.
<?php
class UploadController extends AppController
{
public function directoryList()
{
$directory = '';
// Get data
if (!empty($this->data['directory']) && is_string($this->data['directory']))
{
$directory = $this->data['directory'];
}
$client= new GearmanClient();
$client->addServer("localhost",4730); // Important!!!
$result = $client->do("fileList", serialize($data));
return $result;
}
}
Then from view use requestAction.
$uploads = $this->requestAction(
array('controller' => 'upload', 'action' => 'directoryList'),
array('return')
);
Worker could look like this:
<?php
$worker= new GearmanWorker();
$worker->addServer("localhost",4730); // Important!!!
$worker->addFunction("fileList", "getFileList");
while ($worker->work());
// From Art of Web
// http://www.the-art-of-web.com/php/directory-list-spl/
function getFileList($dir)
{
// array to hold return value
$retval = array();
$dir = $job->workload();
// add trailing slash if missing
if(substr($dir, -1) != "/") $dir .= "/";
// open directory for reading
$d = new DirectoryIterator($dir) or die("getFileList: Failed opening directory $dir for reading");
foreach($d as $fileinfo) {
// skip hidden files
if($fileinfo->isDot()) continue;
$retval[] = array(
'name' => "{$dir}{$fileinfo}",
'type' => ($fileinfo->getType() == "dir") ?
"dir" : mime_content_type($fileinfo->getRealPath()),
'size' => $fileinfo->getSize(),
'lastmod' => $fileinfo->getMTime()
);
}
return $retval;
}
This is pseudo code. Do not use it in production!!! See Gearman documentation for more advance worker setup.
To actually take advantage of load distribution Gearman server should not be on localhost of course.
Your worker.php needs to be already running on a server for this to work. For testing, open up a new terminal window to the server where you want worker.php to run. Start the worker: php worker.php on the command line. (On a production server, you might want to look at supervisor to run your worker without a terminal.)
The code in client.php would go in your controller, but save the result to a variable instead of a print statement.
The fact that this would be from an AJAX call is irrelevant, it will work the same as a normal web page. When the controller executes, the gearman client code will get a response from the worker, and you can output the result to the view.
Symfony2 enables developers to create their own command-line commands. They can be executed from command line, but also from the controller. According to official Symfony2 documentation, it can be done like that:
protected function execute(InputInterface $input, OutputInterface $output)
{
$command = $this->getApplication()->find('demo:greet');
$arguments = array(
...
);
$input = new ArrayInput($arguments);
$returnCode = $command->run($input, $output);
}
But in this situation we wait for the command to finish it's execution and return the return code.
How can I, from controller, execute command forking it to background without waiting for it to finish execution?
In other words what would be equivalent of
$ nohup php app/console demo:greet &
From the documentation is better use start() instead run() if you want to create a background process. The process_max_time could kill your process if you create it with run()
"Instead of using run() to execute a process, you can start() it: run() is blocking and waits for the process to finish, start() creates a background process."
According to the documentation I don't think there is such an option: http://api.symfony.com/2.1/Symfony/Component/Console/Application.html
But regarding what you are trying to achieve, I think you should use the process component instead:
use Symfony\Component\Process\Process;
$process = new Process('ls -lsa');
$process->run(function ($type, $buffer) {
if ('err' === $type) {
echo 'ERR > '.$buffer;
} else {
echo 'OUT > '.$buffer;
}
});
And as mentioned in the documentation "if you want to be able to get some feedback in real-time, just pass an anonymous function to the run() method".
http://symfony.com/doc/master/components/process.html
my idea is to start a minecraft server with the Symfony2 Process Class and want to give feedback to me in real time. So, like described in the Process cookbook part, I try the following code:
$process = new Process('sudo java -jar -Xms512M -Xmx1G ../server/minecraft_server.jar');
$process->setTimeout(null);
$process->run(function ($type, $buffer) {
if ('err' === $type) {
echo 'ERR > '.$buffer;
} else {
echo 'OUT > '.$buffer;
}
});
Because of some permission issues with the apache2 user i modified the sudoers file with this: www-data ALL = (myspecialUser) NOPASSWD: /usr/bin/java
so the www-data user can run the java command.
The server is starting in the background, but my problem is now that I'm not getting any real-time output. Only if I shutdown (or kill) the minecraft server process I get the output.
Any suggestions how to get a real-time output?
Instead of calling the run() method, you should try with the start() one:
$process = new Process('sudo java -jar -Xms512M -Xmx1G ../server/minecraft_server.jar');
$process->setTimeout(null);
$process->start(function ($type, $buffer));
echo 'OUT >' . $process->getOutput();
http://api.symfony.com/master/Symfony/Component/Process/Process.html#method_start
http://api.symfony.com/master/Symfony/Component/Process/Process.html#method_getOutput
I am trying to use Behat for BDD testing. When running a build on Jenkins, I would like Behat to open PHP's build in web server and then close it after running the tests. How to do that?
Basically I need to run:
php -S localhost:8000
In my BDD tests I tried:
/**
* #Given /^I call "([^"]*)" with email and password$/
*/
public function iCallWithPostData($uri)
{
echo exec('php -S localhost:8000');
$client = new Guzzle\Service\Client();
$request = $client->post('http://localhost:8000' . $uri, array(), '{"email":"a","password":"a"}')->send();
$this->response = $request->getBody(true);
}
But then when running Behat it gets stuck without any message.
Just start the server as a part of your build process. Create an ant tasks which would start the server before behat is run and would kill it once behat is finished.
I've been successfully using this approach to start and stop the selenium server.
Solved this myself. I have create two methods. I call the first one before running my BDD tests and the second one after I ran the tests:
private function _startDevelopmentServer($pidfile)
{
$cmd = 'cd ../../public && php -S 127.0.0.1:8027 index.php';
$outputfile = '/dev/null';
shell_exec(sprintf("%s > %s 2>&1 & echo $! >> %s", $cmd, $outputfile, $pidfile));
sleep(1);
}
private function _killDevelopmentServer($pidfile)
{
if (file_exists($pidfile)) {
$pids = file($pidfile);
foreach ($pids as $pid) {
shell_exec('kill -9 ' . $pid);
}
unlink($pidfile);
}
}