Load Behat CommonContexts from Symfony2

To load common contexts for behat on a symfony2 project we basically add to deps and also to autoload as follows:

// to deps
[BehatCommonContexts]
    git=https://github.com/Behat/CommonContexts.git
    target=/behat/CommonContexts
// to autoload.php
'Behat\CommonContext'       => __DIR__.'/../vendor/behat/CommonContexts',

Then do a `bin/vendors install` and then run your behat scenarios!

Updating Behat

I was working on redirect steps and found a command set to upgrade my behat environment.
You can check first what you currently have:

pear list -c behat

And then compare to the following:

sudo pear channel-discover pear.behat.org
pear remote-list -c behat
sudo pear channel-update pear.behat.org
sudo pear upgrade behat/behat
sudo pear upgrade behat/gherkin
sudo pear upgrade behat/mink

Sharing so you don’t have to look or spend time on this and keep to the current bleeding edge.

Capifony + Symfony2 Revisited Experience

Deploying with capifony is really an experience. Even though I had set it up after several months successfully and with the help of @weaverryan I struggled another few hours to get it work for my project.

I needed java installed for assetic and yui-compressor too so I downloaded from, you can select first option jdk and download the compressed binary for your system either 64 or 32:
JDK binary.
This is really just downloading the file and setting up PATH for the system to find the java/bin/java executable. Same applies to yuicompressor which can be downloaded from here.

Another thing I had to deal with was the permissions, basically I ended up setting umask(0000) before all my app*.php and app/console. Besides this I created a script ./script.sh that will remove rm -rf cache/* and logs/* since they are impediment to more capifony deploys after the first if they are to be shared folders. I had shared vendors, logs, cache and the parameters.ini.

In addition to this even though I had installed capifony the easy way, I ended up doing it again over git and that too gave me the opportunity to remove the –reinstall out of the bin/vendors install task which repeated every `cap deploy`. I compiled it with this new change and use it to my like, with faster deployments than ever!

Other things I have learned with capifony is that one can issue all symfony2 commands and custom commands by just typing cap symfony and then wait for the prompt so that one can enter any fos:user:create or any such sort of sf2 command that we can think of. This was very useful to warmup on demand, or to create users and promote them so that one could access client admin dashboard on prod server.

Yet another by-product of this resulted in trial and error kind of easy of the configuration to send emails with swiftmailer. It was a long jorney but I got it to send email via smtp.

Should you want to get straight A’s from the very beginning here is my code you can use to avoid hours of long setup:

set :application, "cordoval"
set :maindomain,  "sites.pe"
set :domain,      "#{application}.#{maindomain}"
set :deploy_to,   "/home/cordoval/www/#{domain}"
 
set :scm,        :git
set :scm_command, "/usr/bin/git"
set :scm_verbose, true
set :repository,  "#{maindomain}:/home/cordoval/repos/#{application}.git"
 
set :branch, "new-feature"
set :user, "cordoval"
set :password, 'jaris'
 
set :shared_files, ["app/config/parameters.ini"]
set :shared_children, [app_path + "/logs", web_path + "/uploads", app_path + "/cache", "vendor"]
set :update_vendors, true
set :dump_assetic_assets, true
 
role :web,        domain                         # Your HTTP server, Apache/etc
role :app,        domain                         # This may be the same as your `Web` server
role :db,         domain, :primary => true       # This is where Rails migrations will run

set :use_sudo,   false
set  :keep_releases,  3
ssh_options[:forward_agent] = true

Let the reader understand the code above.

Understanding Sismo Processes Part I

Update: By the comments from @stof I made exit($return_var) and system(…,$return_var) takes a second argument as shown. So it works now like it should have been. Thanks!

What am I trying to do? Yes I am trying to understand this process method with which sismo personal ci runs my behat tests. The issue here is because I am running a script and not a simple command the process seems to end simply in a green result whereas I could still have some steps failing while on behat but sismo would not want to color my commit with red.

So that said we give credits for the code below to SensioLabs. How then are we going to change this method to allow for our examination of behat results? passing or failing?

The problem:

  /**
   * Runs the process.
   *
   * The callback receives the type of output (out or err) and
   * some bytes from the output in real-time. It allows to have feedback
   * from the independent process during execution.
   *
   * The STDOUT and STDERR are also available after the process is finished
   * via the getOutput() and getErrorOutput() methods.
   *
   * @param Closure|string|array $callback A PHP callback to run whenever there is some
   *                                       output available on STDOUT or STDERR
   *
   * @return integer The exit status code
   *
   * @throws \RuntimeException When process can't be launch or is stopped
   *
   * @api
   */

So right from here we see there could be potential hooks from where we can insert our telling the system when it is an error or when it is a passing test/description/etc.

    public function run($callback = null)
    {
        $this->stdout = '';
        $this->stderr = '';
        $that = $this;
        $callback = function ($type, $data) use ($that, $callback)
        {
            if ('out' == $type) {
                $that->addOutput($data);
            } else {
                $that->addErrorOutput($data);
            }
 
            if (null !== $callback) {
                call_user_func($callback, $type, $data);
            }
        };
 
        $descriptors = array(array('pipe', 'r'), array('pipe', 'w'), array('pipe', 'w'));
 
        $process = proc_open($this->commandline, $descriptors, $pipes, $this->cwd, $this->env, $this->options);
 
        if (!is_resource($process)) {
            throw new \RuntimeException('Unable to launch a new process.');
        }
 
        foreach ($pipes as $pipe) {
            stream_set_blocking($pipe, false);
        }
 
        if (null === $this->stdin) {
            fclose($pipes[0]);
            $writePipes = null;
        } else {
            $writePipes = array($pipes[0]);
            $stdinLen = strlen($this->stdin);
            $stdinOffset = 0;
        }
        unset($pipes[0]);
 
        while ($pipes || $writePipes) {
            $r = $pipes;
            $w = $writePipes;
            $e = null;
 
            $n = @stream_select($r, $w, $e, $this->timeout);
 
            if (false === $n) {
                break;
            } elseif ($n === 0) {
                proc_terminate($process);
 
                throw new \RuntimeException('The process timed out.');
            }
 
            if ($w) {
                $written = fwrite($writePipes[0], (binary) substr($this->stdin, $stdinOffset), 8192);
                if (false !== $written) {
                    $stdinOffset += $written;
                }
                if ($stdinOffset >= $stdinLen) {
                    fclose($writePipes[0]);
                    $writePipes = null;
                }
            }
 
            foreach ($r as $pipe) {
                $type = array_search($pipe, $pipes);
                $data = fread($pipe, 8192);
                if (strlen($data) > 0) {
                    call_user_func($callback, $type == 1 ? 'out' : 'err', $data);
                }
                if (false === $data || feof($pipe)) {
                    fclose($pipe);
                    unset($pipes[$type]);
                }
            }
        }
 
        $this->status = proc_get_status($process);
 
        $time = 0;
        while (1 == $this->status['running'] && $time < 1000000) {
            $time += 1000;
            usleep(1000);
            $this->status = proc_get_status($process);
        }
 
        $exitcode = proc_close($process);
 
        if ($this->status['signaled']) {
            throw new \RuntimeException(sprintf('The process stopped because of a "%s" signal.', $this->status['stopsig']));
        }
 
        return $this->exitcode = $this->status['running'] ? $exitcode : $this->status['exitcode'];
    }

Zombie Pitfalls: Part III

I have been following this thread here and got some responses and experiences that I would like to share.

First there was a post from @nationalfieldtravis. Basically what he is proposing is to just run a zombie instance from outside the process which usually it is autostarted and run it manually. This is the sort of thing done with sahi that one has to run it before running the tests/features.

Second @FireFoxIXI posted a gist which I forked just to save a copy for myself here. The solution proposed is to just modify the driver connection code and do more retries through a parameter.

These two workaround don’t work perfectly and i still get the error when doing some ajax.

throw new Error("No OPTION '" + value + "'");

So I am still awaiting to find some time to first reproduce this error and then work together with behat team on a PR. This post is mainly to document and dont’ loose track of this effort with using zombie for speeding sahi feature running.