Continuous integration - setup

We have the following machines:

  1. CI server: http://qkcoi0001:8080 with hudson
  2. subversion server: http://qksvn0001
  3. report server: \\qkfil0001\HUDSON\

Installing hudson

  1. su -
  2. yum install ant-jsch
  3. yum install subversion
  4. useradd -d /local/home/hudson hudson
  5. passwd hudson
  6. su - hudson
  7. wget http://hudson.gotdns.com/latest/hudson.war
  8. chmod 755 hudson.war
  9. exit
  10. vi /etc/init.d/hudson
    # hudson    Start/Stop the Hudson Continuous Integration server.
    #
    # chkconfig: 345 91 10
    # description: Hudson is a Continuous Integration server. \
    #              It monitors a source code repository and triggers builds \
    #              when it detects any changes. See https://hudson.dev.java.net/ \
    #              for more details.
    # processname: hudson
    # pidfile: /var/run/hudson.pid
    
    # Source function library.
    . /etc/rc.d/init.d/functions
    
    # Get config.
    . /etc/sysconfig/network
    
    # Check that networking is up.
    [ "${NETWORKING}" = "no" ] && exit 0
    
    HUDSON_USER=hudson
    
    start(){
     echo -n $"Starting Hudson service: " 
     su - $HUDSON_USER -c "nohup nice java -jar /home/hudson/hudson.war > ~/hudson.log 2>&1" 
     RETVAL=$?
     echo
    }
    
    stop(){
     action $"Stopping Hudson service: " 
     su - $HUDSON_USER -c "kill `ps -ef | grep hudson.war | grep -v grep | awk '{ print $2 }'`" 
     RETVAL=$?
     echo
    }
    
    status(){
     numproc=`ps -ef | grep hudson.war | grep -v "grep hudson.war" | wc -l`
     if [ $numproc -gt 0 ]; then
      echo "Hudson is running..." 
      else
      echo "Hudson is stopped..." 
     fi
    }
    
    restart(){
      stop
      start
    }
    
    # See how we were called.
    case "$1" in
    start)
     start
     ;;
    stop)
     stop
     ;;
    status)
     status
     ;;
    restart)
     restart
     ;;
    *)
     echo $"Usage: $0 {start|stop|status|restart}" 
     exit 1
    esac
    
    exit 0
    

    Note: hudson.log has to be rotated
  11. chmod a+x /etc/init.d/hudson
  12. chkconfig --add hudson

Configure Hudson: create a new build,

  1. Discard Old Builds; Max # of builds to keep: 5
  2. Source Code Management: Subversion; Repository URL: http://qksvn0001/svn/enrd/branches/phase3
  3. Build Triggers: Poll SCM; Schedule: 0 * * * *
  4. Build: Invoke Ant; Targets: runAllSeleniumTests

single server approach: Xvfb

  1. yum -y install xorg-x11-server-Xvfb firefox ImageMagick xorg-x11-font*
  2. su -c "wget http://selenium.googlecode.com/files/selenium-server-standalone-2.3.0.jar" - hudson
  3. firefox has to be made less secure:
    1. copy cert8.db and cert_override.txt from a firefox profile that has all the relevant certificates accepted
    2. create in the firefox profile file user.js:
      cd [user profile];vi user.js
      user_pref("security.warn_entering_secure", false);
      user_pref("security.warn_entering_weak", false);
      user_pref("security.warn_leaving_secure", false);
      user_pref("security.warn_submit_insecure", false);
      user_pref("security.warn_viewing_mixed", false);
  4. test that it works:
    1. mount a folder with tests in it
    2. Xvfb :1 -screen 0 1024x768x16 2>&1 >/dev/null &
    3. java -jar selenium-server-standalone-2.3.0.jar -htmlSuite *firefox http://enrd.ec.europa.eu/ <test folder>/testsMyEnrd.htm <test folder>/results
    4. import -window root <test folder>/results/screenie.png
  5. add to build.xml the targets:
        <!-- seleniumHQ tests -->
        <target name="-runSeleniumTest">
            <echo>Starting test suite ${testSuite}</echo>
            <java jar="${jarDir}/selenium-server-standalone.jar" 
                fork="true" 
                resultproperty="test.result" 
                errorProperty="test.failure" 
                timeout="600000"> 
                <arg line="-htmlSuite &quot;*firefox&quot;"/>
                <arg line="&quot;${baseURL}&quot;"/>
                <arg line="&quot;${testDir}/${testSuite}&quot;"/>
                <arg line="&quot;${reportDir}/${testSuite}.results.html&quot;"/>
                <arg line="-port ${testPort}"/>
            </java>
            <condition property="test.failed">
                <and>
                    <isset property="test.result"/>
                    <not><equals arg1="${test.result}" arg2="0" /></not>
                </and>
            </condition>
        </target>
        <target name="-try-test" depends="-runSeleniumTest" if="test.failed">
            <!--If there is a test error, capture a screenshot and stop the build-->
            <exec executable="import">
                <arg line="-window root ${reportDir}/screen.png"/>
            </exec>
            <fail message="${test.result}: '${test.failure}'" />
        </target>
    
        <target name="runAllSeleniumTests" depends="time">
            <property name="jarDir" value="${user.home}" />
            <property name="testDir" value="tests/" />
            <property name="reportDir" value="${user.home}/reports/${DSTAMP}${TSTAMP}" /><!-- note: this folder must be mounted-->
            <delete dir="${reportDir}" />
            <mkdir dir="${reportDir}"/>
            <echo>Running SeleniumHQ tests. Results in ${reportDir}</echo>
    
            <parallel>
                <!--The first test to fail stops the build. Add any new test suites here. -->
                <!-- It would be better to use foreach, but:
                    - how to add the optional package?
                    - how to generate the different ports for every test?
                -->
                <sequential>
                    <antcall target="-try-test">
                        <!--testMyEnrd.html-->
                        <param name="testSuite" value="testMyEnrd.html" />
                        <param name="baseURL" value="http://webgate.enrd.eu/agri_enrd_d/myenrd/" />
                        <param name="testPort" value="4444" />
                    </antcall>
                </sequential>
                <sequential>
                    <antcall target="-try-test">
                        <!--testRDP.html-->
                        <param name="testSuite" value="testRDP.html" />
                        <param name="baseURL" value="http://webgate.enrd.eu/agri_enrd_d/myenrd/" />
                        <param name="testPort" value="4445" />
                    </antcall>
                </sequential>
            </parallel>
        </target>
    

distributed approach: using Selenium Grid

Selenium Grid takes care of starting up the various distributed clients. Grid 2.0 is now included in selenium

  1. rpm -Uvh http://plone.lucidsolutions.co.nz/linux/centos/images/jpackage-utils-compat-el5-0.0.1-1.noarch.rpm
  2. cd /etc/yum.repos.d;wget 'http://www.jpackage.org/jpackage50.repo'
  3. su hudson -
  4. wget http://selenium.googlecode.com/files/selenium-server-standalone-2.3.0.jar
  5. java -jar selenium-server-standalone-2.3.0.jar -role hub -port 5555
    We can now check that it works going on http://<servername>:5555/grid/console, then stop the process and create the init script:
  6. ln -s selenium-server-standalone-2.3.0.jar selenium.last
  7. exit
  8. vi /etc/init.d/selenium
    # selenium#
    # chkconfig: 345 91 10
    # description: http://seleniumhq.org/docs/
    # processname: selenium
    # pidfile: /var/run/selenium.pid
    
    # Source function library.
    . /etc/rc.d/init.d/functions
    
    # Get config.
    . /etc/sysconfig/network
    
    # Check that networking is up.
    [ "${NETWORKING}" = "no" ] && exit 0
    
    HUDSON_USER=hudson
    COMMAND="java -jar selenium.last -role hub -port 5555 > ~/selenium.log 2>&1 &" 
    
    start(){
     echo -n $"Starting Selenium: " 
     su - $HUDSON_USER -c $COMMAND
     RETVAL=$?
     echo
    }
    
    stop(){
     action $"Stopping Selenium: " 
     su - $HUDSON_USER -c "kill `ps -ef | grep selenium | grep -v grep | awk '{ print $2 }'`" 
     RETVAL=$?
     echo
    }
    
    status(){
     numproc=`ps -ef | grep selenium-server-standalone.jar | grep -v "grep selenium" | wc -l`
     if [ $numproc -gt 0 ]; then
      echo "Selenium is running..." 
      else
      echo "Selenium is stopped..." 
     fi
    }
    
    restart(){
      stop
      start
    }
    
    # See how we were called.
    case "$1" in
    start)
     start
     ;;
    stop)
     stop
     ;;
    status)
     status
     ;;
    restart)
     restart
     ;;
    *)
     echo $"Usage: $0 {start|stop|status|restart}" 
     exit 1
    esac
    
    exit 0
    
  9. chkconfig --add selenium
  10. reboot

Client machine

  1. install java: https://cds.sun.com/is-bin/INTERSHOP.enfinity/WFS/CDS-CDS_Developer-Site/en_US/-/USD/ViewFilteredProducts-SingleVariationTypeFilter
  2. install ant: http://code.google.com/p/winant/
  3. download the same version of selenium grid
    We can't use a windows service because we'll need to use the browsers, so a user session must be active for selenium to work.
    On a new terminal:
  4. java -jar selenium-server-standalone-2.3.0.jar -role rc -hub http://qkcoi0001:5555/grid/register -port 5555
    Control on http://qkcoi0001:5555/grid/console that it works; kill terminal
  5. create a batch file that we'll launch to have the tests ready to run. On windows:
    set hub=http://qkcoi0001:5555
    set selenium=selenium-server-standalone-2.3.0.jar
    start Java java -jar %selenium% -role rc -hub %hub%/grid/register -port 5555
    
    REM check on %hub%/console
    
    pause

Grid works with FF, IE, Chrome, Safari; defaults to 5 FF, 5 Chrome, 1 IE instances max.

Run tests

login test selenium test: