TIL: testing in the future using the faketime command

Monday, July 22, 2024

Last week's blog post accidentally got published a few hours early1. One of the keen-eyed among you even submitted it to the orange site before it was officially up, since it was in my RSS feed briefly and was picked up by various RSS readers. Resolving that issue led me to discover the command faketime and a wonderful way of validating processes that are time and timezone dependent.

I'm going to first talk about the bug, then separately about how I tested a fix. Feel free to skip ahead to the testing part if you want to skip the story.

The bug that published my post early

Last week's post went up early because I was testing out a new way of publishing previews of posts, and that process had a bug. Previously, I would publish my entire site with drafts to a separate hosting stack just for blog previews. I didn't love that this required two separate deployment processes, though, and I kept admiring how a friend has unlisted posts on her regular site for previews. So I wanted to do that!

Since my static site generator doesn't have hidden pages, I accomplished it by customizing my site templates. One of the comments in that issue thread yields a way to achieve this. Adapting it for all the files I needed, I put something like this inside my templates for atom.xml and my blog/tag pages2:

<!-- snippet from templates/blog.html -->
{% set ts_now = now() | date(format="%Y-%m-%d") | date(format="%s") | int %}

{% for page in section.pages %}
  {% set ts_page = page.date|default(value=0)|date(format="%s")|int %}
  {% if ts_page <= ts_now %}
    <li>{{page.date}}: <a href="{{ page.permalink | safe }}">{{ page.title }}</a></li>
  {%- endif -%}
{% endfor %}

This worked great, and I was able to get feedback on last week's post by sending a link to the hidden page! Neat!

The problem came when I published a typo fix before going to bed on Sunday. The post was scheduled for Monday, and when I published a typo fix, it had already become Monday in UTC. I am on the US east coast, and my computer is set to use Eastern Time. So imagine my surprise when, upon publishing a typo fix, this post also became public and appeared in the feeds! My static site generator was using UTC for the post dates.

I quickly made a small change to remove it from the feeds (I set the post a year in the future). But I couldn't let go of the bug, and I came back to it this week.

I eventually made another tweak to my templates to, effectively, strip out timezone information. It's hacky, but it works. But how do I make sure of that?

Testing in the future

To verify my change, I had to figure out how to check it at a few critical times. Since I want posts to publish on a particular calendar day in my local timezone, I wanted to check if the day before at 11pm filters it out and the next day at 1am includes it.

I stumbled across faketime, which I installed from a system package. It's available on Fedora via sudo dnf install libfaketime, and similar packages exist on other distributions.

Using it is straightforward. You give it a timestamp and a program to run. Then it runs the program while intercepting system calls to time functions. This lets you very easily test something out at a few different times without any modifications to your program or system clock.

Here's how I used it for testing this issue:

# verify that the post disappears before publication time
faketime "sunday 11pm" zola serve

# verify that the post appears after publication time
faketime "monday 1am" zola serve

It can do a few other really useful things, too.

  • Set a specific time: faketime "2024-01-01 12:00:00" zola serve
  • Start at a time, and go 10x faster: faketime -f "@2024-07-21 23:59:00 x10" zola serve
  • Advance by an interval (here, 10 seconds) on each call to get the system time: faketime -f "@2024-07-21 23:59:00 i10.0" zola serve

I just use the simple ones with relative times usually, but it's very nice being able to speed up time! faketime is available as a program or a C library, so it can also be integrated into other programs for testing.


1

With a deep dose of irony, this post also published early. I spent a couple of hours digging in last night and fixing something, because originally I'd not really fixed the bug! Now it is truly fixed, but wow was that a funny twist.

2

This approach does yield a minor bug: hidden posts are included in the count for tags, but are not displayed in the list. In an ideal world, I'd not include them in the count. But this is not an ideal world.


If this post was enjoyable or useful for you, please share it! If you have comments, questions, or feedback, you can email my personal email. To get new posts and support my work, subscribe to the newsletter. There is also an RSS feed.

Want to become a better programmer? Join the Recurse Center!
Want to hire great programmers? Hire via Recurse Center!