Using Xvnc to create headless CI builds for Flex and AIR applications

Brian LeGros | December 20th, 2009 | programming  

Over the last year or so, I’ve worked to integrate xvfb into the projects I work with at the office and in the community to allow the execution of truly headless builds for Flex-based applications. Since the Flash Player and AIR require a windowing environment and typically unit and integration tests require this environment to be executed, integrating Flex into a CI process on Linux gets pretty hairy without having X-Windows support. Recently I’ve found myself switching from xvfb to Xvnc to more easily support headless builds in Flex. VNC server packages are pretty ubiquitous for most Linux distros, so getting something installed is pretty simple. What took me a couple of steps was getting setup based on the configuration of my CI server. In an effort to make searching a little simpler, here are the steps for using the Xvnc-plugin with Hudson on Ubuntu Desktop 8.10 with the default Tomcat 6 installation:

  1. Install the vnc4server package (i.e. – “apt-get install vnc4server”).
  2. Assuming the Ubuntu installation came with Tomcat 6 and is setup to run as the tomcat6 system user, do the following:
    1. Execute vncpassword as any user, following the prompts to set a password to be used by the “vncserver” command. This will create the “~/.vnc/password” file needed to run the vncserver command.
    2. Copy the file at ~/.vnc/password to /usr/shared/tomcat6/.vnc/password which is the default home directory for the tomcat6 user on the standard install of Ubuntu Desktop.
    3. Change the ownership rights on the “password” file to be owned and created by the “tomcat6″ user (i.e. – chown tomcat6:tomcat6 /usr/shared/.vnc/password)
    4. Edit /etc/init.d/tomcat6, adding a line to set the HOME environment variable to “/usr/shared/tomcat6″ (i.e. – export HOME=/usr/shared/tomcat6). Since “tomcat6″ is setup as a system user, from what I can tell, this environment variable is not set by default when a process is running as this user. The “vncserver” command will need this variable to determine where the “password” file is located to launch its process.
  3. If Tomcat is running as a standard user, execute the “vncserver” command using any display number (e.g. – vncserver :99) as the user. The command will force a prompt to enter a password to use for the server which will create the “~/.vnc/password” file with the appropriate ownership rights in the appropriate home directory.
  4. In Hudson, install the Xvnc-plugin for Hudson (http://wiki.hudson-ci.org/display/HUDSON/Xvnc+Plugin)
  5. OPTIONAL: In Hudson, under “Manage Hudson” -> “Configure system” -> “Xvnc”, set the “Base display number” field to 99. This is the base display number xvfb-run uses and I’m partial to reusing this setting.
  6. Under the configuration for you CI build, check the box labeled Run Xvnc during build.
  7. If all goes as expected, then your build should kick off the “vncserver :99″ command, set the DISPLAY environment variable to 99, execute your build to completion, and then execute “vncserver -kill :99″ to kill the Xvnc process.

Based on these steps, I’m am currently building Xvnc support into the FlexUnit4 Ant task for those who don’t use Hudson and can’t take advantage of the Xvnc-plugin. The Xvnc support is a basic mirror of what the plugin for Hudson aims to provide. Hopefully someone will find this footwork useful and save some time. I’m by no means a Linux guru, so if anyone has more insight, please feel free to share so others can benefit from your knowledge as well.

Happy building!

UPDATE: I’ve now tested and deployed the Xvnc support for the FlexUnit Ant task. Hopefully this will help anyone who’s not using Hudson but wants to take advantage of headless FlexUnit test executions using Xvnc.

Converting a FlexCover CVR to Cobertura XML report

Brian LeGros | October 19th, 2009 | programming  

If you’re using FlexCover as a code coverage tool within your Flex build process, the resulting report will be an XML file with a .cvr file extension. Currently there are no FlexCover plugins for the popular CI servers (i.e. – Hudson, Cruise Control, Bamboo, etc), so to take advantage of the cool baked-in reporting for code coverage, an XML report for a supported report format (e.g. – Emma, Cobertura, Clover) is needed. Currently Paul over at eyefodder has a solution using a custom build of the CoverageViewer and CoverageAgent which will produce an Emma formatted report.

Instead of creating my own custom build of FlexCover, I decided to work on an XSL transformation to the Cobertura XML report format to see if I could have any success. After a pain-staking journey back into the world of XSL, I was able to throw together an XSLT that is working with Hudson’s Cobertura plugin. You can find the XSLT under FlexUnit4 source control @ http://opensource.adobe.com/svn/opensource/flexunit/branches/4.x/FlexUnit4Test/fc-to-cobertura.xsl. If you’d like to see the reports generated for Hudson in action, check out http://flexunit.digitalprimates.net/view/Flex%203.2/job/FlexUnit4-Flex3.2/cobertura/. We currently only have the builds using Flex SDK 3.2 running with FlexCover since the latest version of FlexCover (0.81) only supports versions 3.0 and 3.2 of the SDK. Looks like some work has been done to integrate with Flex 4.0, so as support is added to FlexCover, I’ll add that work into the FlexUnit4 CI builds.

To use this XSLT to transform the CVR file, make sure you are using an XSLT 2.0 compatible engine (e.g. – Saxon) with your build tool of choice. Additionally, you will need to provide three paramaters to the stylesheet for it to work correctly:

  • sourcePath – A comma delimited list of absolute paths to the source directories, each excluding a trailing slash, for which the instrumented SWC/SWF was created.
  • version – The version number of FlexCover you used to generate the CVR file.
  • timestamp – The date/time in which the transformation occurred in ms from epoch. I’m using a date format of “MM/DD/yyyy HH:mm:ss.SSS’ and I’m not having any issues, but it may be ignored by the Hudson plugin.

If anyone has any suggestions on rewriting the XSLT using XSL 1.0 instead of 2.0, please let me know, I’m definitely open to refactoring it. Thus far the results look fairly consistent with a Cobertura XML report and integration with Hudson’s Cobertura plugin is working out great. Hope this helps those who are trying to tackle the FlexCover CI integration problem.

Thanks for the invitation KSC

Brian LeGros | January 17th, 2009 | programming  

Big thanks to Doug, Bill, Jim, Mike, Don, Boss boss, and everyone else who joined me for my presentation on Continuous Integration and Flex at Kennedy Space Center. I ended up running around an hour and forty minutes giving an overview of the Adobe Flex domain and continuous integration as a whole. Thank you everyone for taking the time out of your busy schedules to tough through the presentation; I hope I have failed you all equally.

As promised, below are links to the materials from the presentation that I used as well as links to other resources you may find helpful.

Subversion – http://subversion.tigris.org/
Apache Ant – http://ant.apache.org/
Flex Ant Tasks – Use the libraries included in the Flex SDK 3.2 distribution
Fluint Library and Ant Tasks – http://code.google.com/p/fluint/
mock-as3 – http://code.google.com/p/mock-as3/
Hudson – https://hudson.dev.java.net/
Example Application and Component – http://brianlegros.com/blog/files/example_apps.zip
Slides – http://brianlegros.com/blog/files/slides.pdf

If you have any questions, please don’t hesitate email @ me at brianlegros dot com.

NOTE: The Fluint test runners and reports that you saw in my presentation were using a code base that has yet to be released by the Fluint team, but will be hopefully soon. We have a lot of great working going on at the Fluint project, so I’d encourage you all to check out the Google Code site as well as the Fluint mailing list.

Getting AIR to run headless for Continuous Integration

Brian LeGros | January 7th, 2009 | programming  

Here’s the thing about proof-of-concept projects, they always get the high risk technology questions out of the way, but they never manage to expose the stupid gotchas that are coming down the line when you go to make them into a reality. Case in point, unit testing in Flex and continuous integration. In my last post, I spoke about how I got flex-mojos, ant, fluint, and Hudson all playing nice together. Please preface the following with the fact that I’m a terrible server admin, so there may be work arounds for the roadblocks I ran into, I’m just not aware of them.

So when our team went to deploy the PoC, we decided to use Windows. Our hope was that with the lack of headless support in AIR, Windows would provide us access to a windowing system even when a user isn’t authenticated thanks to the dreaded LocalSystem account. As expected, I was able to get Hudson up and running and the AIR test runner was working without issue while running as LocalSystem. I then needed to integrate a series of CI builds which we put together to automatically release our components. All of sudden, I had the need for user specific settings to interact with putty, plink, and SVN, then LocalSystem failed me. I setup a special user to run the service hosting Hudson and placed that user into the Administrator group to start; I figured once I had it working again, I’d restrict its rights … <crickets chirping>. So when I had finally gotten the automatic release builds working with the new user, I re-ran one of my previous CI builds only to find that the build would hang when the AIR runner for Fluint was executed. After hours of pouring over a solution (I even tried this registry hack for the service with no success), I decided that Windows just wasn’t going to work.

I decided to give Linux a shot and I have to say I had much better results; I chose Ubuntu for my PoC due to its simplicity for guys like me. As a nice plus, all of the SSH/SVN woes I experienced disappeared because I had a native SSH client and integration was just easy. I still had the issue however of needing to run AIR in a truly headless mode. I started with some tips I found on the Fluint mailing list and was able to get Xvfb up and running as a service. Integration with the Fluint Ant Task didn’t pan out easily though, so I again looked for another solution. I did some digging and as it turns out a lot of the Java/Swing folks had to solve the same problems we’re having to solve now before Java gained the ability to run Swing apps headlessly. I found this post on xvfb-run and it did the trick. In fact it worked out so well, that I went ahead and integrated it into the Fluint Ant task as an option. Effectively I just had it execute the AIR application with the “-a” flag so sysadmins who are picky about how xvfb-run is used may not like the lack of granularity I’ve built in, but it’s working for us. I know that FlexUnit has a similar issue since the Flash Player can’t be run in a headless-mode either, so this may be a good feature to add to the FlexUnit Ant task eventually too. On a side note, my changes to Fluint are being reviewed right now and it looks like I may get my branch merged into the next release fairly soon for anyone who is interested in finding binaries.

We’re still working to deploy on a different Linux distro at the moment, but I think we’ve finally managed to mitigate the risk of running a Flex build on a CI server for the different variations we’ve thrown together. If you see another post from me really soon, you’ll know the edge of the PoC sword got me again … stupid sneaky sword.

Continuous Integration with Maven, Flex, Fliunt, and Hudson

Brian LeGros | December 17th, 2008 | programming  

Recently I was tasked with streamlining our build process at work so we could get a continuous integration (CI) server up and running. We use the common stack of technologies found in most Flex shops (basic SDK, some libraries, and Flex Builder) as well as Maven. I ran into some challenges getting our CI process to work as we wanted, so I figured I’d go through some of the gotchas I encountered.

On the build side of things, when I came on, Maven was already in place using flex-mojos. Now I’m a big fan of the simplicity that Ant brings to the mix, but the issue of dependency management being baked into Maven makes it extremely appealing; I do like Ivy as an alternative when using Ant, but I wasn’t going to re-write the company’s build process. So we had flex-mojos building our source and producing artifacts for deployment to our team’s Maven repository, but we needed to integrate our unit tests into our build. We were using dpuint and were excited to see that fluint had been released with Ant support. Currently flex-mojos doesn’t support Fluint, although my colleagues tell me they’re working on it, so I knew I was going to have to use Ant. To start I had to get flex-mojos building my test SWF so I could use the Fluint Ant task. The Ant support in Fluint requires that you produce a module SWF that will work with their test runner written in AIR. After an hour of messing with flex-mojos, I was unable to get the compile, or test-compile, goal to do what I wanted, so I decided to use the maven-ant-run plugin to compile our tests as well.

Below is the snippet I was able to get working to compile our tests and execute the Fluint test runner:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
<properties>
   <flex.home>PATH_TO_FLEX_SDK_HOME</flex.home>
   <fluint.testrunner>PATH_TO_FLUINT_AIR_RUNNER_EXECUTABLE</fluint.testrunner>
</properties>
...
<build>
   <plugins>
      <plugin>
         <groupId>info.flex-mojos</groupId>
         <artifactId>flex-compiler-mojo</artifactId>
         <version>2.0M9</version>
         <extensions>true</extensions>
         <configuration>
            <skipTests>true</skipTests>
         </configuration>
      </plugin>
      <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-antrun-plugin</artifactId>
         <executions>
            <execution>
               <id>fluint-test-compile</id>
               <phase>test-compile</phase>
               <configuration>
                  <tasks>
                     <!-- Pull in Flex Ant Tasks -->
                     <taskdef resource="flexTasks.tasks" />
 
                     <property name="FLEX_HOME" location="${flex.home}" />
 
                     <!-- Create test-classes directory -->
                     <mkdir dir="${project.build.testOutputDirectory}" />
 
                     <mxmlc file="${project.build.testSourceDirectory}/AirRunner.mxml" 
                        output="${project.build.testOutputDirectory}/AirRunner.swf" 
                        keep-generated-actionscript="false">
 
                        <load-config filename="${FLEX_HOME}/frameworks/flex-config.xml" />
                        <source-path path-element="${FLEX_HOME}/frameworks"  />
                        <compiler.library-path dir="${FLEX_HOME}/frameworks" append="true">
                           <include name="libs" />
                        </compiler.library-path>
                        <compiler.library-path dir="${project.build.directory}/.." append="true">
                           <include name="libs" />
                        </compiler.library-path>
                        <compiler.library-path dir="${project.build.directory}" append="true">
                           <include name="*.swc" />
                        </compiler.library-path>
                     </mxmlc>      
                  </tasks>
               </configuration>
               <goals>
                  <goal>run</goal>
               </goals>
            </execution>
            <execution>
               <id>fluint-test-run</id>
               <phase>test</phase>
               <configuration>
                  <tasks>
                     <!-- Pull in Fluint Ant Task -->
                     <taskdef name="fluint" classname="net.digitalprimates.ant.tasks.fluint.Fluint" />     
 
                     <property name="test.report.loc" location="${project.build.directory}/surefire-reports" />
 
                     <!-- Create reporting directory -->
                     <mkdir dir="${test.report.loc}" />
 
                     <fluint debug="true" 
                        headless="true"
                        testRunner="${fluint.testrunner}" 
                        outputDir="${test.report.loc}" 
                        workingDir="${project.build.testOutputDirectory}">
 
                        <fileset dir="${project.build.testOutputDirectory}">
                           <include name="**/AirRunner.swf"/>
                        </fileset>
                     </fluint>      
                  </tasks>
               </configuration>
               <goals>
                  <goal>run</goal>
               </goals>
            </execution>
         </executions>
         <dependencies>
            <dependency>
               <groupId>org.apache.ant</groupId>
               <artifactId>ant</artifactId>
               <version>1.7.0</version>
            </dependency>
            <dependency>
               <groupId>flex.ant</groupId>
               <artifactId>flexTasks</artifactId>
               <version>1.0.0</version>
            </dependency>
            <dependency>
               <groupId>net.digitalprimates</groupId>
               <artifactId>FluintAnt</artifactId>
               <version>1.0.1-SNAPSHOT</version>
            </dependency>
         </dependencies>
      </plugin>
   </plugins>
</build>

Couple of things to point out about the above snippet:

  • There are two dependencies on resources being available on the disk, the Flex SDK (flex.home property) and the Fluint Air Runner (fluint.testrunner property).
  • Using Ant I had to create the “test-classes” and “surefire-report” directory to stick with Maven conventions.
  • We adhered to the convention of naming our test runners for the Fluint Ant task “AirRunner.mxml” so we could use this snippet in a parent POM.
  • I had to change the dependency for the maven-ant-run plugin from Ant 1.6.5, which is the default, to Ant 1.7.0, which is required by the Fluint Ant task.

You may also notice that I’m using snapshot versions of the Fluint library and the Fluint Ant task. I ended up having to change the source of the Fluint library, Ant task, and AIR runner to get Fluint to work as I wanted it to with my build. Fluint is an awesome unit testing library, it just needed some tweaks. I made changes to fix the following:

  • The XML output from the Fluint AIR runner wasn’t compliant with what the Surefire Report plugin was expecting.
  • The name of output file from the Fluint AIR runner was in the convention “TEST-*.xml” which the SureFire reporting plugin expects.
  • Fluint had the notion of an error and failure being separate but it wasn’t implemented for the Flash or AIR test runners.
  • The Ant task didn’t allow the user to specify a working directory so that the AIR runner could be launched from the appropriate directory.

I later found out that AIR and relative paths don’t play nicely together (= at all, unless there is helper code), so we also had to re-factor our test suites to NOT rely on any assets unless they are embedded or referenced with absolute URIs. This made the change to the Fluint Ant task kinda worthless, but I kept it in anyway for when AIR works in the future. Additionally, it’s important to note, that the “headless” mode in the Fluint AIR runner is really just a minimized window that closes after the XML report is written; if you plan on running your CI build on an OS without a windowing solution, then FLuint will not work since AIR does not support running in a true headless mode. On a side note, my changes should address issues #5 and #22 on the Fluint Google Code site; issue #21 should be solved by the Ant dependency fix I spoke about above and issue #20 is just a matter of the fluintAnt15.jar being compiled with Java 1.6 instead of 1.5, I believe. I’ve submitted these fixes along with my code to the Fluint guys in an email, just haven’t heard anything back yet.

So at this point I had the build process working as I wanted such that I could run “mvn clean deploy site” and find a snapshot in our team’s maven repository and site documentation generated. On to CI. I have used CruiseControl many times in the past, but the idea of being entrenched in XML, especially with all the Maven and Ant fun, was discouraging so I decided to give Hudson a try this time around. Wow … Hudson is amazing improvement over CruiseControl. Completely UI driven, I have yet to find myself digging through XML and best of all. The post-build support feel a little lighter than CruiseControl’s, but I think that’s just because I haven’t come across an X10 plugin so we can get a stop light or glowing orb setup. Hudson provides trend reporting on builds and unit tests as well as embedded reporting for unit tests and xdoclet-like documentation; it also has tons of Groovy integration which I really like (not that we’re using it … yet). Initially I chose to go with the pure Maven build for our projects, but I then decided to switch back to the free-style build; I couldn’t get trend reporting for unit tests to work with the pure Maven build, so I think my conventions are off for the Fluint reporting. In the free-style build I set the “site” directory as the Javadoc location and the “surefire-report” directory as the test report directory. Even though there is more configuration in a free-style build, it was simpler in the short run to get what I wanted in Hudson running. If unit test trend reporting isn’t as important to your CI needs, then the pure maven build may be more along the lines of what you’d like to use so that you can get the additional build trigger “Build whenever a SNAPSHOT dependency is built”. On a side note, I’m working towards using the FlexCover support in flex-mojos to make our site reports complete, but haven’t had a chance to dive in yet.

I hope some of the hurdles I encountered can help if you’re trying to get your CI process working with Flex. The flex-mojos, Fluint, and Hudson guys have some good walkthroughs/tutorials to cover the details I left out. I’m always up for suggestions, so definitely feel free to rip into my solutions. :)