When I started this blog, my intent was to illustrate different ways to do things in Perl (where TIMTOWTDI originated). Since then I have transitioned from Perl to Python, become active in several open source software projects, and started to learn how to contribute to project code in addition to test automation. I am returning to the blog to discuss things as I learn them. 'There's More Than One Way To Do It' remains true, even using different languages or an established design pattern.
Thursday, March 13, 2014
secure ldap on centos
In the unlikely event that you were wondering how to fix the fact that the ldap client can't talk to the server using ldaps / starttls even tho you added the CA cert using certutil, you need to you need to create /etc/openldap/cacerts and add it to there instead of /etc/openldap/certs.
Friday, January 10, 2014
From nose to testr: Output Capture
The thing that drove me most crazy when I was trying to write nose-testresources (a plugin for nose that would put ResourcedTestCases inside OptimisedTestSuites) was that I lost nose's default behaviour of capturing log output and stdout. I put a lot of work into logging information that would help me troubleshoot failures, and was flailing without it.
I talked to Robert Collins, the primary maintainer of this chain of tools, and he suggested I use testtools.TestCase, which supports addFixture() and python-fixtures, which includes FakeLogger. Now, this transition turned out to be a little bit sticky - both testtools.TestCase and testresources.ResouredTestCase inherit from unittest.TestCase, so dual inheritance should have worked, but I was running into this strange problem that resources were never being cleaned up. It turned out that testtools.TestCase calls setUp() but doesn't call tearDown() - it uses addCleanup() for that purpose. As part of the debugging process for this issue, I axed the multiple inheritance an just created a ResourcedTestCase that follows testtools.TestCase norms as follows:
from testresources import setUpResources, tearDownResources, _get_result
import testtools
import fixtures
class ResourcedTestCase(testtools.TestCase):
"""Inherit from testtools.TestCase instead of unittest.TestCase in order
to have self.useFixture()."""
def setUp(self):
# capture output
FORMAT = '%(asctime)s [%(levelname)s] %(name)s %(lineno)d: %(message)s'
self.useFixture(fixtures.FakeLogger(format=FORMAT))
# capture stdout
stdout = self.useFixture(fixtures.StringStream('stdout')).stream
self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
# capture stderr
stderr = self.useFixture(fixtures.StringStream('stderr')).stream
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
super(ResourcedTestCase, self).setUp()
setUpResources(self, self.resources, _get_result)
self.addCleanup(tearDownResources, self, self.resources, _get_result)
I talked to Robert Collins, the primary maintainer of this chain of tools, and he suggested I use testtools.TestCase, which supports addFixture() and python-fixtures, which includes FakeLogger. Now, this transition turned out to be a little bit sticky - both testtools.TestCase and testresources.ResouredTestCase inherit from unittest.TestCase, so dual inheritance should have worked, but I was running into this strange problem that resources were never being cleaned up. It turned out that testtools.TestCase calls setUp() but doesn't call tearDown() - it uses addCleanup() for that purpose. As part of the debugging process for this issue, I axed the multiple inheritance an just created a ResourcedTestCase that follows testtools.TestCase norms as follows:
from testresources import setUpResources, tearDownResources, _get_result
import testtools
import fixtures
class ResourcedTestCase(testtools.TestCase):
"""Inherit from testtools.TestCase instead of unittest.TestCase in order
to have self.useFixture()."""
def setUp(self):
# capture output
FORMAT = '%(asctime)s [%(levelname)s] %(name)s %(lineno)d: %(message)s'
self.useFixture(fixtures.FakeLogger(format=FORMAT))
# capture stdout
stdout = self.useFixture(fixtures.StringStream('stdout')).stream
self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
# capture stderr
stderr = self.useFixture(fixtures.StringStream('stderr')).stream
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
super(ResourcedTestCase, self).setUp()
setUpResources(self, self.resources, _get_result)
self.addCleanup(tearDownResources, self, self.resources, _get_result)
With this new base class, my tests now capture logging, stdout, and stderr under both testr and nose, with and without nose-testresources.
Thursday, January 9, 2014
From nose to testr: More Flexible Test Discovery
testrepository requires a results stream in subunit format, and the python implementation of that is testtools. testtools uses the standard unittest.TestLoader. This loader will let you discover tests from one specific directory, or run tests from multiple fully specified test modules. I am accustomed to nose, which lets you specify an arbitrary number of directories and modules, so I modified the TestLoader to bend it to my will.
import os
import unittest
class TestLoader(unittest.TestLoader):
"""Test loader that extends unittest.TestLoader to:
* support names that can be a combination of modules and directories
"""
def loadTestsFromNames(self, names, module=None):
"""Return a suite of all tests cases found using the given sequence
of string specifiers. See 'loadTestsFromName()'.
"""
suites = []
for name in names:
if os.path.isdir(name):
top_level = os.path.split(name)[0]
suites.extend(self.discover(name, top_level_dir=top_level))
else:
suites.extend(self.loadTestsFromName(name, module))
return self.suiteClass(suites)
import os
import unittest
class TestLoader(unittest.TestLoader):
"""Test loader that extends unittest.TestLoader to:
* support names that can be a combination of modules and directories
"""
def loadTestsFromNames(self, names, module=None):
"""Return a suite of all tests cases found using the given sequence
of string specifiers. See 'loadTestsFromName()'.
"""
suites = []
for name in names:
if os.path.isdir(name):
top_level = os.path.split(name)[0]
suites.extend(self.discover(name, top_level_dir=top_level))
else:
suites.extend(self.loadTestsFromName(name, module))
return self.suiteClass(suites)
Then it just became a matter of borrowing from the subunit runner script and instantiating SubunitTestProgram with the new loader.
SubunitTestProgram(module=None, argv=sys.argv, testRunner=SubunitTestRunner,
stdout=sys.stdout, testLoader=TestLoader())
From nose to testr: Rationale
When I started at SwiftStack, my first priority was to write as many automated tests as I could. I wanted to use a framework/runner already familiar to the developers, has good online support / community, and unittest-compatible because it was almost certain I'd have to change frameworks eventually. I chose nose.
Over the course of the next 6 months, I was a little bit too successful at writing automated tests, and I arrived at the point that a full test run in the default environment took 13 hours, there was not enough time in the day to run the tests against all of the different environments, and I was unable to effectively test the effect of changes to the automation infrastructure before merging.
I needed to speed up the tests.
While there were some tests where the test itself was slow, the bigger problem was setup for the tests. The fixtures I needed for many of the tests were very expensive, and even if nose let me set them up on a per-class basis rather than a per-test basis, it was still adding time. Enter testresources, whose OptimisedTestSuite analyses the resources required by each test, orders them according to those resources, and shares resources across tests.
I tried for quite some time to get testresources to work with nose...I wrote a nose plugin that allowed me to get by, but there were some distinct problems, and the primary maintainer for nose was not available (he has recently requested hand-off to a new maintainer). I eventually decided to go with what the OpenStack community had been telling me all along - that I should use the testrepository (testr) / subunit / testtools / testresources collection of tools.
There have been challenges. I'm still not done. But I've got insights to share:
Over the course of the next 6 months, I was a little bit too successful at writing automated tests, and I arrived at the point that a full test run in the default environment took 13 hours, there was not enough time in the day to run the tests against all of the different environments, and I was unable to effectively test the effect of changes to the automation infrastructure before merging.
I needed to speed up the tests.
While there were some tests where the test itself was slow, the bigger problem was setup for the tests. The fixtures I needed for many of the tests were very expensive, and even if nose let me set them up on a per-class basis rather than a per-test basis, it was still adding time. Enter testresources, whose OptimisedTestSuite analyses the resources required by each test, orders them according to those resources, and shares resources across tests.
I tried for quite some time to get testresources to work with nose...I wrote a nose plugin that allowed me to get by, but there were some distinct problems, and the primary maintainer for nose was not available (he has recently requested hand-off to a new maintainer). I eventually decided to go with what the OpenStack community had been telling me all along - that I should use the testrepository (testr) / subunit / testtools / testresources collection of tools.
There have been challenges. I'm still not done. But I've got insights to share:
- More Flexible Test Discovery
- Output Capture
- Capturing and Recovery from OptimisedTestSuite errors
And more to come.
Subscribe to:
Comments (Atom)