Categories
Uncategorized

assertThat

I’ve just found a new feature in junit 4.4: assertThat()1. This gives you a much nicer way of specifying assertions than the usual assertEquals() or assertTrue(). Some examples from the docs above:

  assertThat(x, is(3));
  assertThat(x, is(not(4)));
  assertThat(responseString, either(containsString("color")).or(containsString("colour")));
  assertThat(myList, hasItem("3"));

This is both very readable, and leads to much improved diagnostic messages in failure.

It’s also (relatively) easy to extend to provide your own matchers (although check out hamcrest for some handy predefined ones). For example, I’ve just come up with this class to assert whether a collection is empty is empty or not.

class EmptyMatcher extends TypeSafeMatcher<Collection<?>> {
    @Override
    public boolean matchesSafely(Collection<?> c) {
        return c.isEmpty();
    }

    public void describeTo(Description desc) {
        desc.appendText("empty");
    }

    @Factory
    public static <T> Matcher<? super Collection<?>> empty() {
        return new EmptyMatcher();
    }
}

This is based on the example in the hamcrest tutorial. The only thing of real interest is the static factory method empty()2. This is what you would import static, so you can say:

  assertThat(setOfThings, empty());

This is more concise and leads to better error reporting than it’s predecessor.

  assertThat(setOfThings.size(), is(0));

One of the other nice things about using Matchers is that you can have side effects other than matching something. A great example is describedAs(). Say that you have:

  assertThat(a.getFrog(), is(not(nullValue())));

This would produce an error like:

Expected: is not null
Got: null

You can add in a description like this:

  assertThat(a.getFrog(), describedAs("frog", is(not(nullValue()))));

The error now becomes:

Expected: frog
Got: null

In the use I’ve put it to so far, this seems to be particularly appropriate for null values, which are otherwise quite unhelpful when a test fails.

I’ve completely switched my latest project to using assertThat(). So far, it seems to be leading to some nice readable code and I’m quite pleased with the results.

1 As an aside, “junit.org FAIL”: no javadocs, no news. The place is a mess.

2 I recommend checking out the chapter on generics in Effective Java 2nd Edition in order to properly understand the declaration here.

Categories
Uncategorized

Postfix 2.5.1 TLS on FreeBSD

This is one of those things that I have to put up there in case anybody else has the same obscure setup that I do…

I run postfix on FreeBSD, using the ports system. This means I have a tendency to just use portupgrade to upgrade to the latest version of anything I happen to have installed. Normally, this works just fine. I usually check the output to see if any warnings about upgrading pop out and that’s about it. Slightly seat-of-the-pants, I know.

Anyway, I recently upgraded to postfix 2.5.1 and started seeing these messages in the logs.

Jul 26 21:29:44 gimli postfix/tlsmgr[7789]: fatal: tls_prng_exch_open: cannot open PRNG exchange file /var/lib/postfix/prng_exch: Permission denied

tlsmgr is the bit of postfix that handles SMTP over SSL.

The first port of call is to look through the postfix release notes. This seemed relevant.

[Incompat 20071206] The tlsmgr(8) and verify(8) servers no longer use root privileges when opening the address_verify_map, *_tls_session_cache_database, and tls_random_exchange_name cache files. This avoids a potential security loophole where the ownership of a file (or directory) does not match the trust level of the content of that file (or directory).

So, what’s the problem?

  % sudo -u postfix ls -l /var/lib/postfix
  Password:
  ls: /var/lib/postfix: Permission denied
  % sudo -u postfix ls -l /var/lib
  total 0
  ls: lib: Permission denied
  % sudo -u postfix ls -ld /var/lib
  drwxr-x---  5 root  wheel  512 26 Jul 08:14 /var/lib

So, it’s basically a permissions problem. Postfix can’t see the directory it’s trying to use. Previously it wasn’t a problem, as postfix was doing things as root, and root sidesteps permissions checks.

What to do? The simplest is to change the permissions. But I don’t particularly like doing that on systems directories, as they may well get reset in the future (e.g. nightly runs of mtree). So the simplest option is probably to reconfigure postfix to use a different directory. One that it actually has permission to access, like /var/db/postfix.

Annoyingly, when I look at the port to understand this problem (PR#121236), it was fixed in April. I wonder why I didn’t get the fix?

As it turns out a reinstall of postfix (portupgrade -f postfix-2.5.1_2,1) completely fixes the problem, and the directory it uses is now /var/db/postfix by default. I wonder what caused it to go wrong in the first place though?