Mocking the system time
Testing your shell scripts can be complicated enough already but when
you start to incorporate time based test scenarios you can quickly find
yourself in the land of fragile tests and intermittent failures. By
adding a small command line utility, called faketime
, to your toolbox
you can make your chronology related tests more reliable and
reproducible.
To start we’ll install faketime
. This focused little binary allows you
to explicitly set the system time for which ever command you pass to it.
On Fedora systems the install is as simple as:
sudo dnf install libfaketime
First we’ll run a normal date
command to ensure everything is as we expect.
$ date
Sat 30 May 13:27:16 BST 2020
If we want to run our commands with a specific, and different date, we
invoke faketime
when we run them.
faketime '2008-12-24 08:15:42' date
Wed 24 Dec 08:15:42 GMT 2008
This allows you to test edge cases, such as behaviour on a leap day, or start your sequence of tests from a known good point. When testing systems that have longer waits between parts of their functionality you can run the commands with explicit times and ensure you handle each case.
# create the batch with a known good time
faketime '2008-10-24 08:15:42' write-batch.py
# test the handling of expired records by
# setting the time forward immediately
faketime '2008-12-24 08:15:42' process-batch.py --expiry 31
WARNING: Monthly data is out of stale. Older than 31 days
If you’re writing in a higher level language than shell there are
sometimes more specific testing libraries to support this kind of
functionality, such as
Timecop in ruby.
faketime
can still be handy when you’re working with a language that lacks such niceties or
are running in a constrained environment. The following example shows
the time being explicitly set for an entire language runtime but still
progress forward within the process.
faketime '2008-12-24 08:15:42' ruby -e 'puts Time.new ; sleep 5 ; puts Time.new'
2008-12-24 08:15:42 +0000
2008-12-24 08:15:47 +0000
And for old times sake here it is faking the time for a perl
interpreter.
faketime '2008-12-24 08:15:42' perl -e 'print localtime . "\n"'
Wed Dec 24 08:15:42 2008
faketime
is a very niche tool that provides flexibility in a narrow
set of use cases. You won’t need it often but when you do it’s much
easier to install it than try to kludge in your own implementation.