It can be difficult to use the Perl debugger to debug Evergreen's Perl code while the system is running. One workaround is to run a unit test that calls the Perl code you'd like to debug. This approach allows you to provide specific known values to the subroutines in question.
The following steps work for unit tests (i.e. the tests in Open-ILS/src/perlmods/t). I don't think they work for the live tests. These are written using the docker dev containers. If you use a different development environment, you'll probably have to adjust them.
OpenILS::Application::Storage::QueryParser::remove_search_field
subroutine, which is currently called on line 25 of t/21-QueryParser.t.docker ps
# gives you a list of running containers. Find the ID or name of the one you just starteddocker exec -it container_id_or_name bash
su opensrf
cd /home/opensrf/repos/Evergreen/Open-ILS/src/perlmods
perl -Ilib -d -T t/21-QueryParser.t # -T is only necessary if the first line of the test specifies perl -T
n
then enter a few times until you reach the context of a line in t/21-QueryParser.tb 25
c
to proceed to the breakpointmain::(t/21-QueryParser.t:25): $QParser->remove_search_field('author', 'personal');
s
to step into the query parser's remove_search_field method!l
(lower case L)n
x
then the expression. For example, you could enter x $pkg->search_fields->{'author'}
to get a list of the current author search fields in the parser.R
to restart the test, which will now take your changes into account. Maybe. This can be buggy in my experience.q
Sometimes your test code or production code will have an error that causes it to die. Sometimes this will cause multiple tests or subtests to fail. If this happens, you can run into frustrating situations where you set a breakpoint within a failing test, enter c
, and instead of allowing you to debug that line, you get the message "Debugged program terminated." To avoid this:
Most of Evergreen's code is unfortunately not (yet) covered by a unit test. However, in some cases you can throw together a simple unit test for the purposes of debugging, and it has the added benefit of improving our test coverage. This will be easier for simple subroutines that don't depend on many other parts of the code.
OpenILS::Application::Acq::EDI::nice_string
doesn't have a test, let's test it!
use warnings; use strict; use Test::More tests => 2; use_ok 'OpenILS::Application::Acq::EDI'; my $edi = OpenILS::Application::Acq::EDI->new; $edi->nice_string('Hello'); pass();
And once we have finished our debugging, we can turn this into a legit test by replacing `pass()` with a real assertion.
use warnings; use strict; use Test::More tests => 2; use_ok 'OpenILS::Application::Acq::EDI'; my $edi = OpenILS::Application::Acq::EDI->new; is $edi->nice_string('Hello'), 'Hello', 'String Hello is left intact';
Run it with prove, and then let's submit that patch to boost our code coverage!
If it relies on a complex object, but you can pass it in, you can use Test::MockObject
. If it relies on a complex object but it is setup somewhere you can't control in your test (e.g. the initializer creates a new CSTORE editor), use Test::MockModule
.
* The Perl 5 Debugger by Ricardo Signes (youtube video) – a good talk on the Perl debugger