Jetty ExampleThe Jetty example demonstrates a real world use of BlackBadger bringing together Jetty - the open source Java based web server - and Apache JMeter - an open source testing tool. Jetty Component XMLThe Jetty component is responsible for downloading and installing Jetty to it's host and running it on a given port. There are a number of parameters that provide some flexibility but it will work 'out of the box' with the provided defaults. The comments should provide a reasonable explanation of which each does. <!-- the port which Jetty will serve HTTP requests on --> <property name="port" value="8080"/> <!-- parameters used for stopping Jetty --> <property name="stop.port" value="8078"/> <property name="stop.key" value="secret"/> <!-- the name of the Jetty zip file --> <property name="filename" value="jetty-6.0.0.zip"/> <!-- the name of the Jetty file without the zip extension --> <basename property="name" file="${filename}" suffix=".zip"/> <!-- the url from which to download jetty - defaults to one of the public mirrors --> <property name="repository" value="http://heanet.dl.sourceforge.net/sourceforge/jetty/"/> <!-- the location when Jetty will be installed --> <property name="installdir" value="/opt/"/> <!-- the top level directory where Jetty will be installed --> <property name="homedir" value="${installdir}${name}/"/> <!-- the directory to use for temporary file --> <property name="tmpdir" value="./tmp/"/> The 'clean' target removes the home directory thus removing any previous installation and the files downloaded the temporary directory. <target name="clean" description="Called at the start to ensure the environment is clean for deployment"> <delete dir="${tmpdir}"/> <delete file="${tmpdir}${filename}"/> </target> Deployment of Jetty is performed by the 'deploy' target. It downloads the Jetty zip file distribution from the url provided by the 'filename' and 'repository' parameters, and subsequently unzips it to the desired directory. <target name="deploy" description="Downloads Jetty and extracts the zip file"> <mkdir dir="${tmpdir}"/> <echo message="Downloading Jetty..."/> <get src="${repository}${filename}" dest="${tmpdir}${filename}"/> <echo message="Download complete"/> <echo message="Extracting zip file..."/> <unzip src="${tmpdir}${filename}" dest="${installdir}" /> <echo message="Complete"/> </target> Since Jetty provides a means of starting it via the 'start.jar' executable jar, we use the <java> task in the 'run' target to kick it off. It conveniently also provides a means of passing in the parameters we've set - the port, stop.port and stop.key. But because the process doesn't return whilst Jetty is stilling running we need to do 2 things. Firstly the process must be spawned (using the spawn attribute) so that the target can be executed to completion. Unfortunately by doing that we lose some of the other attribute functionality that would normally be useful in verifying that the process started up without error. The alternative we've used here is to wait for Jetty to return an http request on a url we know it should successfully return if the startup succeeded. We allow it up to a minute - checking every second - for it to respond. If it fails to respond in that period, the 'failedcheck' property is set and the <fail> task will subsequently cause this target to fail so that BlackBadger can be made aware of it. Otherwise, the startup is considered a success and we're ready to move onto the next state. <target name="run" description="Starts Jetty"> <echo message="Starting up Jetty on port ${port}..."/> <java jar="${homedir}/start.jar" fork="true" maxmemory="128m" dir="${homedir}" spawn="true"> <sysproperty key="jetty.port" value="${port}"/> <sysproperty key="STOP.PORT" value="${stop.port}"/> <sysproperty key="STOP.KEY" value="${stop.key}"/> <arg value="etc/jetty.xml"/> </java> <!-- wait until we can successfully hit a page on the server thus confirming it started up --> <waitfor maxwait="1" maxwaitunit="minute" checkevery="1000" timeoutproperty="failedcheck"> <http url="http://localhost:${port}/test/index.html"/> </waitfor> <!-- if it didn't return successfully in the set timeout then abort --> <fail if="failedcheck" message="Failed to startup Jetty"/> <echo message="Jetty started up successfully"/> </target> The test state in this instance is empty because it's at this point the JMeter component will be running it's tests. Everything that needs to be done to prepare Jetty to be tested against should have been done prior to this target. <target name="test" description="Called when the system is ready to start testing"> </target> Finally, the 'terminate' target performs the necessary java invocation to stop Jetty. Note that a similar <java> task is used but in this case we do not spawn the process because we want the shutdown to complete before we can consider the target execution at an end. <target name="terminate" description="Called when either an exception/error has occurred or the system is to stop."> <echo message="Shutting down Jetty..."/> <java jar="${homedir}/start.jar" fork="true" failonerror="true" maxmemory="128m" dir="${homedir}"> <sysproperty key="STOP.PORT" value="${stop.port}"/> <sysproperty key="STOP.KEY" value="${stop.key}"/> <arg line="--stop"/> </java> <echo message="Shutdown complete"/> </target> JMeter Component XMLThe Apache JMeter component is designed for deploying JMeter on a machine and running a given test file. Again the properties defined at the top of the page are explained by the comments. Note that unlike the Jetty component however, there are 2 properties which although defaulted, require to be overridden in any run - the testrepository and testfile. <!-- the name of the JMeter distribution zip file --> <property name="filename" value="jakarta-jmeter-2.2.zip"/> <basename property="name" file="${filename}" suffix=".zip"/> <!-- the url from which to download the jmeter installation --> <property name="repository" value="http://www.mirrorservice.org/sites/ftp.apache.org/jakarta/jmeter/binaries/"/> <!-- the url from which to download the test file --> <property name="testrepository" value=""/> <!-- the name of the test file to run --> <property name="testfile" value="test.jmx"/> <!-- the host that the testfile should be configured to use --> <property name="testfile.host" value="localhost"/> <!-- the temporary directory to use for downloaded files --> <property name="tmpdir" value="tmp/"/> <!-- the location when JMeter will be installed --> <property name="installdir" value="/opt/"/> <!-- the top level directory where JMeter will be installed --> <property name="homedir" value="${installdir}${name}/"/> <!-- the name of the jmeter jar to execute --> <property name="jmeter.jar" value="ApacheJMeter.jar"/> As with the Jetty component, the 'clean' target removes any previous installation of JMeter and the files downloaded the temporary directory. <target name="clean" description="cleans up any existing files from a previous run"> <delete dir="${jmeter.home}"/> <!-- delete any existing jmeter install --> <delete file="${tmpdir}${jmeter.tar}"/> <delete file="${tmpdir}${testfile}"/> </target> The 'deploy' target will download the JMeter distribution file and extract it to the installation directory. It also downloads the test file that will be used in the test run and edits the domain that it will run against - we're making the assumption that this is an http based testfile. <target name="deploy" description="installs JMeter and downloads the test file"> <mkdir dir="${tmpdir}"/> <echo message="Downloading JMeter zip file"/> <get src="${repository}${filename}" dest="${tmpdir}${filename}"/> <echo message="Downloading JMeter test file"/> <get src="${testrepository}${testfile}" dest="${tmpdir}${testfile}"/> <!-- set the host that the testfile will run against --> <replace file="${tmpdir}${testfile}" value="<stringProp name="HTTPSampler.domain">${testfile.host}</stringProp>"> <replacetoken><stringProp name="HTTPSampler.domain">localhost</stringProp></replacetoken> </replace> <echo message="Extracting JMeter zip"/> <unzip src="${tmpdir}${filename}" dest="${installdir}"/> <echo message="Complete"/> </target> Nothing needs to be done in the 'run' target for JMeter. <target name="run" description="JMeter does it's running in the test target"> </target> Unlike the Jetty component, JMeter as the testing component does it's running in the 'test' target. Here we demonstrate an alternative to the <java> task in starting up the component - the <exec> task. The main argument we pass in here is the path to the test file that we want to run. Note that it's important that the 'failonerror' attribute is set to 'true' so that the target execution will fail as a whole if the JMeter startup fails and thus BlackBadger will be aware that the run failed. <target name="test" description="Runs the tests"> <echo>Running JMeter...</echo> <exec executable="java" failonerror="true"> <arg line="-jar ${homedir}bin/${jmeter.jar} -n -t ${basedir}/${tmpdir}${testfile}"/> </exec> <echo>JMeter run complete</echo> </target> Last but not least, the 'terminate' target gathers the all important test results using the BlackBadger-specific <logfile> task. Note that it's possible that the test could have saved the results as any arbitrary filename but we only log the files with the ".log" file extension. However by recommending that all results are saved with this naming convention we can maximize the reusability of this component. <target name="terminate" description="Sends all the .log files back to the MasterBadger"> <!-- if the test file does any logging of results it should do so in the working directory with a filename extension of ".log" so that it's collected here --> <logfile> <fileset dir="${basedir}"> <include name="*.log"/> </fileset> </logfile> </target> System XMLThe system xml is pretty straightforward. It consists of 1 agent with 2 components deployed on it - the component being tested and the testing component. In a real world testing scenario these would more likely be deployed on separate machines which is the reason behind the jetty 'ipaddress' property and the jmeter 'testfile.host' property that makes use of it. We pass in a 'port' property to the Jetty component (overriding the default 8080) and the details of the test file that we wish to run to the JMeter component. <?xml version="1.0" encoding="UTF-8"?> <system name="Jetty example"> <!-- This example will download Jetty and JMeter, running a small JMeter test file against the test application that's bundled with Jetty --> <!-- the url where the JMeter test file can be downloaded from minus the filename --> <property name="testrepository" value="http://developer.spikesource.com/frs/download.php/121/"/> <agent id="agent1"> <group id="server"> <comp base="jetty" id="Jetty"> <!-- startup jetty on port 80 --> <property name="port" value="80"/> <property name="ipaddress" value="${agent.this.ipaddress}"/> </comp> <comp base="jmeter" id="jmeter"> <property name="testrepository" value="${system.testrepository}"/> <property name="testfile" value="jettytest.jmx"/> <property name="testfile.host" value="${component.jetty.ipaddress}"/> </comp> </group> </agent> </system> Expected outputBelow is how the output from a successful run might look:05/10/06 16:32.35: MasterBadger-WeeBadger=WB_10.6002 registered; OS=Windows XP 05/10/06 16:32.45: StateMachine-WeeBadgers now setup with data entering execution states 05/10/06 16:32.45: StateMachine#clean-Executing State 05/10/06 16:32.45: RemoteWeeBadger:WB_10.6002-clean started 05/10/06 16:32.45: RemoteWeeBadger:WB_10.6002-Component.Jetty executing state: clean 05/10/06 16:32.46: RemoteWeeBadger:WB_10.6002-Component.Jetty.[ANT] Deleting directory E:\SpikeSource\BlackBadger\tmp 05/10/06 16:32.46: RemoteWeeBadger:WB_10.6002-Component.Jetty completed state: clean 05/10/06 16:32.46: RemoteWeeBadger:WB_10.6002-Component.jmeter executing state: clean 05/10/06 16:32.46: RemoteWeeBadger:WB_10.6002-Component.jmeter completed state: clean 05/10/06 16:32.46: RemoteWeeBadger:WB_10.6002-clean completed time=563ms 05/10/06 16:32.46: StateMachine#clean-Executing State Completed 05/10/06 16:32.46: StateMachine#deploy-Executing State 05/10/06 16:32.46: RemoteWeeBadger:WB_10.6002-deploy started 05/10/06 16:32.46: RemoteWeeBadger:WB_10.6002-Component.Jetty executing state: deploy 05/10/06 16:32.46: RemoteWeeBadger:WB_10.6002-Component.Jetty.[ANT] Created dir: E:\SpikeSource\BlackBadger\tmp 05/10/06 16:32.46: RemoteWeeBadger:WB_10.6002-Component.Jetty.[ANT] Downloading Jetty... 05/10/06 16:32.46: RemoteWeeBadger:WB_10.6002-Component.Jetty.[ANT] Getting: http://heanet.dl.sourceforge.net/sourceforge/jetty/jetty-6.0.0.zip 05/10/06 16:32.46: RemoteWeeBadger:WB_10.6002-Component.Jetty.[ANT] To: E:\SpikeSource\BlackBadger\tmp\jetty-6.0.0.zip 05/10/06 16:34.16: RemoteWeeBadger:WB_10.6002-Component.Jetty.[ANT] Download complete 05/10/06 16:34.16: RemoteWeeBadger:WB_10.6002-Component.Jetty.[ANT] Extracting zip file... 05/10/06 16:34.16: RemoteWeeBadger:WB_10.6002-Component.Jetty.[ANT] Expanding: E:\SpikeSource\BlackBadger\tmp\jetty-6.0.0.zip into \opt 05/10/06 16:34.29: RemoteWeeBadger:WB_10.6002-Component.Jetty.[ANT] Complete 05/10/06 16:34.29: RemoteWeeBadger:WB_10.6002-Component.Jetty completed state: deploy 05/10/06 16:34.29: RemoteWeeBadger:WB_10.6002-Component.jmeter executing state: deploy 05/10/06 16:34.29: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] Downloading JMeter zip file 05/10/06 16:34.29: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] Getting: http://www.mirrorservice.org/sites/ftp.apache.org/jakarta/jmeter/binaries/jakarta-jmeter-2.2.zip 05/10/06 16:34.29: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] To: E:\SpikeSource\BlackBadger\tmp\jakarta-jmeter-2.2.zip 05/10/06 16:35.35: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] Downloading JMeter test file 05/10/06 16:35.35: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] Getting: http://developer.spikesource.com/frs/download.php/121/jettytest.jmx 05/10/06 16:35.35: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] To: E:\SpikeSource\BlackBadger\tmp\jettytest.jmx 05/10/06 16:35.36: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] Extracting JMeter zip 05/10/06 16:35.36: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] Expanding: E:\SpikeSource\BlackBadger\tmp\jakarta-jmeter-2.2.zip into \opt 05/10/06 16:35.37: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] Complete 05/10/06 16:35.37: RemoteWeeBadger:WB_10.6002-Component.jmeter completed state: deploy 05/10/06 16:35.37: RemoteWeeBadger:WB_10.6002-deploy completed time=170891ms 05/10/06 16:35.37: StateMachine#deploy-Executing State Completed 05/10/06 16:35.37: StateMachine#run-Executing State 05/10/06 16:35.37: RemoteWeeBadger:WB_10.6002-run started 05/10/06 16:35.37: RemoteWeeBadger:WB_10.6002-Component.Jetty executing state: run 05/10/06 16:35.37: RemoteWeeBadger:WB_10.6002-Component.Jetty.[ANT] Starting up Jetty on port 80... 05/10/06 16:35.40: RemoteWeeBadger:WB_10.6002-Component.Jetty.[ANT] Jetty started up successfully 05/10/06 16:35.40: RemoteWeeBadger:WB_10.6002-Component.Jetty completed state: run 05/10/06 16:35.40: RemoteWeeBadger:WB_10.6002-Component.jmeter executing state: run 05/10/06 16:35.41: RemoteWeeBadger:WB_10.6002-Component.jmeter completed state: run 05/10/06 16:35.41: RemoteWeeBadger:WB_10.6002-run completed time=3672ms 05/10/06 16:35.41: StateMachine#run-Executing State Completed 05/10/06 16:35.41: StateMachine#test-Executing State 05/10/06 16:35.41: RemoteWeeBadger:WB_10.6002-test started 05/10/06 16:35.41: RemoteWeeBadger:WB_10.6002-Component.Jetty executing state: test 05/10/06 16:35.41: RemoteWeeBadger:WB_10.6002-Component.Jetty completed state: test 05/10/06 16:35.41: RemoteWeeBadger:WB_10.6002-Component.jmeter executing state: test 05/10/06 16:35.41: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] Running JMeter... 05/10/06 16:35.42: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] Created the tree successfully 05/10/06 16:35.42: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] Starting the test 05/10/06 16:37.27: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] Tidying up ... 05/10/06 16:37.32: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] ... end of run 05/10/06 16:37.32: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] JMeter run complete 05/10/06 16:37.32: RemoteWeeBadger:WB_10.6002-Component.jmeter completed state: test 05/10/06 16:37.32: RemoteWeeBadger:WB_10.6002-test completed time=111343ms 05/10/06 16:37.32: StateMachine#test-Executing State Completed 05/10/06 16:37.32: StateMachine#terminate-Executing State 05/10/06 16:37.32: RemoteWeeBadger:WB_10.6002-terminate started 05/10/06 16:37.32: RemoteWeeBadger:WB_10.6002-Component.Jetty executing state: terminate 05/10/06 16:37.32: RemoteWeeBadger:WB_10.6002-Component.Jetty.[ANT] Shutting down Jetty... 05/10/06 16:37.32: RemoteWeeBadger:WB_10.6002-Component.Jetty.[ANT] Shutdown complete 05/10/06 16:37.32: RemoteWeeBadger:WB_10.6002-Component.Jetty completed state: terminate 05/10/06 16:37.32: RemoteWeeBadger:WB_10.6002-Component.jmeter executing state: terminate 05/10/06 16:37.32: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] sending files 05/10/06 16:37.33: RemoteWeeBadger:WB_10.6002-Component.jmeter.[ANT] 3 files sent 05/10/06 16:37.33: RemoteWeeBadger:WB_10.6002-Component.jmeter completed state: terminate 05/10/06 16:37.33: RemoteWeeBadger:WB_10.6002-terminate completed time=1296ms 05/10/06 16:37.33: StateMachine#terminate-Executing State Completed 05/10/06 16:37.33: StateMachine#terminate-All WeeBadgers now completed their state executions |