continuous integration testing for plone using hudson
DESCRIPTION
http://db.tt/pdKBTHCTRANSCRIPT
Continuous Integration Testing with Hudson
Wednesday, October 27, 2010
Continuous Integration
Wednesday, October 27, 2010
Continuous Integration
• Extreme Programming principle
• Martin Fowlerhttp://www.martinfowler.com/articles/continuousIntegration.html
Wednesday, October 27, 2010
Continuous Integration• Maintain a Source
Repository
• Automate the Build
• Make the Build Self-Testing
• Everyone Commits Every Day
• Every Commit Should Be Built
• Keep the Build Fast
• Test in a Clone of the Production Environment
• Make it Easy to Get the Latest Deliverables
• Everyone Can See the Results of the Latest Build
• Automate Deployment
Wednesday, October 27, 2010
Essentially
• Commit your code
• Test the crap out of it
• Regressions are bad
• Assign blame
• Shame is a great motivator
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Hudson vs Buildbot?
Wednesday, October 27, 2010
*shrug*
Wednesday, October 27, 2010
Hudson (Pros)
Wednesday, October 27, 2010
Easy to install/run
%> java -jar hudson.war
Wednesday, October 27, 2010
Easy to Configure
• Create
• Modify
• Manage
• All TTW
Wednesday, October 27, 2010
Frequent Releases~ 1 / Week
Wednesday, October 27, 2010
Inline Documentation
Wednesday, October 27, 2010
Plugins
Wednesday, October 27, 2010
Hudson (Cons)
Wednesday, October 27, 2010
It’s Java.
Wednesday, October 27, 2010
It’s Java.1. It eats resources
2. I don’t know how to write plugins
Wednesday, October 27, 2010
Hudson
Wednesday, October 27, 2010
Project Layout
Wednesday, October 27, 2010
Project Layout
• Project/Job
Wednesday, October 27, 2010
Project Layout
• Project/Job
• Build
Wednesday, October 27, 2010
Project Layout
• Project
• Build
• Trigger
Wednesday, October 27, 2010
Triggers
• Other projects
• Remote trigger
• Periodically
• SCM polling
Wednesday, October 27, 2010
Project Layout
• Project/Job
• Build
• Trigger
• Build Step
Wednesday, October 27, 2010
Build Steps
• Shell script
• Python script
• Ant
• Maven
Wednesday, October 27, 2010
Project Layout
• Project/Job
• Build
• Trigger
• Build Step
• Post-Build Action
Wednesday, October 27, 2010
Post-Build Actions
• Trigger builds
• Archive results
• Generate reports
• Send email
Wednesday, October 27, 2010
Build Status
Wednesday, October 27, 2010
Build Status
• Successful
• Unstable
• Failed
Wednesday, October 27, 2010
Build Stability
Wednesday, October 27, 2010
Filesystem Layout
Wednesday, October 27, 2010
Filesystem Layouthudson /
config.xmlhudson.plugins.*.xmljobs /
myjob / builds /
2010-10-21_11-56-402010-10-21_12-20-26
config.xmlworkspace /
Wednesday, October 27, 2010
Filesystem Layouthudson /
config.xmlhudson.plugins.*.xmljobs /
myjob / builds /
2010-10-21_11-56-402010-10-21_12-20-26
config.xmlworkspace /
Wednesday, October 27, 2010
Filesystem Layouthudson /
config.xmlhudson.plugins.*.xmljobs /
myjob / builds /
2010-10-21_11-56-402010-10-21_12-20-26
config.xmlworkspace /
Wednesday, October 27, 2010
Filesystem Layouthudson /
config.xmlhudson.plugins.*.xmljobs /
myjob / builds /
2010-10-21_11-56-402010-10-21_12-20-26
config.xmlworkspace /
Wednesday, October 27, 2010
Plugins
Wednesday, October 27, 2010
Plugins
• Green Balls
• Python
• Subversion
• Trac
• Warnings
• Violations
• Cobertura
• Disk Usage
• Chuck Norris
Wednesday, October 27, 2010
Plugins
• Green Balls
• Python
• Subversion
• Trac
• Warnings
• Violations
• Cobertura
• Disk Usage
• Chuck Norris
Wednesday, October 27, 2010
Plone Integration
Wednesday, October 27, 2010
Buildout & mr.developer
Wednesday, October 27, 2010
buildout.cfg[buildout]...extensions = mr.developer
Wednesday, October 27, 2010
buildout.cfg[buildout]...extensions = mr.developersources = sources
[sources]fsd.core = svn https:.../weblion/fsd.core/trunkfsd.membrane = svn https:.../weblion/fsd.membrane/trunk
Wednesday, October 27, 2010
mr.developer
• bin/develop checkout
• bin/develop status
• bin/develop update
• bin/develop activate (deactivate)
• bin/develop reset
• bin/develop purge
Wednesday, October 27, 2010
buildout.cfg[buildout]...extensions = mr.developersources = sourcesauto-checkout = fsd.core fsd.membrane
[sources]fsd.core = svn https:.../weblion/fsd.core/trunkfsd.membrane = svn https:.../weblion/fsd.membrane/trunk
Wednesday, October 27, 2010
buildoutbin/
buildoutdevelop...
bootstrap.pybuildout.cfg...src/
fsd.corefsd.membrane
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Tests
Wednesday, October 27, 2010
Tests
• bin/test returns text
• Hudson wants JUnit (XML) format
• collective.xmltestreport
Wednesday, October 27, 2010
hudson.cfg[buildout]extends = buildout.cfg
parts += xmltestrunner
[xmltestrunner]recipe = collective.xmltestreporteggs = ${test:eggs}defaults = ${test:defaults} + ['--xml']
Wednesday, October 27, 2010
hudson.cfg[buildout]extends = buildout.cfg
parts += xmltestrunner
[xmltestrunner]recipe = collective.xmltestreporteggs = ${test:eggs}defaults = ${test:defaults} + ['--xml']
Wednesday, October 27, 2010
hudson.cfg[buildout]extends = buildout.cfg
parts += xmltestrunner
[xmltestrunner]recipe = collective.xmltestreporteggs = ${test:eggs}defaults = ${test:defaults} + ['--xml']
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Test Coverage
Wednesday, October 27, 2010
Test Coverage
[coverage]recipe = zc.recipe.eggeggs = coverageinitialization = sys.argv = sys.argv[:] + ['run', 'bin/xmltestrunner', '-k', '-q', '--xml']
Wednesday, October 27, 2010
Test Coverage[report]recipe = zc.recipe.eggeggs = coveragescripts = coverage=reportinitialization = eggs = '${buildout:eggs-directory}' bin = '${buildout:directory}/bin' exclude = '--omit=' + ','.join([eggs, sys.prefix, bin]) sys.argv = sys.argv[:] + ['xml', '-i', exclude, include]
Wednesday, October 27, 2010
Test Coverage
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Code Analysis
Wednesday, October 27, 2010
Code Analysis
• zptlint
• pyflakes
• pylint
• jslint
Wednesday, October 27, 2010
zptlint
Wednesday, October 27, 2010
zptlint
• http://pypi.python.org/pypi/zptlint
• Scan page templates for parser and output errors
Wednesday, October 27, 2010
zptlint
[zptlint]recipe = zc.recipe.eggeggs = zptlintentry-points = zptlint=zptlint:run
Wednesday, October 27, 2010
zptlint
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal" xmlns:metal="http://xml.zope.org/namespaces/metal" lang="en" metal:use-macro="context/main_template/macros/master"><body> <metal:fill fill-slot="content-core"> <div tal:content="structure view/context/text/output"> <h2>People</h2> <div tal:content="structure context/@@people" /> </metal:fill></body></html>
Wednesday, October 27, 2010
zptlint
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal" xmlns:metal="http://xml.zope.org/namespaces/metal" lang="en" metal:use-macro="context/main_template/macros/master"><body> <metal:fill fill-slot="content-core"> <div tal:content="structure view/context/text/output"> <h2>People</h2> <div tal:content="structure context/@@people" /> </metal:fill></body></html>
Wednesday, October 27, 2010
zptlint
%> bin/zptlint src/.../view.pt
Wednesday, October 27, 2010
zptlint
%> bin/zptlint src/.../view.pt
*** Error in: src/.../view.pt <class 'zope.tal.taldefs.TALError'>: TAL attributes on <div> require explicit </div> , at line 12, column 9
Wednesday, October 27, 2010
Parsing Log Messages
• Warnings plug-in
• Regular expression
• Groovy script (groovy.codehaus.org)
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Priorities
• HIGH
• NORMAL
• LOW
Wednesday, October 27, 2010
zptlint[zptlint-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -e zptlint.log ]; then echo "Old zptlint.log file removed" rm zptlint.log fi echo "Running zptlint-test" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find $pkg -regex ".*\.[c|z]?pt" | xargs -r bin/zptlint | perl -p -e 's/\s+$/ /g;s/\s+/ /g;s/\*{3}s?/\n/g' >> zptlint.log doneoutput = ${buildout:directory}/bin/zptlint-testmode = 755
Wednesday, October 27, 2010
zptlint[zptlint-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -e zptlint.log ]; then echo "Old zptlint.log file removed" rm zptlint.log fi echo "Running zptlint-test" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find $pkg -regex ".*\.[c|z]?pt" | xargs -r bin/zptlint | perl -p -e 's/\s+$/ /g;s/\s+/ /g;s/\*{3}s?/\n/g' >> zptlint.log doneoutput = ${buildout:directory}/bin/zptlint-testmode = 755
Wednesday, October 27, 2010
zptlint[zptlint-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -e zptlint.log ]; then echo "Old zptlint.log file removed" rm zptlint.log fi echo "Running zptlint-test" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find $pkg -regex ".*\.[c|z]?pt" | xargs -r bin/zptlint | perl -p -e 's/\s+$/ /g;s/\s+/ /g;s/\*{3}s?/\n/g' >> zptlint.log doneoutput = ${buildout:directory}/bin/zptlint-testmode = 755
Wednesday, October 27, 2010
zptlint[zptlint-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -e zptlint.log ]; then echo "Old zptlint.log file removed" rm zptlint.log fi echo "Running zptlint-test" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find $pkg -regex ".*\.[c|z]?pt" | xargs -r bin/zptlint | perl -p -e 's/\s+$/ /g;s/\s+/ /g;s/\*{3}s?/\n/g' >> zptlint.log doneoutput = ${buildout:directory}/bin/zptlint-testmode = 755
Wednesday, October 27, 2010
zptlint[zptlint-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -e zptlint.log ]; then echo "Old zptlint.log file removed" rm zptlint.log fi echo "Running zptlint-test" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find $pkg -regex ".*\.[c|z]?pt" | xargs -r bin/zptlint | perl -p -e 's/\s+$/ /g;s/\s+/ /g;s/\*{3}s?/\n/g' >> zptlint.log doneoutput = ${buildout:directory}/bin/zptlint-testmode = 755
Wednesday, October 27, 2010
zptlint[buildout]...# A list of package locations to be examined # by Hudsonpackage-directories = src/fsd.core/fsd/core src/fsd.membrane/fsd/membrane
Wednesday, October 27, 2010
zptlint[zptlint-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -e zptlint.log ]; then echo "Old zptlint.log file removed" rm zptlint.log fi echo "Running zptlint-test" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find $pkg -regex ".*\.[c|z]?pt" | xargs -r bin/zptlint | perl -p -e 's/\s+$/ /g;s/\s+/ /g;s/\*{3}s?/\n/g' >> zptlint.log doneoutput = ${buildout:directory}/bin/zptlint-testmode = 755
Wednesday, October 27, 2010
zptlint[zptlint-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -e zptlint.log ]; then echo "Old zptlint.log file removed" rm zptlint.log fi echo "Running zptlint-test" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find $pkg -regex ".*\.[c|z]?pt" | xargs -r bin/zptlint | perl -p -e 's/\s+$/ /g;s/\s+/ /g;s/\*{3}s?/\n/g' >> zptlint.log doneoutput = ${buildout:directory}/bin/zptlint-testmode = 755
Wednesday, October 27, 2010
zptlint[zptlint-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -e zptlint.log ]; then echo "Old zptlint.log file removed" rm zptlint.log fi echo "Running zptlint-test" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find $pkg -regex ".*\.[c|z]?pt" | xargs -r bin/zptlint | perl -p -e 's/\s+$/ /g;s/\s+/ /g;s/\*{3}s?/\n/g' >> zptlint.log doneoutput = ${buildout:directory}/bin/zptlint-testmode = 755
Wednesday, October 27, 2010
zptlint[zptlint-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -e zptlint.log ]; then echo "Old zptlint.log file removed" rm zptlint.log fi echo "Running zptlint-test" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find $pkg -regex ".*\.[c|z]?pt" | xargs -r bin/zptlint | perl -p -e 's/\s+$/ /g;s/\s+/ /g;s/\*{3}s?/\n/g' >> zptlint.log doneoutput = ${buildout:directory}/bin/zptlint-testmode = 755
Wednesday, October 27, 2010
zptlint[zptlint-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -e zptlint.log ]; then echo "Old zptlint.log file removed" rm zptlint.log fi echo "Running zptlint-test" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find $pkg -regex ".*\.[c|z]?pt" | xargs -r bin/zptlint | perl -p -e 's/\s+$/ /g;s/\s+/ /g;s/\*{3}s?/\n/g' >> zptlint.log doneoutput = ${buildout:directory}/bin/zptlint-testmode = 755
Wednesday, October 27, 2010
zptlint[zptlint-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -e zptlint.log ]; then echo "Old zptlint.log file removed" rm zptlint.log fi echo "Running zptlint-test" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find $pkg -regex ".*\.[c|z]?pt" | xargs -r bin/zptlint | perl -p -e 's/\s+$/ /g;s/\s+/ /g;s/\*{3}s?/\n/g' >> zptlint.log doneoutput = ${buildout:directory}/bin/zptlint-testmode = 755
Wednesday, October 27, 2010
zptlint[zptlint-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -e zptlint.log ]; then echo "Old zptlint.log file removed" rm zptlint.log fi echo "Running zptlint-test" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find $pkg -regex ".*\.[c|z]?pt" | xargs -r bin/zptlint | perl -p -e 's/\s+$/ /g;s/\s+/ /g;s/\*{3}s?/\n/g' >> zptlint.log doneoutput = ${buildout:directory}/bin/zptlint-testmode = 755
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
pyflakes
Wednesday, October 27, 2010
pyflakes
• Python syntax checking
• Find common errors quickly
• Doesn’t attempt to run Python code
Wednesday, October 27, 2010
pyflakes
[pyflakes]recipe = zc.recipe.eggeggs = pyflakesentry-points = pyflakes=pyflakes.scripts.pyflakes:main
Wednesday, October 27, 2010
pyflakes%> bin/pyflakes src/.../person.py
Wednesday, October 27, 2010
pyflakes%> bin/pyflakes src/.../person.py
src/.../person.py:25: 'ATTRIBUTE_NAME' imported but unusedsrc/.../person.py:25: 'IAttributeUUID' imported but unused
Wednesday, October 27, 2010
pyflakes[pyflakes-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -s pyflakes.log ]; then rm pyflakes.log echo "Old pyflakes.log file removed" fi echo "Running pyflakes" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find -L $pkg -regex ".*\.py"|xargs -r bin/pyflakes >> pyflakes.log doneoutput = ${buildout:directory}/bin/pyflakes-testmode = 755
Wednesday, October 27, 2010
pyflakes[pyflakes-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -s pyflakes.log ]; then rm pyflakes.log echo "Old pyflakes.log file removed" fi echo "Running pyflakes" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find -L $pkg -regex ".*\.py"|xargs -r bin/pyflakes >> pyflakes.log doneoutput = ${buildout:directory}/bin/pyflakes-testmode = 755
Wednesday, October 27, 2010
pyflakes[pyflakes-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -s pyflakes.log ]; then rm pyflakes.log echo "Old pyflakes.log file removed" fi echo "Running pyflakes" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find -L $pkg -regex ".*\.py"|xargs -r bin/pyflakes >> pyflakes.log doneoutput = ${buildout:directory}/bin/pyflakes-testmode = 755
Wednesday, October 27, 2010
pyflakes[pyflakes-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -s pyflakes.log ]; then rm pyflakes.log echo "Old pyflakes.log file removed" fi echo "Running pyflakes" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find -L $pkg -regex ".*\.py"|xargs -r bin/pyflakes >> pyflakes.log doneoutput = ${buildout:directory}/bin/pyflakes-testmode = 755
Wednesday, October 27, 2010
pyflakes[pyflakes-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -s pyflakes.log ]; then rm pyflakes.log echo "Old pyflakes.log file removed" fi echo "Running pyflakes" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find -L $pkg -regex ".*\.py"|xargs -r bin/pyflakes >> pyflakes.log doneoutput = ${buildout:directory}/bin/pyflakes-testmode = 755
Wednesday, October 27, 2010
[pyflakes-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -s pyflakes.log ]; then rm pyflakes.log echo "Old pyflakes.log file removed" fi echo "Running pyflakes" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find -L $pkg -regex ".*\.py"|xargs -r bin/pyflakes >> pyflakes.log doneoutput = ${buildout:directory}/bin/pyflakes-testmode = 755
pyflakes
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
pylint
Wednesday, October 27, 2010
pylint
• Syntax checking
• PEP8 compliance
• Imports code
• You’ve done everything wrong
Wednesday, October 27, 2010
pylint
[pylint]recipe = zc.recipe.eggeggs = logilab.pylintinstallerextra-paths = ${instance:location}/lib/pythonentry-points = pylint=pylint.lint:Runarguments = [ '--output-format=parseable', '--zope=y', '--reports=y', '--disable-msg=
E0611,F0401,W0232,E1101,C0103,C0111,R0201,W0201,R0911,R0904,F0220, E1103,R0901,E0211,E0213,E1002,W0622',
'--generated-members=objects', ] + sys.argv[1:]
Wednesday, October 27, 2010
pylint
• disable-msg
• R0911: Too many return statements (%s/%s)
• R0201: Method could be a function
• W0201: Attribute %r defined outside of __init__
• http://pylint-messages.wikidot.com/all-messages
Wednesday, October 27, 2010
pylint[pylint-test]recipe = collective.recipe.templateinput = inline: #!/bin/sh if [ -s pylint.log ]; then rm pylint.log echo "Old pylint.log file removed" fi echo "Running pylint" PACKAGES="${buildout:package-directories}" for pkg in $PACKAGES do find -L $pkg -regex ".*\.py" | xargs bin/pylint >> pylint.log done echo "Finished"output = ${buildout:directory}/bin/pylint-testmode = 755
Wednesday, October 27, 2010
pylint
Wednesday, October 27, 2010
pylint
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Selenium
Wednesday, October 27, 2010
Selenium• Automated web application testing
Wednesday, October 27, 2010
Selenium1. Open this page
2. Click that thing
3. Fill out that form
4. Click submit
Did it work?
Wednesday, October 27, 2010
Selenium Testcase
def test_login_overlay(self): self.open("/") self.wait() self.selenium.click('link=Log in') self.waitForElement('form#login_form') self.selenium.type("name=__ac_name", TEST_USER_NAME) self.selenium.type("name=__ac_password", TEST_USER_PASSWORD) self.selenium.click("submit") self.wait() self.failUnless(self.selenium.is_text_present("Log out"))
Wednesday, October 27, 2010
Selenium Testcaseclass SeleniumLayer(PloneSandboxLayer): defaultBases = (HOST_ADJUSTABLE_ZSERVER_FIXTURE, PLONE_FIXTURE)
# Connection parameters seleniumHost = os.environ.get('SELENIUM_HOST', 'localhost') seleniumPort = os.environ.get('SELENIUM_PORT', '4444') seleniumBrowser = os.environ.get('SELENIUM_BROWSER', '*firefox')
def setUpZope(self, app, configurationContext): ...
def setUpPloneSite(self, portal): ... url = "http://%s:%s/%s" % (self['host'], self['port'], PLONE_SITE_ID) self['selenium'] = selenium.selenium(self.seleniumHost,
self.seleniumPort, self.seleniumBrowser, url) self['selenium'].start()
def tearDownPloneSite(self, portal): self['selenium'].stop() del self['selenium']
Wednesday, October 27, 2010
Selenium Testcaseclass SeleniumLayer(PloneSandboxLayer): defaultBases = (HOST_ADJUSTABLE_ZSERVER_FIXTURE, PLONE_FIXTURE)
# Connection parameters seleniumHost = os.environ.get('SELENIUM_HOST', 'localhost') seleniumPort = os.environ.get('SELENIUM_PORT', '4444') seleniumBrowser = os.environ.get('SELENIUM_BROWSER', '*firefox')
def setUpZope(self, app, configurationContext): ...
def setUpPloneSite(self, portal): ... url = "http://%s:%s/%s" % (self['host'], self['port'], PLONE_SITE_ID) self['selenium'] = selenium.selenium(self.seleniumHost,
self.seleniumPort, self.seleniumBrowser, url) self['selenium'].start()
def tearDownPloneSite(self, portal): self['selenium'].stop() del self['selenium']
Wednesday, October 27, 2010
Selenium Testcaseclass SeleniumLayer(PloneSandboxLayer): defaultBases = (HOST_ADJUSTABLE_ZSERVER_FIXTURE, PLONE_FIXTURE)
# Connection parameters seleniumHost = os.environ.get('SELENIUM_HOST', 'localhost') seleniumPort = os.environ.get('SELENIUM_PORT', '4444') seleniumBrowser = os.environ.get('SELENIUM_BROWSER', '*firefox')
def setUpZope(self, app, configurationContext): ...
def setUpPloneSite(self, portal): ... url = "http://%s:%s/%s" % (self['host'], self['port'], PLONE_SITE_ID) self['selenium'] = selenium.selenium(self.seleniumHost,
self.seleniumPort, self.seleniumBrowser, url) self['selenium'].start()
def tearDownPloneSite(self, portal): self['selenium'].stop() del self['selenium']
Wednesday, October 27, 2010
Selenium RC
• Firefox
• Internet Explorer
• Safari
• Chrome
• Opera
• more...
Wednesday, October 27, 2010
Selenium Grid
Wednesday, October 27, 2010
Wednesday, October 27, 2010
“Firefox?”
Wednesday, October 27, 2010
Thanks!
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Selenium Test Runnerfsd/
core/...selenium/
base.pytestSelenium.py
tests/...
Wednesday, October 27, 2010
Selenium Test Runner
[selenium]recipe = collective.xmltestreporteggs = fsd.core [test] fsd.membrane [test]defaults = ['--tests-pattern', '^f?selenium$', '--xml']
Wednesday, October 27, 2010
Selenium Test Runner
[selenium]recipe = collective.xmltestreporteggs = fsd.core [test] fsd.membrane [test]defaults = ['--tests-pattern', '^f?selenium$', '--xml']
Wednesday, October 27, 2010
Selenium Test Runner
[selenium-firefox]recipe = ${selenium:recipe}eggs = ${selenium:eggs}defaults = ${selenium:defaults} [selenium-safari]recipe = ${selenium:recipe}eggs = ${selenium:eggs}defaults = ${selenium:defaults}
Wednesday, October 27, 2010
Selenium Test Runner
%> bin/selenium-firefox%> bin/selenium-safari
Wednesday, October 27, 2010
Selenium Test Runner
workspace/bin/...parts/
selenium-firefox/testreports/
*.xmlselenium-safari/
testreports/*.xml
Wednesday, October 27, 2010
~
Wednesday, October 27, 2010
Sprint!
• Saturday
• QA Sprint
• Selenium testing and more
• Free food!
Wednesday, October 27, 2010
Multi-Configuration Projects
Wednesday, October 27, 2010
Multi-Configuration Projects
• Run a build for each set of n x n ( x n x n) variables.
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Wish List
Wednesday, October 27, 2010
Wish List
• Load testing
• Sphinx builds
• Chameleon compatibility checking
• Windmill
Wednesday, October 27, 2010
Best Practices
Wednesday, October 27, 2010
Check in Your Configs
• Configuration is stored in XML files
• Easy to back up to SVN
Wednesday, October 27, 2010
Check in Your Configshudson /
config.xmlhudson.plugins.*.xmljobs /
myjob / builds /
2010-10-21_11-56-402010-10-21_12-20-26
config.xmlworkspace /
Wednesday, October 27, 2010
hudson /config.xmlhudson.plugins.*.xmljobs /
myjob / builds /
2010-10-21_11-56-402010-10-21_12-20-26
config.xmlworkspace /
Check in Your Configs
Wednesday, October 27, 2010
Check in Your Configs
Wednesday, October 27, 2010
Watch Your Disk Space
• “Hudson disk-usage” plugin
Wednesday, October 27, 2010
Watch Your Disk Space
Wednesday, October 27, 2010
Watch Your Disk Space
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Use an Egg Cache
• Set up a default.cfg for your hudson account.
[buildout]eggs-directory =
/home/hudson/.buildout/eggsdownload-cache =
/home/hudson/.buildout/downloads
Wednesday, October 27, 2010
Pin unittest2
• (If you’re using it)
• plone.app.testing
• 3x faster buildout
Wednesday, October 27, 2010
Split Big Builds
• How long does the build take?
• How often does each part need to be run?
• Tests?
• Coverage?
Wednesday, October 27, 2010
Split Big Builds
• Build
• Test
• Syntax Checking
• Coverage
• Selenium
Wednesday, October 27, 2010
Split Big Builds1. “Build other projects” post-build action
Wednesday, October 27, 2010
Split Big Builds1. “Build other projects” post-build action
2. Custom workspace
Wednesday, October 27, 2010
Split Big Builds1. “Build other projects” post-build action
2. Custom workspace
3. Build Fingerprinting
Wednesday, October 27, 2010
Fingerprinting
• “These builds are related”
• Archive an md5 hash of a file to act as an identifier
Wednesday, October 27, 2010
FingerprintingIn parent build:
In parent and child builds:
Wednesday, October 27, 2010
Reporting
Wednesday, October 27, 2010
Hudson Report Views
Wednesday, October 27, 2010
Wednesday, October 27, 2010
Chuck
Wednesday, October 27, 2010
iPhone
Wednesday, October 27, 2010
Extreme Feedback Devices
Wednesday, October 27, 2010
hudson.plone.org
• Currently builds Plone 4.0.x
• Core developers have access
• Add your core & collective projects
Wednesday, October 27, 2010
Thanks
• Martin Aspeli
• Timo Stollenwerk
• Hanno Schlichting
Wednesday, October 27, 2010
QA Sprint!
• Saturday
• QA Sprint
• Selenium testing and more
• Free food!
Wednesday, October 27, 2010