Subversion dumps

Saturday, July 18. 2009
Comments

This week, we just had it. The current provider we pay to host our subversion repositories is just unbearable, and so we decided to move (on) to [Unfuddle][3]. Our reason to move to Unfuddle is that they offer everything we need (and more, e.g. Git), at a pretty good price. I also heard Unfuddle a 100 times when I shopped for a recommendation.

And on top of all the features, they also kick butt at support and for example offered to import our repositories right away. But, has anyone of you tried to dump a subversion repository, ever?

Creating a dump

Being a good user, I rtfm'd first. The manual states to use svnadmin dump. And apparently it's that easy?

Not really.

First off, the manual tells me to: svnadmin /path/to/repo. That didn't work at all though. Instead I had to svnadmin dump /path/to/repo/.svn. But that didn't work regardless.

After rtfm, there's stfw, and I did that too when I encountered the following issues:

server# svnadmin ./path/to/repo/.svn
svnadmin: Expected repository format '3' or '5'; found format '8'

... then I updated my local subversion client, checked out a new copy of the repository, and got this:

server# svnadmin ./path/to/repo/.svn
svnadmin: Can't open file './path/to/repo/.svn/format', no such file or directory

There really is no format file when I check out the same repository with Subversion 1.6.3.

Ahhhh!!!111 Madness!

Apparently a more recent version of Subversion cannot deal older repositories?

Updated, 2009-07-23: Apparently it helps to be awake while doing this. The solution to the problem above is rather simple. svnadmin does not work on a checkout, but only on the real repository. So in case you are hosting with an external provider such as Unfuddle, Hosted Projects, CVSDude, Assembla and so on, you won't be able to svnadmin dump on a working copy.


Continue reading "Subversion dumps"

Nginx+PHP+FastCGI: Testing your web application with bleeding edge PHP

Sunday, July 5. 2009
Comments

So, every once in a while I find myself in need of trying out newer, maybe, not-yet-released features in PHP. For example, recently, I wanted to test RoundCube PHP6 — this is how I did it.

On a side note, the same setup would also work for testing code with previous versions of PHP.

Toolbox

I used nginx and the PHP source with a little bit of ./configure and make — for kicks!

My O.S. of choice is FreeBSD and therefor the installation steps covered are tailored to it. With a small amount of Linux/Unix-fu, anyone should make it work on another distribution regardless.

Install nginx

First off, install nginx. On FreeBSD, this should be all:

  • cd /usr/ports/www/nginx-devel && make install distclean

On other systems, this maybe a:

  • apt-get install nginx
  • emerg nginx
  • rpm -shoot-myself nginx

The next step includes the infamous spawn-fcgi which many people use to control the php-cgi processes. A lot of tutorials on the net suggest to install lighttpd because it's a part of it, but on FreeBSD, you may skip that and do the following instead:

  • cd /usr/ports/www/spawn-cgi && make install distclean

Pretty cool, huh?

So once this is done, the usual tasks need to be completed — in no particular order:

  • edit the nginx config and enable fastcgi in nginx (/usr/local/etc/nginx/nginx.conf)
  • enable nginx itself in /etc/rc.conf (nginx_enable="YES")
  • get another nifty start script (see Shell Script) to wrap spawn-cgi

... and done!


Continue reading "Nginx+PHP+FastCGI: Testing your web application with bleeding edge PHP"

Avoiding common pitfalls with Zend_Test

Saturday, March 28. 2009
Comments

Sometimes I think I'm particularly stupid when it comes to learning new things. Well, that, or maybe I'm just the only one complaining enough. ;-)

I feel like I've wasted a great deal of time last week with basics that were nowhere to be found or required debugging to no end. The following is the outcome, a rather random list of things to watch out for when you're starting on Zend_Test.

A general understanding of testing and PHPUnit is more than helpful.

How do you debug?

Did your test not redirect, or did your query assertions go wrong?

Generally, there are two ways:

<?php
// (...)
function testIfTheSunCameUp()
{
    var_dump($this->response, $this->request);
}

Not so pretty, right?

In general I don't understand why it will say, "failed asserting status code 404", and will not tell you what it got instead. It offers you a backtrace so you can go into the class and add var_dump(), but that's hardly useful.

One of the things I love about PHPT is that a failed test case is so descriptive. There's really no debugging a failed test because the process of debugging generally involves gathering information where PHPT hands it over to you right away. But maybe that's a PHPUnit thing.

And of course:

phpunit --verbose AllTests.php

My grudge here is that I'm a total PHPUnit newbie. Before Zend_Test I avoided PHPUnit where I could because I felt that it is a beast — one that's especially hard to tame.

Update: Someone else noticed too, please vote on ZF-6013.

Control your environment

We offer a REST-API to partners and that API is basically MVC and lots of context switching depending on GET, POST, PUT, HEAD, DELETE and a couple parameters. I like to think of it as true REST. ;-)

Since the unit tests are run on the cli, not even GET is set. So make sure to add this to your test:

<?php
// (...)
$this->request->setMethod('GET');

Keep in mind that $_SERVER is not set and if you really happen to rely on anything from that ($this->getServer()), you need to explicitly set it or figure out another smart way to deal with it. In my case, I'm overriding some of these $_SERVER variables in my bootstrap with a config setting when I'm using the "testing" environment.

Update: I've opend ZF-6162, please vote.

The basic AllTests.php

AllTests.php is used to tell phpunit what to do, a simple setup would look like this:

tests/AllTests.php

tests/controllers/AllTests.php

tests/controllers/IndexControllerTest.php

tests/controllers/AllTests.php:

<?php
require_once dirname(__FILE__) . '/IndexControllerTest.php';

class ControllersAllTests
{
    public static function main()
    {
        PHPUnit_TextUI_TestRunner::run(self::suite());
    }

    public static function suite()
    {
        $suite = new PHPUnit_Framework_TestSuite('Controllers');
        $suite->addSuiteCase('IndexControllerTestCase');
        return $suite;
    }
}

tests/AllTests.php:

<?php
(...)
class AllTests
{
    public static function suite()
    {
        $suite = new PHPUnit_Framework_TestSuite('AllTests');
        $suite->addSuite(ControllersAllTests::suite());
        return $suite;
    }
}

Zend_Session_Namespace

Avoid locking session namespaces, they will stab you in the eye. See ZF-6072.

Zend_Dom_Query

I'd suggest you remove all @-operators from Zend_Dom_Query since it doesn't really tell you what is wrong with the response otherwise. I've opened ZF-6142 so this gets fixed.

Slightly related to Zend_Dom_Query is a bug I noticed when you're response is empty. It's a rather trivial issue where null is not the same as an empty string. I've opened ZF-6143 and included a patch.

Bootstrapping the correct way

The most simple way to bootstrap is to create a small class to initialize your application. The class takes an environment parameter to __construct() which allows you to load a different config section or other nifty stuff. I called mine Lagged_App() and the code came originally from Andries Seuten's example ZF application but it evolved over the past years.

I wouldn't recommend his tutorial today (because things changed since 2007), but at the time it was pretty easy and straight forward. Today's bar is the quickstart section in the official manual. But since the quickstart suggests includes, I spent some time cleaning up my by going through said quickstart guide and I posted a quick and dirty example (which I labeled Lagged_Application)) in my subversion repository on Google Code.

A test case is a test case

I'm using the following "base" test case for all my controller tests:

<?php
class Lagged_PHPUnit_ControllerTestCase
    extends Zend_Test_PHPUnit_ControllerTestCase
{
    public function setUp()
    {
        Zend_Session::$_unitTestEnabled = true;

        $bootstrap       = new Bootstrap('testing');
        $this->bootstrap = array($bootstrap, 'start');
        parent::setUp();
    }
}

Clean up

One of the most fundamental things your mother tried to teach you.

This is in most of my tearDown()'s:

public function tearDown()
{
    $this->resetRequest()->resetResponse();
    $this->setQuery(array());
    $this->setPost(array());
}

Avoid direct PHP calls

I'd avoid the following:

  1. Skipping views with echo in the controller (bad, bad, bad ;-)).
  2. Use the Zend_Action_Helper redirector instead of header().
  3. Use Zend_Session etc. vs. session_*() (Don't forget Zend_Session::$_unitTestEnabled = true;).
  4. Don't dispatch always. ;-)
Defined tags for this entry: , , , , ,