summaryrefslogtreecommitdiffstats
path: root/testing
diff options
context:
space:
mode:
authorWilliam Deegan <bill@baddogconsulting.com>2015-09-21 17:03:12 (GMT)
committerWilliam Deegan <bill@baddogconsulting.com>2015-09-21 17:03:12 (GMT)
commit0941093e0e5a030faa49968457638a3a6aee7ad8 (patch)
tree6d33513c14eb6eac0531dd050de0ecca4c39bd79 /testing
downloadSCons-2.4.0.zip
SCons-2.4.0.tar.gz
SCons-2.4.0.tar.bz2
release 2.4.02.4.0
Diffstat (limited to 'testing')
-rw-r--r--testing/README.md7
-rw-r--r--testing/buildbot.hosts1
-rw-r--r--testing/buildbot.yml80
-rw-r--r--testing/framework/TestUnit/__init__.py5
-rw-r--r--testing/framework/TestUnit/cli.py35
-rw-r--r--testing/framework/TestUnit/taprunner.py130
6 files changed, 258 insertions, 0 deletions
diff --git a/testing/README.md b/testing/README.md
new file mode 100644
index 0000000..bb81ce2
--- /dev/null
+++ b/testing/README.md
@@ -0,0 +1,7 @@
+Here lie various files related to SCons that
+can not find the place in other directories:
+
+ buildbot.yml - Ansible playbook to set up
+ buildbot for running tests
+
+ buildbot.hosts - Ansible inventory file
diff --git a/testing/buildbot.hosts b/testing/buildbot.hosts
new file mode 100644
index 0000000..3e0be7d
--- /dev/null
+++ b/testing/buildbot.hosts
@@ -0,0 +1 @@
+localhost ansible_connection=local builder=xxx pass=xxx \ No newline at end of file
diff --git a/testing/buildbot.yml b/testing/buildbot.yml
new file mode 100644
index 0000000..81c2143
--- /dev/null
+++ b/testing/buildbot.yml
@@ -0,0 +1,80 @@
+# Ansible playbook to setup buildbot instance.
+# Edit buildbot.hosts to set builder and pass variables.
+# Then exec:
+#
+# ansible-playbook -i buildbot.hosts buildbot.yml
+#
+# botuser can be overridden from command line:
+#
+# ansible-playbook -i hosts buildbot.yml -e 'botuser=sconsy'
+#
+# Tested with Ansible 1.5.0, based on
+# http://scons.org/wiki/InstallingBuildbotSlaves
+# Send questions to:
+#
+# anatoly techtonik <techtonik@gmail.com>
+#
+---
+# host is overridable with --extra-vars 'host=address'
+- hosts: "{{ host | default('localhost') }}"
+ vars:
+ # botuser can be overridden with -e 'botuser=scons2'
+ - botuser: scons
+ - hgrc: /home/{{ botuser }}/.hgrc
+ - venv: /home/{{ botuser }}/buildbot-virtualenv
+ - work: /home/{{ botuser }}/buildbot-workdir
+
+ vars_prompt:
+ - name: maintainer
+ prompt: contact details of the builbot owner
+ default: name <mail@example.com>
+ private: no
+
+ tasks:
+ # --- install requirements ---
+ - name: ubuntu/debian - make sure mercurial is installed
+ apt: pkg={{ item }}
+ with_items:
+ - mercurial
+ - python-virtualenv
+
+ # --- enable mercurial purge extension ---
+ - name: create .hgrc if necessary
+ stat: path={{ hgrc }}
+ register: st
+ - file: path={{ hgrc }} owner={{ botuser }} state=touch
+ when: not st.stat.exists
+ - name: enable mercurial purge extension
+ ini_file: dest={{ hgrc }}
+ section=extensions option=hgext.purge
+ value=
+
+ - name: install buildbot-slave in virtualenv
+ pip: name=buildbot-slave virtualenv={{ venv }}
+
+ - name: create buildbot environment
+ command: "{{ venv }}/bin/buildslave create-slave
+ {{ work }} buildbot.scons.org:9989 {{ builder }} {{ pass }}
+ creates={{ work }}"
+ sudo: yes
+ sudo_user: "{{ botuser }}"
+
+ - name: set contact details of the buildbot owner
+ copy: dest="{{ work }}/info/admin" content="{{ maintainer }}"
+ notify:
+ - restart buildbot
+
+ - name: update host information
+ copy: dest="{{ work }}/info/host"
+ content="{{ansible_lsb.description}}
+ {{'\n'}}{{ansible_machine}}
+ {{'\n'}}{{ansible_memtotal_mb}}MB RAM
+ {{'\n'}}Python {{ansible_python_version}}"
+ notify:
+ - restart buildbot
+
+ handlers:
+ - name: restart buildbot
+ command: "{{ venv }}/bin/buildslave restart {{ work }}"
+ sudo: yes
+ sudo_user: "{{ botuser }}"
diff --git a/testing/framework/TestUnit/__init__.py b/testing/framework/TestUnit/__init__.py
new file mode 100644
index 0000000..51cf972
--- /dev/null
+++ b/testing/framework/TestUnit/__init__.py
@@ -0,0 +1,5 @@
+
+__all__ = ['TAPTestRunner', 'TAPTestResult', 'run']
+
+from .taprunner import TAPTestRunner, TAPTestResult
+from .cli import run
diff --git a/testing/framework/TestUnit/cli.py b/testing/framework/TestUnit/cli.py
new file mode 100644
index 0000000..6aec735
--- /dev/null
+++ b/testing/framework/TestUnit/cli.py
@@ -0,0 +1,35 @@
+"""
+Choose test runner class from --runner command line option
+and execute test cases.
+"""
+
+import unittest
+import optparse
+import sys
+
+
+def get_runner():
+ parser = optparse.OptionParser()
+ parser.add_option('--runner', default='unittest.TextTestRunner',
+ help='name of test runner class to use')
+ opts, args = parser.parse_args()
+
+ fromsplit = opts.runner.rsplit('.', 1)
+ if len(fromsplit) < 2:
+ raise ValueError('Can\'t use module as a runner')
+ else:
+ runnermod = __import__(fromsplit[0])
+ return getattr(runnermod, fromsplit[1])
+
+
+def run(suite=None):
+ runner = get_runner()
+ if suite:
+ if not runner().run(suite).wasSuccessful():
+ sys.exit(1)
+ else:
+ unittest.main(argv=sys.argv[:1], testRunner=runner)
+
+
+if __name__ == '__main__':
+ run()
diff --git a/testing/framework/TestUnit/taprunner.py b/testing/framework/TestUnit/taprunner.py
new file mode 100644
index 0000000..5c2e87c
--- /dev/null
+++ b/testing/framework/TestUnit/taprunner.py
@@ -0,0 +1,130 @@
+"""
+Format unittest results in Test Anything Protocol (TAP).
+http://testanything.org/tap-version-13-specification.html
+
+Public domain work by:
+ anatoly techtonik <techtonik@gmail.com>
+
+Changes:
+ 0.3 - fixed used imports that failed on Python 2.6
+ 0.2 - removed unused import that failed on Python 2.6
+ 0.1 - initial release
+"""
+
+__version__ = "0.3"
+
+
+from unittest import TextTestRunner
+try:
+ from unittest import TextTestResult
+except ImportError:
+ # Python 2.6
+ from unittest import _TextTestResult as TextTestResult
+
+
+class TAPTestResult(TextTestResult):
+
+ def _process(self, test, msg, failtype = None, directive = None):
+ """ increase the counter, format and output TAP info """
+ # counterhack: increase test counter
+ test.suite.tap_counter += 1
+ msg = "%s %d" % (msg, test.suite.tap_counter)
+ if "not" not in msg:
+ msg += " " # justify
+ self.stream.write("%s - " % msg)
+ if failtype:
+ self.stream.write("%s - " % failtype)
+ self.stream.write("%s" % test.__class__.__name__)
+ self.stream.write(".%s" % test._testMethodName)
+ if directive:
+ self.stream.write(directive)
+ self.stream.write("\n")
+ # [ ] write test __doc__ (if exists) in comment
+ self.stream.flush()
+
+ def addSuccess(self, test):
+ super(TextTestResult, self).addSuccess(test)
+ self._process(test, "ok")
+
+ def addFailure(self, test, err):
+ super(TextTestResult, self).addFailure(test, err)
+ self._process(test, "not ok", "FAIL")
+ # [ ] add structured data about assertion
+
+ def addError(self, test, err):
+ super(TextTestResult, self).addError(test, err)
+ self._process(test, "not ok", "ERROR")
+ # [ ] add structured data about exception
+
+ def addSkip(self, test, reason):
+ super(TextTestResult, self).addSkip(test, reason)
+ self._process(test, "ok", directive=(" # SKIP %s" % reason))
+
+ def addExpectedFailure(self, test, err):
+ super(TextTestResult, self).addExpectedFailure(test, err)
+ self._process(test, "not ok", directive=(" # TODO"))
+
+ def addUnexpectedSuccess(self, test):
+ super(TextTestResult, self).addUnexpectedSuccess(test)
+ self._process(test, "not ok", "FAIL (unexpected success)")
+
+ """
+ def printErrors(self):
+ def printErrorList(self, flavour, errors):
+ """
+
+
+class TAPTestRunner(TextTestRunner):
+ resultclass = TAPTestResult
+
+ def run(self, test):
+ self.stream.write("TAP version 13\n")
+ # [ ] add commented block with test suite __doc__
+ # [ ] check call with a single test
+ # if isinstance(test, suite.TestSuite):
+ self.stream.write("1..%s\n" % len(list(test)))
+
+ # counterhack: inject test counter into test suite
+ test.tap_counter = 0
+ # counterhack: inject reference to suite into each test case
+ for case in test:
+ case.suite = test
+
+ return super(TAPTestRunner, self).run(test)
+
+
+if __name__ == "__main__":
+ import sys
+ import unittest
+
+ class Test(unittest.TestCase):
+ def test_ok(self):
+ pass
+ def test_fail(self):
+ self.assertTrue(False)
+ def test_error(self):
+ bad_symbol
+ @unittest.skip("skipin'")
+ def test_skip(self):
+ pass
+ @unittest.expectedFailure
+ def test_not_ready(self):
+ self.fail()
+ @unittest.expectedFailure
+ def test_invalid_fail_mark(self):
+ pass
+ def test_another_ok(self):
+ pass
+
+
+ suite = unittest.TestSuite([
+ Test('test_ok'),
+ Test('test_fail'),
+ Test('test_error'),
+ Test('test_skip'),
+ Test('test_not_ready'),
+ Test('test_invalid_fail_mark'),
+ Test('test_another_ok')
+ ])
+ if not TAPTestRunner().run(suite).wasSuccessful():
+ sys.exit(1)