Today I was trying to run some Test::Class-based unit tests for a project I'm working on. This project has lots of functional tests that go through Test::WWW::Mechanize, so they run inside Apache and mod_perl.
What I was trying to do was testing the same code outside the Apache server, just as regular command-line-runnable tests. Being a Perl project, you have all the nice infrastructure already done for you, and so you can just run make test
or Build test
depending on the exact tool you're using.
However, when I run this, I got a strange error:
PERL_DL_NONLAZY=1 /usr/bin/perl "-MExtUtils::Command::MM" "-e" "test_harness(0, 'blib/lib', 'blib/arch')" t/*/*.t t/unit-tests/basic-sanity.t .. ok t/unit-tests/handler-xml.t ... Can't load '/usr/lib/perl5/auto/APR/Request/Apache2/Apache2.so' for module APR::Request::Apache2: /usr/lib/perl5/auto/APR/Request/Apache2/Apache2.so: undefined symbol: modperl_xs_sv2request_rec at /usr/lib/perl/5.10/DynaLoader.pm line 193. at /usr/lib/perl5/Apache2/Request.pm line 3 Compilation failed in require at /usr/lib/perl5/Apache2/Request.pm line 3. BEGIN failed--compilation aborted at /usr/lib/perl5/Apache2/Request.pm line 3.
The weird error is:
Can't load '/usr/lib/perl5/auto/APR/Request/Apache2/Apache2.so' for module APR::Request::Apache2: /usr/lib/perl5/auto/APR/Request/Apache2/Apache2.so: undefined symbol: modperl_xs_sv2request_rec at /usr/lib/perl/5.10/DynaLoader.pm line 193.
and specifically, undefined symbol: modperl_xs_sv2request_rec
.
Why is this happening?
A search for this error message gives back very few results, and not very useful. However, this more specific search turns up fewer results, but that led me to the solution.
The first hit, in particular, I have no idea what that page says, because it's Japanese, but the code blocks are clearly referring to the PERL_DL_NONLAZY
environment variable:
PERL_DL_NONLAZY Set to one to have perl resolve all undefined symbols when it loads a dynamic library. The default behaviour is to resolve symbols when they are used. Setting this variable is useful during testing of extensions as it ensures that you get an error on misspelled function names even if the test suite doesn't call it.
AFAIK, it all boils down to the modperl_xs_sv2request_rec
function not being available if your code is not running inside Apache with mod_perl loaded. So, it makes sense to run the tests with PERL_DL_NONLAZY=0
(that is, be lazy!), like the Japanese guy suggests.
However, changing that in the Makefile incantations seems to be a Royal Pain, so I just gave prove a shot. And once more, I had the proof that prove
is just the way to run your test suite, because prove seems to be smart enough to set PERL_DL_NONLAZY automatically to zero.
So now, I'm running prove through a shell script, like this:
... BASE_DIR=<project_root> ... export CONFIG_FILE=/etc/blah-blah export WHATEVER_ELSE=... ... prove -I $BASE_DIR/lib $* $BASE_DIR/t/unit-tests
And that's it, all tests successful! o/