Sunday, September 1, 2013

How to execute the maven-karma-plugin in a CloudBees Jenkins build job (by installing NodeJs and Karma)

I recently faced the task of getting my new JavaScript unit test suite implemented using Karma to execute as part of a Maven build. The maven-karma-plugin was the obvious choice and worked like a charm on my own machine. A few tricks was however necessary to make it work in the Jenkins Maven build job executed on CloudBees. Many thanks to blogs mentioned in the bottom and CloudBees support.

I added a script, which installs NodeJS and Karma if not already installed. This was done by adding a Pre build step of type 'Execute Shell'. Notice that I am also installing phantomjs to execute the tests using a headless browser.

# install nodejs, if using cloudbees (and if not already installed)
curl -s -o use-node https://repository-cloudbees.forge.cloudbees.com/distributions/ci-addons/node/use-node
NODE_VERSION=0.10.13 source ./use-node

ARCH=`uname -m`
node_name=node-${NODE_VERSION}-${ARCH}

# install phantomjs, karma
[ -d /scratch/jenkins/addons/node/$node_name/lib/node_modules/phantomjs ] || npm install -g phantomjs
[ -d /scratch/jenkins/addons/node/$node_name/lib/node_modules/karma ] || npm install -g karma
[ -d /scratch/jenkins/addons/node/$node_name/lib/node_modules/karma-junit-reporter ] || npm install -g karma-junit-reporter
[ -d /scratch/jenkins/addons/node/$node_name/lib/node_modules/karma-phantomjs-launcher ] || npm install -g karma-phantomjs-launcher

Note: I also had to add karma-junit-reporter and the karma-phantomjs-launcher plugins to the Karma configuration (karma.conf.js). My plugin configuration looked like this: 

plugins : [ 'karma-jasmine', 'karma-chrome-launcher', 'karma-firefox-launcher', 'karma-junit-reporter', 'karma-phantomjs-launcher' ]

Now the tricky part was that the system path configured in a pre build step was not available in the main build step. I learned that entried in the $HOME/bin folder would be available in the main build job, and I therefore added the following to the bottom of the script (in the pre build step):

[ -d $HOME/bin ] || mkdir $HOME/bin
[ -f $HOME/bin/karma ] || ln -s /scratch/jenkins/addons/node/$node_name/bin/karma $HOME/bin/karma
[ -f $HOME/bin/node ] || ln -s /scratch/jenkins/addons/node/$node_name/bin/node $HOME/bin/node

Next was to execute the maven-karma-plugin. As I had a Maven build job, there was no possibility to configure a file pattern matching the Karma unit test reports. Jenkins would initially therefore not collect the reports and include them in the unit test output. I solved this by first configuring Karma (karma.conf.js) to place the reports in the target/surefire-reports folder:

junitReporter : {
outputFile : 'target/surefire-reports/karmaUnit.xml'
},

and next configuring the maven-karma-plugin to execute just before unit tests in the Maven phase process-test-classes:

<plugin>
  <groupId>com.kelveden</groupId>
  <artifactId>maven-karma-plugin</artifactId>
  <version>1.3</version>
  <configuration>
    <configFile>${basedir}/src/test/resources/config/karma.conf.js</configFile>
    <browsers>PhantomJS</browsers>
  </configuration>
  <executions>
    <execution>
      <id>karma</id>
      <goals>
        <goal>start</goal>
      </goals>
      <!-- execute karma before test phase to let Jenkins collect the target/surefire-reports/karmaUnit.xml -->
      <phase>process-test-classes</phase>
    </execution>
  </executions>
</plugin>

Voila. Karma unit tests was now executed on my Jenkins build server in CloudBees and JavaScript unit test reports are available through the Web interface.

I've found inspiration in these:

Friday, August 16, 2013

Installing Node.js, NPM and Karma on Ubuntu 11.10


I've seen many receipes for how to install Node.js and Karma on Ubuntu 11.10, but none as  simple as this.

Download latest Node.js from http://nodejs.org/. Unzip the .tar.gz file into some directory (from here called nodeJsDir).

Open a terminal and type in the following commands:

cd nodeJsDir
./configure
make
sudo make install

There after simple install karma by executing the command

sudo npm install -g karma

Karma can now be started executing

karma start

Friday, January 18, 2013

Solved bad_record_mac error for Jenkins/Hudson on Tomcat

I have just updated Lund&Bendsens Continuous Integration server from Hudson version 2.2.1 to version 3.0.0. The upgrade process itself gave no troubles, but all jobs checking out from SubVersion failed with the known bad_record_mac error:


org.tmatesoft.svn.core.SVNException: svn: E175002: Received fatal alert: bad_record_mac
svn: E175002: PROPFIND request failed on '/xxxxxxxx/trunk'
    at org.tmatesoft.svn.core.internal.wc.SVNErrorManager.error(SVNErrorManager.java:64)
    at org.tmatesoft.svn.core.internal.wc.SVNErrorManager.error(SVNErrorManager.java:51)
    at org.tmatesoft.svn.core.internal.io.dav.DAVUtil.findStartingProperties(DAVUtil.java:136)
    at org.tmatesoft.svn.core.internal.io.dav.DAVUtil.getBaselineProperties(DAVUtil.java:226)
    at org.tmatesoft.svn.core.internal.io.dav.DAVUtil.getBaselineInfo(DAVUtil.java:184)
    at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.fetchRepositoryRoot(DAVConnection.java:110)
    at org.tmatesoft.svn.core.internal.io.dav.DAVRepository.doGetFullPath(DAVRepository.java:794)
    at org.tmatesoft.svn.core.internal.io.dav.DAVRepository.info(DAVRepository.java:740)
    at hudson.scm.SubversionSCM$CheckOutTask.checkClockOutOfSync(SubversionSCM.java:816)
    at hudson.scm.SubversionSCM$CheckOutTask.invoke(SubversionSCM.java:795)
    at hudson.scm.SubversionSCM$CheckOutTask.invoke(SubversionSCM.java:774)
    at hudson.FilePath.act(FilePath.java:791)
    at hudson.FilePath.act(FilePath.java:773)
    at hudson.scm.SubversionSCM.checkout(SubversionSCM.java:766)
    at hudson.scm.SubversionSCM.checkout(SubversionSCM.java:709)
    at hudson.model.AbstractProject.checkout(AbstractProject.java:1515)
    at hudson.model.AbstractBuild$AbstractRunner.checkout(AbstractBuild.java:521)
    at hudson.model.AbstractBuild$AbstractRunner.run(AbstractBuild.java:428)
    at hudson.model.Run.run(Run.java:1390)
    at hudson.maven.MavenModuleSetBuild.run(MavenModuleSetBuild.java:414)
    at hudson.model.ResourceController.execute(ResourceController.java:81)
    at hudson.model.Executor.run(Executor.java:137)
Caused by: javax.net.ssl.SSLException: Received fatal alert: bad_record_mac
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:190)
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1774)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:954)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1138)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.java:632)
    at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.java:59)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.sendData(HTTPConnection.java:235)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPRequest.dispatch(HTTPRequest.java:168)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:368)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:286)
    at org.tmatesoft.svn.core.internal.io.dav.http.HTTPConnection.request(HTTPConnection.java:274)
    at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.performHttpRequest(DAVConnection.java:704)
    at org.tmatesoft.svn.core.internal.io.dav.DAVConnection.doPropfind(DAVConnection.java:132)
    at org.tmatesoft.svn.core.internal.io.dav.DAVUtil.getProperties(DAVUtil.java:73)
    at org.tmatesoft.svn.core.internal.io.dav.DAVUtil.getResourceProperties(DAVUtil.java:79)
    at org.tmatesoft.svn.core.internal.io.dav.DAVUtil.getStartingProperties(DAVUtil.java:103)
    at org.tmatesoft.svn.core.internal.io.dav.DAVUtil.findStartingProperties(DAVUtil.java:125)
    ... 19 more



I tried different solution approaches, but what work was a simple update from JDK 6 to JDK 7. There was a catch though to the solution. We had installed Tomcat as a Windows Service and I updated the service configuration to use JDK 7 as JAVA_HOME. It was however not enough. I also had to update a service jvm configuration, which pointed a the JDK 6 jvm. I therefore ended up updating the Tomcat Windows Service as follows:

TOMCAT_HOME\bin>tomcat7 //US//Tomcat7 --JavaHome="C:\Program Files\Java\jdk1.7.0" --Jvm="C:\Program Files\Java\jdk1.7.0\jre\bin\server\jvm.dll"

More about the Tomcat service scripts can be seen here: http://tomcat.apache.org/tomcat-7.0-doc/windows-service-howto.html.

Inspiration to the JDK upgrade came from https://issues.jenkins-ci.org/browse/JENKINS-11985. This issue also indicates that the problem resides in the SubVersion plugin, which is used on both Hudson and Jenkins. The above fix should therefore also hold for Jenkins installation on Tomcat.