<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Dave Gardner - PHP Developer &#187; Dev Environment</title>
	<atom:link href="http://www.davegardner.me.uk/blog/category/dev-environment/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.davegardner.me.uk/blog</link>
	<description>Just behind the bleeding edge of PHP.</description>
	<lastBuildDate>Wed, 27 Jul 2011 15:14:29 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Effective load testing with Apache JMeter</title>
		<link>http://www.davegardner.me.uk/blog/2010/09/23/effective-load-testing-with-apache-jmeter/</link>
		<comments>http://www.davegardner.me.uk/blog/2010/09/23/effective-load-testing-with-apache-jmeter/#comments</comments>
		<pubDate>Thu, 23 Sep 2010 13:57:16 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Dev Environment]]></category>
		<category><![CDATA[jmeter]]></category>
		<category><![CDATA[load testing]]></category>
		<category><![CDATA[stress testing]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://www.davegardner.me.uk/blog/?p=112</guid>
		<description><![CDATA[Load testing is surely one of the most important activities that many developers ignore. I would include myself in that bracket; it is far too often something that gets bounced out of a busy schedule. However load testing, and its cousin stress testing, are absolutely essential when attempting to create a <em>reliable</em> application.
This blog post concentrates on load testing and gives an introduction to Apache JMeter (one of many load testing tools).]]></description>
			<content:encoded><![CDATA[<p>Load testing is surely one of the most important activities that many developers ignore. I would include myself in that bracket; it is far too often something that gets bounced out of a busy schedule. However load testing, and its cousin stress testing, are absolutely essential when attempting to create a <em>reliable</em> application.</p>
<p>This blog post concentrates on <a href="http://en.wikipedia.org/wiki/Load_testing" target="_blank">load testing</a>, which Wikipedia defines as:</p>
<blockquote><p>Load testing is the process of putting demand on a system or device and measuring its response.”</p></blockquote>
<p>This is subtly different to <a href="http://en.wikipedia.org/wiki/Stress_testing" target="_blank">stress testing</a>, which aims to test a system &#8220;beyond normal operational capacity, often to a breaking point&#8221;. Load testing is useful to ensure that your application meets the business requirements, for example &#8220;cope with x million page unique users per day with a response time of less than 1 second&#8221;.</p>
<p>This post covers:</p>
<ul>
<li><a href="#things-to-consider">Things to consider when load testing</a></li>
<li><a href="#using-apache-jmeter">Using Apache JMeter</a></li>
<li><a href="#verifying-the-details-of-a-response">Verifying the details of a response</a></li>
<li><a href="#extracting-data-from-a-response">Extracting data from a response</a></li>
<li><a href="#constant-throughput-timer">Defining load levels using a constant throughput timer</a></li>
</ul>
<h3><a name="things-to-consider">Things to consider when load testing</a></h3>
<p>It&#8217;s very easy to carry out useless load testing. I know this from experience. We were testing a system designed to serve 30 API requests per second, each response containing data on a user from a pool of roughly 100,000,000. When we carried out our load testing we designed a test using a pool of 1,000 unique user IDs. Spot the obvious problem! Testing with only 1,000 unique user IDs meant that we quickly reached a point where various layers of caching would be happily dealing with the job of fetching this limited set of data. This includes MySQL&#8217;s key cache plus the operating system file system cache.</p>
<p>To avoid making the same mistakes, make sure you consider the following points when load testing.</p>
<ol>
<li><strong>Use indicative hardware</strong><br />When load testing to ensure that an application reaches minimum performance standards, you will need to test on hardware that mirrors your &#8220;live&#8221; setup as closely as possible. Sometimes this is easy, for example if you are running a live system consisting of three servers. If however you are running a 30 server cluster including a 100TB database, getting an accurate staging system can be hard work.</li>
<li><strong>Use indicative data</strong><br />If you have a production system with 100,000,000 rows of data, it&#8217;s a good idea not to carry out load testing on a staging system with only 300 rows. Similarly, if your application stores rows that are roughly 100KB each, the load testing system should be designed to replicate these conditions. The closer you can get to your <em>actual</em> data, the more useful the results.</li>
<li><strong>Think about system state</strong><br />Layers of caching can make load testing hard work. This includes application caching such as Memcache plus operating system caching and database caching. If your live environment workload can expect warmed caches then it is valid to leave these things warmed! However running a load test over and over again may get your application into an unnatural state of &#8220;preparedness&#8221;.</li>
</ol>
<h3><a name="using-apache-jmeter">Using Apache JMeter</a></h3>
<p>It may be tempting to write your own load test tools. Why not indeed? A few CURLs, a few processes; simple. My advice would be this: before you do this, try out JMeter. <a href="http://jakarta.apache.org/site/downloads/downloads_jmeter.cgi">You can download JMeter from this page.</a></p>
<p>This example job reads in a list of user UUIDs from a <strong>text file</strong> and then makes an HTTP request for each user.</p>
<h4>1. Launch JMeter</h4>
<pre class="code">sh bin/jmeter.sh &amp;</pre>
<h4>2. Configure job</h4>
<ul>
<li>Right click on <strong>Test Plan</strong> heading, click <strong>Add</strong> &gt; <strong>Thread Group</strong></li>
<li>Right click on <strong>Thread Group</strong>, click <strong>Add</strong> &gt; <strong>CSV Data Set Config</strong></li>
<li>Click on the newly added config element and enter a valid <strong>Filename</strong> &#8211; this should contain one user UUID per line</li>
<li>Enter <strong>userId</strong> under <strong>Variable Names (comma-delimited)</strong></li>
<li>Click on the <strong>Thread Group</strong>, configure the <strong>Number of Threads</strong> (say 5), the <strong>Ramp-Up Period</strong> (say 180) and then the test <strong>Duration</strong> (say 600). This tells JMeter to launch up to 5 threads, ramping these up over 2 minutes, with the test running for a total of 10 minutes.</li>
</ul>
<p style="text-align: center;"><a href="http://www.davegardner.me.uk/blog/wp-content/uploads/2010/09/Screen-shot-2010-09-23-at-14.36.52.png"></a><a href="http://www.davegardner.me.uk/blog/wp-content/uploads/2010/09/Screen-shot-2010-09-23-at-14.36.52.png"><img class="size-full wp-image-117 aligncenter" title="Thread group settings" src="http://www.davegardner.me.uk/blog/wp-content/uploads/2010/09/Screen-shot-2010-09-23-at-14.36.52.png" alt="Thread group settings" width="554" height="311" /></a></p>
<ul>
<li>Right click on <strong>Thread Group</strong>, click <strong>Add</strong> &gt; <strong>Sampler</strong> &gt; <strong>HTTP Request</strong></li>
<li>Click on the newly added sampler element and enter a valid <strong>Server Name or IP</strong></li>
<li>You should probably add in some <strong>Timeouts</strong>; depending on your desired performance under load</li>
<li>Enter a <strong>Path</strong>, including the previously defined variable as follows: /1/user/${userId}/data.json</li>
</ul>
<p style="text-align: center;"><a href="http://www.davegardner.me.uk/blog/wp-content/uploads/2010/09/Screen-shot-2010-09-23-at-14.41.36.png"><img class="aligncenter size-full wp-image-121" title="HTTP request settings" src="http://www.davegardner.me.uk/blog/wp-content/uploads/2010/09/Screen-shot-2010-09-23-at-14.41.36.png" alt="Screen shot 2010-09-23 at 14.41.36" width="582" height="386" /></a></p>
<h4>3. Add a listener</h4>
<p>This was a stage that took me a while to figure out! You <em>must</em> have at least one listener, otherwise you cannot view any results from the job. You can add listeners to the <strong>Thread Group</strong> in the same way you added samplers and config elements. The <strong>Summary Report</strong> is very useful, as is <strong>View Results Tree</strong> (especially during debugging).</p>
<h4>4. Run the job!</h4>
<p>It&#8217;s usually a good idea to <strong>Clear All</strong> (from the Run menu) before you fire off the job.</p>
<h4>5. Profit</h4>
<p style="text-align: center;"><a href="http://www.davegardner.me.uk/blog/wp-content/uploads/2010/09/Screen-shot-2010-09-23-at-14.44.37.png"><img class="aligncenter size-full wp-image-125" title="Epic Fail!" src="http://www.davegardner.me.uk/blog/wp-content/uploads/2010/09/Screen-shot-2010-09-23-at-14.44.37.png" alt="Epic Fail!" width="565" height="336" /></a></p>
<h3><a name="verifying-the-details-of-a-response">Verifying the details of a response</a></h3>
<p>By default JMeter will work with HTTP response codes &#8211; which is handy. So 404 errors and 500 errors etc… will all be dealt with. It&#8217;s often useful to look at the actual <em>content</em> of the response to decide on success. This can help catch things like PHP Fatal Errors (where you may have a 200 OK response, but a completely blank document). This is where the <strong>Response Assertion</strong> comes in.</p>
<p>Right click on any <em>sampler</em> and then <strong>Add</strong> &gt; <strong>Assertion</strong> &gt; <strong>Response Assertion</strong>. You can then define patterns to test against; these can use regular expressions. One other point to note is that if you wish to have HTTP 500 or 400 errors ignored (treated as success) then you should tick the <strong>Ignore Status</strong> tick box.</p>
<h3><a name="extracting-data-from-a-response">Extracting data from a response</a></h3>
<p>Hitting URLs with known UUIDs is a handy tool, however it&#8217;s also useful to call a URL to add a user, extract the newly added user UUID and then use this in any subsequent requests. Fortunately this is also very easy to achieve with JMeter, using the <strong>Regular Expression Extractor</strong>.</p>
<p>Right click on any <em>sampler</em> and then <strong>Add</strong> &gt; <strong>Post Processors</strong> &gt; <strong>Regular Expression Extractor</strong>. The following settings extract data from a JSONP response which includes a userId definition; this is then assigned to the JMeter variable <em>userId</em>.</p>
<ul>
<li>Reference Name: userId</li>
<li>Regular Expression: var userId = &#8216;([a-f0-9-]+)&#8217;;</li>
<li>Template: $1$</li>
<li>Match No. (0 for Random): 1</li>
<li>Default Value: null</li>
</ul>
<p style="text-align: center;"><a href="http://www.davegardner.me.uk/blog/wp-content/uploads/2010/09/Screen-shot-2010-09-23-at-14.47.32.png"><img class="aligncenter size-full wp-image-130" title="Configuring variable extraction" src="http://www.davegardner.me.uk/blog/wp-content/uploads/2010/09/Screen-shot-2010-09-23-at-14.47.32.png" alt="Configuring variable extraction" width="587" height="382" /></a></p>
<h3><a name="constant-throughput-timer">Defining load levels using a constant throughput timer</a></h3>
<p>When load testing I find it useful to run a number of tests at different levels of load &#8211; for a very specifically defined number of requests per second. To achieve this level of control, the <strong>Constant Throughput Timer</strong> element is very handy. This timer allows you to specific a <em>target throughput</em> in samples per minute. JMeter will then throttle back requests, if needed, to attempt to achieve this rate. The only thing you may need to do is ensure you have enough threads allowed to meet the desired throughput. Remember that the number of threads can be defined within the <strong>Thread Group</strong> settings.</p>
<p style="text-align: center;"><a href="http://www.davegardner.me.uk/blog/wp-content/uploads/2010/09/Screen-shot-2010-09-23-at-14.50.18.png"><img class="aligncenter size-full wp-image-135" title="Timer settings" src="http://www.davegardner.me.uk/blog/wp-content/uploads/2010/09/Screen-shot-2010-09-23-at-14.50.18.png" alt="Timer settings" width="600" height="397" /></a></p>
<p>Enjoy your load testing!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.davegardner.me.uk/blog/2010/09/23/effective-load-testing-with-apache-jmeter/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Setting up continuous integration for PHP using Hudson and Phing</title>
		<link>http://www.davegardner.me.uk/blog/2009/11/09/continuous-integration-for-php-using-hudson-and-phing/</link>
		<comments>http://www.davegardner.me.uk/blog/2009/11/09/continuous-integration-for-php-using-hudson-and-phing/#comments</comments>
		<pubDate>Mon, 09 Nov 2009 13:44:44 +0000</pubDate>
		<dc:creator>Dave</dc:creator>
				<category><![CDATA[Dev Environment]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[ci]]></category>
		<category><![CDATA[continuous integration]]></category>
		<category><![CDATA[hudson]]></category>
		<category><![CDATA[phing]]></category>
		<category><![CDATA[unit test]]></category>

		<guid isPermaLink="false">http://www.davegardner.me.uk/blog/?p=5</guid>
		<description><![CDATA[In this, my first post, I'm going to write about the benefits of Unit Testing and how Continuous Integration (CI) can be used to get the best out of Unit Testing. This will include details of how I setup a CI system using Hudson CI server, Phing build tool combined with various other analysis tools (including PHP Unit).]]></description>
			<content:encoded><![CDATA[<p>In this, my first post, I&#8217;m going to write about the benefits of <strong>Unit Testing</strong> and how <strong>Continuous Integration</strong> (CI) can be used to get the best out of Unit Testing. This will include details of <a href="#php-ci-setup">how I setup a CI system</a> using <strong>Hudson</strong> CI server, <strong>Phing</strong> build tool combined with various other analysis tools (including <strong>PHP Unit</strong>).</p>
<p>One of the best explanations of Unit Testing I&#8217;ve read was <a href="http://stackoverflow.com/questions/67299/is-unit-testing-worth-the-effort/69263#69263" target="_blank">posted by benzado on Stack Overflow.</a></p>
<blockquote><p>Unit testing is a lot like going to the gym. You know it is good for you, all the arguments make sense, so you start working out. There&#8217;s an initial rush, which is great, but after a few days you start to wonder if it is worth the trouble.</p></blockquote>
<p>The difficulty with Unit Testing is <strong>keeping it up</strong>. It is very easy to slip into poor habits and before you know it there&#8217;s a huge chunk of code with no tests. Possibly a huge, badly designed chunk of code, that didn&#8217;t benefit from having tests written before it was coded. Before you know what&#8217;s going on, you end up with a project that you really <em>can&#8217;t</em> write tests for, because retrofitting the tests is near impossible.</p>
<p>For me, there are two critical reasons for Unit Testing:</p>
<ol>
<li><strong>Enforcing good design</strong><br />
To be able to write tests, you need to be able to zero in on a “unit” of code, isolating it from all the rest of your 1,000,000 lines of web application. Writing Unit Tests forces you to design systems that have loose coupling because otherwise it is impossible to test.</li>
<li><strong>Allowing changes to be made in confidence</strong><br />
Without Unit Tests, you get to the point where no one really wants to make any changes to the code. This is especially true in a commercial environment, where many people have worked on the code, including some key team member who has since left. Unit Tests allow you to make changes to one part of the code and be <em>pretty convinced</em> you haven&#8217;t messed up something else.</li>
</ol>
<h2>Continuous integration</h2>
<p>Martin Fowler <a href="http://martinfowler.com/articles/continuousIntegration.html" target="_blank">describes the process of Continuation Integration</a> in detail. He suggests:</p>
<blockquote><p>Continuous Integration is a software development practice where members of a team integrate their work frequently, usually each person integrates at least daily &#8211; leading to multiple integrations per day. Each integration is verified by an automated build (including test) to detect integration errors as quickly as possible. Many teams find that this approach leads to significantly reduced integration problems and allows a team to develop cohesive software more rapidly. This article is a quick overview of Continuous Integration summarizing the technique and its current usage.</p></blockquote>
<p>The key idea behind CI is to do what is most painful often, namely “building” everyone&#8217;s code from source and making sure it all works.</p>
<p>A CI system usually consists of the following key elements:</p>
<div id="attachment_10" class="wp-caption alignnone" style="width: 310px"><img class="size-medium wp-image-10" title="Continuous integration" src="http://www.davegardner.me.uk/blog/wp-content/uploads/2009/11/ci-300x247.jpg" alt="Continuous integration" width="300" height="247" /><p class="wp-caption-text">Continuous integration</p></div>
<ul>
<li>Developers commit code</li>
<li>CI server detects changes</li>
<li>CI server checksout code, runs tests, analyses code</li>
<li>CI server feeds back to development team</li>
</ul>
<p>If you want to find out more about CI, I recommend the excellent book <a href="#">Continuous Integration: Improving Software Quality and Reducing Risk</a>. There is an excerpt published on <a href="http://www.javaworld.com/javaworld/jw-06-2007/jw-06-awci.html" target="_blank">JavaWorld</a> which covers a lot of the key advantages. In particular, it highlights:</p>
<blockquote><p>1. Reduce risks<br />
2. Reduce repetitive manual processes<br />
3. Generate deployable software at any time and at any place<br />
4. Enable better project visibility<br />
5. Establish greater confidence in the software product from the development team</p></blockquote>
<p>CI gets the most out of Unit Tests by <strong>forcing them to be run after every change</strong>. Not only that, but with a good CI setup, developers instantly know if they haven&#8217;t written enough tests. If avoids the situtation where Joe Bloggs has added in a huge chunk of code with zero tests.</p>
<h2 id="php-ci-setup">Setting up CI for a PHP project</h2>
<p>To get my environment setup, I consulted the following blog posts which are worth a read:</p>
<ol>
<li><a href="http://blog.jepamedia.org/2009/10/28/continuous-integration-for-php-with-hudson/" target="_blank">http://blog.jepamedia.org/2009/10/28/continuous-integration-for-php-with-hudson/</a></li>
<li><a href="http://toptopic.wordpress.com/2009/02/26/php-and-hudson/" target="_blank">http://toptopic.wordpress.com/2009/02/26/php-and-hudson/</a></li>
</ol>
<p>I&#8217;m assuming you&#8217;re using a CentOS 5 server (or I guess RHEL5). If not, you may still find various parts of this useful.</p>
<h3>1. Install JDK</h3>
<p>EPEL provide a set of CentOS packages, including a package for openJDK. This is the easiest way of installing Java.</p>
<p>Firstly, setup <a href="http://fedoraproject.org/wiki/EPEL/FAQ#howtouse" target="_blank">EPEL</a>:</p>
<pre class="code">wget -O /etc/yum.repos.d/hudson.repo http://hudson-ci.org/redhat/hudson.repo</pre>
<p>Next install <a href="http://openjdk.java.net/install/" target="_blank">OpenJDK</a>:</p>
<pre class="code">yum install java-1.6.0-openjdk</pre>
<h3>2. Install Hudson</h3>
<p>Download and install the CentOS RPM for <a href="http://hudson-ci.org/redhat/" target="_blank">Hudson</a>:</p>
<pre class="code">wget -O /etc/yum.repos.d/hudson.repo http://hudson-ci.org/redhat/hudson.repo
rpm --import http://hudson-ci.org/redhat/hudson-ci.org.key
yum install hudson</pre>
<p>Now Hudson is installed, we can start using the standard CentOS “service” command.</p>
<pre class="code">service hudson start</pre>
<p>We can check Hudson is working by pointing the browser at port 8080 (the default Hudson port). Hudson will work “out of the box”  and give you a web interface immediately. This is the primary reason I decided to go with Hudson over the other possibilities, eg: CruiseControl and phpUnderControl. Although I didn&#8217;t do an exhaustive analysis before I decided on Hudson, it just <em>seemed</em> right to me.</p>
<p>To get the graphing engine working for Hudson, you may need to install x.</p>
<pre class="code">yum groupinstall base-x</pre>
<h3>3. Install phing</h3>
<p><a href="http://phing.info/trac/" target="_blank">Phing</a> is a PHP project build system or build tool based on Apache Ant. A build tool ensures that the process of creating your working web application from source code happens in a structured and repeatable way. This helps reduce the possibility of errors caused by simply uploading files via FTP or some other simple method.</p>
<p>Make sure PEAR is installed for PHP (this is the easiest way of installing phing):</p>
<pre class="code">yum install php-pear</pre>
<p>Then install the PEAR phing package:</p>
<pre class="code">pear channel-discover pear.phing.info
pear install phing/phing</pre>
<h3>4. Setup SVN</h3>
<p>If you haven&#8217;t got a <a href="http://subversion.tigris.org/" target="_blank">Subversion</a> repository, you&#8217;re going to need one (or some other SCM tool like CVS, GIT or Mercurial).</p>
<pre class="code">yum install mod_dav_svn</pre>
<p>The simplest setup involves creating a repo in /var/www/svn/&lt;my repo&gt;</p>
<pre class="code">mkdir -v /var/www/svn/test
svnadmin create --fs-type fsfs /var/www/svn/test
chown –R apache:apache /var/www/svn/test</pre>
<p>Setup Apache by pretty much uncommenting the lines in /etc/httpd/conf.d/subversion.conf. Once Apache restarted, you&#8217;ll be able to get to it via /repos/test, assuming you&#8217;re using the default settings (sets up SVN on /repos). I haven&#8217;t gone into the details of getting SVN up and running; there are lots of resources out there that will help you do this.</p>
<h3>5. Install PHP tools</h3>
<h5><a href="http://www.phpdoc.org/" target="_blank">PHPDocumentor</a> – to generate documentation automatically from code</h5>
<pre class="code">pear install PhpDocumentor</pre>
<h5><a href="http://github.com/sebastianbergmann/phpcpd" target="_blank">PHP CPD</a> – “copy and paste detector” for PHP</h5>
<p>This requires PHP 5.2. At time of writing, this wasn&#8217;t standard with CentOS 5, but is part of the CentOS “test” repo. This can be setup by creating a yum repo file, eg: /etc/yum.repos.d/centos-test.repo and populating with:</p>
<pre class="code">[c5-testing]
name=CentOS-5 Testing
baseurl=http://dev.centos.org/centos/5/testing/$basearch/
enabled=1
gpgcheck=1
gpgkey=http://dev.centos.org/centos/RPM-GPG-KEY-CentOS-testing</pre>
<p>Then you can do:</p>
<pre class="code">yum update php</pre>
<p>You may also need to upgrade pear; if the install of phpcpd fails (below). To do this, try:</p>
<pre class="code">pear upgrade pear</pre>
<p>or, if this wants to be forced, and you think it&#8217;s a good idea (I did):</p>
<pre class="code">pear upgrade --force pear</pre>
<p>Finally we can install phpcpd!</p>
<pre class="code">pear channel-discover pear.phpunit.de
pear install phpunit/phpcpd</pre>
<h5><a href="http://www.pdepend.org/news.html" target="_blank">PHP Depend</a> &#8211; help analyse quality of codebase</h5>
<p>Note you may have update PHP to include the DOM module (first line below).</p>
<pre class="code">yum install php-dom
pear channel-discover pear.pdepend.org
pear install pdepend/PHP_Depend-beta</pre>
<h5><a href="http://pear.php.net/package/PHP_CodeSniffer" target="_blank">PHP Code Sniffer</a> &#8211; analyse code for adherence to style/standards</h5>
<pre class="code">pear install PHP_CodeSniffer-1.2.0</pre>
<h5><a href="http://pear.php.net/package/PHP_CodeSniffer" target="_blank">PHP Unit</a> &#8211; unit test framework for PHP</h5>
<pre class="code">pear channel-discover pear.phpunit.de
pear install phpunit/PHPUnit</pre>
<p>To make PHP Unit work, we need <a href="http://xdebug.org/" target="_blank">XDebug</a> installed, the PHP profiler.</p>
<pre class="code">yum install php-devel gcc
pecl install xdebug</pre>
<h3>6. Install Hudson plugins</h3>
<p>Use the web interface to install the following plugins (Manage Hudson -&gt; Plugins).</p>
<ul>
<li>Checkstyle</li>
<li>Clover</li>
<li>DRY</li>
<li>Green Balls (handy because it shows successful builds as green circles rather than blue)</li>
<li>JDepend</li>
<li>xUnit (will handle the output of PHPUnit test results XML)</li>
</ul>
<h3>7. Setup the phing build script</h3>
<p>The Phing build script defines what steps will be taken to “build” the application.</p>
<p>Hudson itself works by placing our code into a project workspace. It will checkout the code from subversion and place it into the following location, where “Test” is the name of our project.</p>
<pre class="code">/var/lib/hudson/jobs/Test/workspace/</pre>
<p>We can then use the Phing build script to carry out a number of processes on this code. When we talk about “building”, what we will actually do is place the code where we need it so it can actually run the website (we&#8217;ll keep this within the workspace) plus we run tests etc&#8230;</p>
<p>We&#8217;ll keep the build script in the subversion repository, so effectively it will be updated from SVN each build. For this approach to work, the following XML needs to be stored in a file named build.xml, stored in the project root folder (within trunk), eg: /trunk/build.xml</p>
<pre class="code">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
 &lt;project name="test" basedir="." default="app"&gt;
    &lt;property name="builddir" value="${ws}/build" /&gt;

    &lt;target name="clean"&gt;
        &lt;echo msg="Clean..." /&gt;
        &lt;delete dir="${builddir}" /&gt;
    &lt;/target&gt;

    &lt;target name="prepare"&gt;
        &lt;echo msg="Prepare..." /&gt;
        &lt;mkdir dir="${builddir}" /&gt;
        &lt;mkdir dir="${builddir}/logs" /&gt;
        &lt;mkdir dir="${builddir}/logs/coverage" /&gt;
        &lt;mkdir dir="${builddir}/docs" /&gt;
        &lt;mkdir dir="${builddir}/app" /&gt;
    &lt;/target&gt;

    &lt;!-- Deploy app --&gt;
    &lt;target name="app"&gt;
        &lt;echo msg="We do nothing yet!" /&gt;
    &lt;/target&gt;

    &lt;!-- PHP API Documentation --&gt;
    &lt;target name="phpdoc"&gt;
        &lt;echo msg="PHP Documentor..." /&gt;
        &lt;phpdoc title="API Documentation"
                destdir="${builddir}/docs"
                sourcecode="yes"
                defaultpackagename="MHTest"
                output="HTML:Smarty:PHP"&gt;
            &lt;fileset dir="./app"&gt;
                &lt;include name="**/*.php" /&gt;
            &lt;/fileset&gt;
        &lt;/phpdoc&gt;
    &lt;/target&gt;

    &lt;!-- PHP copy/paste analysis --&gt;
    &lt;target name="phpcpd"&gt;
        &lt;echo msg="PHP Copy/Paste..." /&gt;
        &lt;exec command="phpcpd --log-pmd=${builddir}/logs/pmd.xml source" escape="false" /&gt;
    &lt;/target&gt;

    &lt;!-- PHP dependency checker --&gt;
    &lt;target name="pdepend"&gt;
        &lt;echo msg="PHP Depend..." /&gt;
        &lt;exec command="pdepend --jdepend-xml=${builddir}/logs/jdepend.xml ${ws}/source" escape="false" /&gt;
    &lt;/target&gt;

    &lt;!-- PHP CodeSniffer --&gt;
    &lt;target name="phpcs"&gt;
        &lt;echo msg="PHP CodeSniffer..." /&gt;
        &lt;exec command="phpcs --standard=ZEND --report=checkstyle ${ws}/source &gt; ${builddir}/logs/checkstyle.xml" escape="false" /&gt;
    &lt;/target&gt;

    &lt;!-- Unit Tests &amp; coverage analysis --&gt;
    &lt;target name="phpunit"&gt;
        &lt;echo msg="PHP Unit..." /&gt;
        &lt;exec command="phpunit --log-junit ${builddir}/logs/phpunit.xml --log-pmd ${builddir}/logs/phpunit.pmd.xml --coverage-clover ${builddir}/logs/coverage/clover.xml --coverage-html ${builddir}/logs/coverage/ ${ws}/source/tests"/&gt;
    &lt;/target&gt;
&lt;/project&gt;</pre>
<h3>8. Setup Hudson</h3>
<p>The first step is to create a new job.</p>
<ul>
<li>From the Hudson homepage, click New Job.</li>
<li>Enter a Job name, for example “Dave&#8217;s Product Build” and choose “Build a free-style software project”. Click OK.</li>
</ul>
<p>Now you need to configure the job; the configuration form should be displayed immidiately after adding.</p>
<p>Under <strong>Source Code Management</strong> choose <strong>Subversion</strong> and enter:</p>
<ul>
<li>Repository URL: http://www.myrepo.com/path/to/repo</li>
<li>Local module directory: source</li>
<li>Check &#8220;Use update&#8221; which speeds up checkout</li>
</ul>
<p>Under <strong>Build Triggers</strong> select <strong>Poll SCM</strong> and enter the following schedule:</p>
<pre class="code">5 * * * *
10 * * * *
15 * * * *
20 * * * *
25 * * * *
30 * * * *
35 * * * *
40 * * * *
45 * * * *
50 * * * *
55 * * * *</pre>
<p>Note that this will poll for changes to the repository every 5 minutes and rebuild if any changes are detected.</p>
<p>Under <strong>Build</strong> click the button to <strong>Add build step</strong> and choose <strong>Execute shell</strong>, enter the command:</p>
<pre class="code">phing -f $WORKSPACE/source/build.xml prepare app phpdoc phpcs phpunit -Dws=$WORKSPACE</pre>
<p>Under <strong>Post-build Actions</strong> choose:</p>
<ul>
<li>Check Publish Javadoc and then enter:<br />
Javadoc directory = build/docs/</li>
<li>Check Publish testing tools result report and then click Add and pick PHP Unit, enter:<br />
+ PHPUnit Pattern = build/logs/phpunit.xml</li>
<li>Check Publish Clover Coverage Report and enter:<br />
+ Clover report directory = build/logs/coverage<br />
+ Clover report file name = clover.xml</li>
<li>Check Publish duplicate code analysis results and enter:<br />
+ Duplicate code results = build/logs/phpunit.pmd-cpd.xml</li>
<li>Check Publish Checkstyle analysis results and enter:<br />
+ Checkstyle results = build/logs/checkstyle.xml</li>
</ul>
<p>Finally, click <strong>Build Now</strong> to test it all works.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.davegardner.me.uk/blog/2009/11/09/continuous-integration-for-php-using-hudson-and-phing/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
	</channel>
</rss>

