Continuous Integratation testing FlexUnit on CentOS

First let me introduce myself.  My name is Joshua Garnett.  I joined Adobe last fall as a Computer Scientist on the Flash Platform Services Team.  I’m currently working on the InMarket app distribution service. If you’re an app developer and looking to simplify your deployment process, you should definitely check it out.

Now on to the actual reason behind this post.  Recently I was tasked with getting FlexUnit tests to run in our CI environment. There is a lot of documentation out there on how to get things up and running on Hudson, but I wasn’t able to find a fool-proof method for those of us who just want to use an ant build script to run the tests. This is a brief summary of the items that need to be setup and installed in order to do just that.

Here is the software that I ended up using:


I’m not going to cover creating FlexUnit tests, but I wanted to display an example Test Application for running the Unit tests. The key item is adding the CIListener() to the FlexUnitCore.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application 
	xmlns:mx="http://www.adobe.com/2006/mxml"
	creationComplete="runMe()
	xmlns:adobe="http://www.adobe.com/2009/flexUnitUIRunner">
 
	<mx:Script>
		<![CDATA[
			import com.your.company.tests.AllTests;
 
			import flexunit.framework.TestSuite;
 
			import org.flexunit.listeners.CIListener;
			import org.flexunit.listeners.UIListener;
			import org.flexunit.runner.FlexUnitCore;
 
			private var core:FlexUnitCore;
 
			public function runMe():void {
				core = new FlexUnitCore();
				core.addListener(new UIListener(uiListener));
				core.addListener(new CIListener());
 
				core.run( com.your.company.tests.AllTests );
			}
		]]>
	</mx:Script>
 
	<adobe:TestRunnerBase id="uiListener" width="100%" height="100%" />
</mx:Application>

Once the Testing Application is created, we need to create an ant build script to run the tests. The script below is compatible with Ant 1.7.0+ and should run on multiple platforms.

<project name="YourProject" default="test">
 
	<property name="SRC_DIR" value="./src" />
	<property name="TEST_DIR" value="./bin-test" />
	<property name="FLEX_UNIT_DIR" value="./flexunit-output" />
 
	<property name="flexunit.jar" value="./libs/flexUnitTasks-4.1.0_RC2-28.jar" />
 
	<property name="flexunit.swc" value="./libs/flexunit-4.1.0_RC2-28-flex_3.5.0.12683.swc" />
	<property name="flexunit-uilistener.swc" value="./libs/flexunit-uilistener-4.1.0_RC2-28-flex_3.5.0.12683.swc" />
	<property name="flexunit-cilistener.swc" value="./libs/flexunit-cilistener-4.1.0_RC2-28-flex_3.5.0.12683.swc" />
 
	<!-- Setup platform booleans -->
	<condition property="isMac">
		<os family="mac" />
	</condition>
 
	<condition property="isWindows">
		<os family="windows" />
	</condition>
 
	<condition property="isLinux">
		<os name="Linux" />
	</condition>
 
	<!-- 
		Different platforms can have different SDK locations, mxmlc scripts, 
		and FlexUnit properties.
	-->
	<target name="setupEnvironment" depends="setPropsMac,setPropsWindows,setPropsLinux" />
 
	<target name="setPropsMac" if="isMac">
		<property name="FLEX_HOME" value="/Applications/Adobe Flash Builder 4/sdks/3.5.0/" />
		<property name="MXMLC" value="${FLEX_HOME}/bin/mxmlc" />
		<property name="HEADLESS" value="false" />
	</target>
 
	<target name="setPropsWindows" if="isWindows">
		<property name="FLEX_HOME" value="C:\Program Files (x86)\Adobe\Adobe Flash Builder 4\sdks\3.5.0" />
		<property name="MXMLC" value="${FLEX_HOME}/bin/mxmlc.exe" />
		<property name="HEADLESS" value="false" />
	</target>
 
	<target name="setPropsLinux" if="isLinux">
		<property name="FLEX_HOME" value="/opt/flex_sdk_3.5.0.12683" />
		<property name="MXMLC" value="${FLEX_HOME}/bin/mxmlc" />
		<!-- only linux should run in headless mode -->
		<property name="HEADLESS" value="true" />
	</target>
 
	<!-- this is used for running flexunit from the command line -->
	<taskdef resource="flexUnitTasks.tasks" classpath="${flexunit.jar}"/>
 
	<target name="clean" depends="">
		<delete dir="${TEST_DIR}" />
		<delete dir="${FLEX_UNIT_DIR}" />
	</target>
 
	<target name="test" depends="clean,setupEnvironment">
		<property name="debug" value="true" />
		<antcall target="flexUnitTest" />
	</target>
 
	<target name="flexUnitTest" depends="">
		<exec executable="${MXMLC}" failonerror="true">
			<arg value="-debug=${debug}" />
			<arg value="-compiler.source-path=${SRC_DIR}" />
			<arg value="-source-path=${SRC_DIR}" />
			<arg value="-link-report=linkReport.xml" />
			<arg value="-library-path+=${flexunit.swc}" />
			<arg value="-library-path+=${flexunit-uilistener.swc}" />
			<arg value="-library-path+=${flexunit-cilistener.swc}" />
			<!-- Be sure to include any other swcs needed to build the swf -->
			<arg value="-output=${TEST_DIR}/FlexUnitTestingApp.swf" />
			<arg value="--" />
			<arg value="${SRC_DIR}/FlexUnitTestingApp.mxml" />
		</exec>
 
		<mkdir dir="${FLEX_UNIT_DIR}"/>
 
		<!-- 
			Note: By specifying haltonfailure, the ant script will use a return 
			code of 1 instead of 0, which you can use to script validation of
			the test results.
		-->
		<flexunit swf="${TEST_DIR}/FlexUnitTestingApp.swf" 
					toDir="$FLEX_UNIT_DIR}"
					haltonfailure="true"
					headless="${HEADLESS}"
					verbose="true"
					localTrusted="true" />
 
		<junitreport todir="${FLEX_UNIT_DIR}">
			<fileset dir="${FLEX_UNIT_DIR}">
				<include name="TEST-*.xml"/>
			</fileset>
			<report format="frames" todir="${FLEX_UNIT_DIR}/html"/>
		</junitreport>
	</target>
</project>

Lastly, we need to install a few packages on CentOS 5.5. All of these commands should be run as root.

# Download and install the flash projector
wget http://download.macromedia.com/pub/flashplayer/updaters/10/flashplayer_10_sa_debug.tar.gz
tar xzvf flashplayer_10_sa_debug.tar.gz
 
# Add it to the PATH and make the symbolic link gflashplayer
mv flashplayerdebugger /usr/bin
ln -s /usr/bin/flashplayerdebugger /usr/bin/gflashplayer
 
# install xvnc
yum install vnc-server
 
# install windowing system
yum groupinstall "GNOME Desktop Environment"
 
# Setup VNC Password
vncpasswd

We are now ready to run the FlexUnit tests on a CentOS instance. By running either ant or ant test we should see the swf build, flex unit run, and then finally see the creation of the HTML files for viewing the results. Sample output below.

Buildfile: build.xml
 
clean:
   [delete] Deleting directory /opt/bin-test
   [delete] Deleting directory /opt/flexunit-output
 
setPropsMac:
 
setPropsWindows:
 
setPropsLinux:
 
setupEnvironment:
 
test:
 
flexUnitTest:
     [exec] Loading configuration file /opt/flex_sdk_3.5.0.12683/frameworks/flex-config.xml
     [exec] /opt/bin-test/FlexUnitTestingApp.swf (911489 bytes)
    [mkdir] Created dir: /opt/flexunit-output
 [flexunit] Validating task attributes ...
 [flexunit] OS: [Linux]
 [flexunit] Generating default values ...
 [flexunit] Using default working dir [/opt]
 [flexunit] Using default reporting dir [/opt]
 [flexunit] Using the following settings for the test run:
 [flexunit]     FLEX_HOME: [/opt/flex_sdk_3.5.0.12683]
 [flexunit]     haltonfailure: [true]
 [flexunit]     headless: [true]
 [flexunit]     display: [99]
 [flexunit]     localTrusted: [true]
 [flexunit]     player: [flash]
 [flexunit]     port: [1024]
 [flexunit]     swf: [/opt/bin-test/FlexUnitTestingApp.swf]
 [flexunit]     timeout: [60000ms]
 [flexunit]     toDir: [/opt]
 [flexunit] Setting up server process ...
 [flexunit] Starting server ...
 [flexunit] Starting xvnc
 [flexunit] Attempting start on :99 ...
 [flexunit] Executing 'vncserver' with arguments:
 [flexunit] ':99'
 [flexunit] 
 [flexunit] The '' characters around the executable and arguments are
 [flexunit] not part of the command.
 [flexunit] 
 [flexunit] Opening server socket on port [1024].
 [flexunit] Waiting for client connection ...
 [flexunit] 
 [flexunit] Starting applications specified in /root/.vnc/xstartup
 [flexunit] 
 [flexunit] Setting DISPLAY=:99
 [flexunit] Executing 'gflashplayer' with arguments:
 [flexunit] '/opt/bin-test/FlexUnitTestingApp.swf'
 [flexunit] 
 [flexunit] The '' characters around the executable and arguments are
 [flexunit] not part of the command.
 [flexunit] 
 [flexunit] Client connected.
 [flexunit] Setting inbound buffer size to [262144] bytes.
 [flexunit] Receiving data ...
 [flexunit] Sending acknowledgement to player to start sending test data ...
 [flexunit] 
 [flexunit] Stopping server ...
 [flexunit] End of test data reached, sending acknowledgement to player ...
 [flexunit] Closing client connection ...
 [flexunit] Closing server on port [1024] ...
 [flexunit] Terminating xvnc on :99
 [flexunit] Executing 'vncserver' with arguments:
 [flexunit] '-kill'
 [flexunit] ':99'
 [flexunit] 
 [flexunit] The '' characters around the executable and arguments are
 [flexunit] not part of the command.
 [flexunit] 
 [flexunit] Killing Xvnc process ID 3685
 [flexunit] Analyzing reports ...
 [flexunit] 
 [flexunit] Suite: com.your.company.tests.ParserTest
 [flexunit] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.044 sec
 [flexunit] Suite: com.your.company.tests.ModelTest
 [flexunit] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.025 sec
 [flexunit] 
 [flexunit] Results :
 [flexunit] 
 [flexunit] Tests run: 5, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.069 sec
 [flexunit] 
[junitreport] Processing /opt/flexunit-output/TESTS-TestSuites.xml to /tmp/null2057278126
[junitreport] Transform time: 267ms
[junitreport] Deleting: /tmp/null2057278126
 
BUILD SUCCESSFUL
Total time: 21 seconds