[OPEN-ILS-DEV] Testing Evergreen

Shawn Boyette sboyette at esilibrary.com
Sat Oct 17 14:47:33 EDT 2009


Hello, all. This message, per yesterday's dev meeting in IRC, is about 
my past efforts in adding a testing suite to OpenSRF, and the direction 
I was trying to go with it.

One of the first things I did when I was hired at ESI was to change the 
way OpenSRF's Perl modules were handled during install. At the time, 
they were simply copied from the osrf tree into the /openils tree, and 
that was that (OpenILS's modules are still done this way). I laid down a 
CPAN-style build on them with Module::Starter, so that they would be 
moved into @INC instead.

I got a skeletal testing suite for free with this, and I extended it 
ever so slightly to have a use_ok() test (see Test::More in your perldoc 
or on search.cpan.org if you're unfamiliar) for each module so that, at 
the least, we could be assured that everything *compiled*.

The next thing I did (after a bit of a hiatus) was to tweak things such 
that the Perl module tests would run from a top-level "make check", 
instead of during the "make" phase. You get this make target for free 
with the automake system, and it's where all tests should be hooked in 
the future.

I'm personally more used to "make test", but to do that we'd  have to 
define a null target named "test" in every Makefile.am in the system 
that doesn't have actual tests, or the build will die. So I'm very much 
in favor of using the GNU-standard "check", which happens when you have 
a target with that name in Makefile.am, and is just doesn't happen when 
you don't.

I then set out to build up the Perl modules' test suite. OpenSRF 
currently exists as 2 parallel implementations: Perl and C. The Perl 
side is the complete "reference" imlpementation, and the C side is a 
partial, for-speed reimplementation. I speak both languages, but am more 
of a Perl programmer than a C programmer, so from that, from the Perl 
implementation being the declared reference, and from the richness of 
Perl's testing environment, I decided to work there first.

My strategy was simple: start with the "base" modules; those which all 
the higher-level modules depended on, and which had no internal 
dependencies themselves. As the botom layer was exhaustively tested, 
work would move "up the stack", with the next round of testing resting 
on a base which had been proven, so far as was possible, to behave 
correctly.

This turned out to be impossible because my assumtion about the 
architecture of OpenSRF was badly flawed. The namespace structure of the 
modules does not reflect their architectural structure and dependencies. 
The osrf internal dependency graph actually looks like this:

http://open-ils.org/~sboyette/osrfdeps.png

which, initially, I couldn't figure out what to do with. I picked 
O::U::JSON and pulled it up to 100% test coverage because it was one of 
the dangling modules with no internal dependencies. To my mind, it is 
senseless to start testing in the middle or at the top of a dependency 
graph, because you haven't yet proven that underlying code is behaving 
as expected -- you can't simply trust that everything is OK and write 
tests which enshrine current behavior, unless you are perfect in all 
respects. At best you'll have to back up and rewrite tests as you expose 
and fix bugs. At worst you'll build a test suite which is guaranteed to 
deliver broken software.

That said, the only plan I have been able to come up with involves doing 
exactly that -- and then turning around and tearing it down.

Assuming that we want OpenSRF to be testable and provable, it must be 
refactored -- but to be safely refactored, there must be a test suite, 
so we can know that the refactored code behaves as the old code did. 
Making OpenSRF correct will therefore be a two-phase process.

The first phase is writing a test suite which, basically, only does 
tests at the subroutine/module level. That is, it simply tests for an 
expected output for a given input. "Internals" testing, the ones which 
use implementation-level knowledge of the code to prove that we get the 
right answer for the right reasons, will not be written at this point.

Once we have a scaffold of test which covers the behavior of the current 
osrf stack, refactoring begins. A refactoring of this magnitude will 
basically be a rewrite. Module names and structure will change, so the 
scaffolding tests will get dragged around, filesystem-wise, but the 
important thing is that the tests remain attached to the code which is 
performing the task whose behavior they check.

The second phase is rewriting the test suite from "behavior" to "proof 
adn correctness" testing. This might be a true, discrete phase or it 
might happen in parallel, as refactoring of individual components 
settles into stability.

This is my plan, and this is where I had planned to devote my time. The 
C side of things is no less important, but I had assumed I would be 
working largely alone, so it has received much less consideration at 
this time. I am also largely ignorant of testing infrastructure in C. I 
know how to write unit tests, but I don't know of the existance of 
higher level things like test harnesses and coverage tools like 
Devel::Cover. If anyone knows these things, or even better, would like 
to go ahead and work on C testing, I would welcome it :)

That's all I have for now. I'll be back later with info on the Buildbot 
and other stuffs.

-- 
Shawn Boyette (OTR)
<sboyette at esilibrary.com>
Testing and Reliability
Equinox Software, Inc.


More information about the Open-ils-dev mailing list