Writing

Feed Software, technology, sysadmin war stories, and more.

Monday, September 3, 2012

Unit tests with expected values from outer space

Once, I found myself having to troubleshoot a broken unit test. It had been hard coded to write to the equivalent of a world-writable public FTP directory. Not surprisingly, that directory had filled up, and now everyone who had coded their tests while ignoring best practices had to go in and fix their stuff. The author was long gone from my team, so it fell to me.

I changed our test to make it use the proper temporary location for the things it was creating, and was rewarded with a new failure:

self.assertEqual(384, info.mode)
AssertionError: 384 != 33152

All I did was change the path and it starts complaining about a "mode" mismatch? What's with these strange numbers? They don't look familiar. I dug into the source and found my answer:

info = file_lib.Stat(path)
# 384 is the mode for '-rw-------'
self.assertEqual(384, info.mode)

Yes, some bonehead was doing stat() on a file, and was using decimal values to represent the modes. They even left a comment in there to explain it instead of using a value that anyone with Unix experience should recognize. 384 in decimal is the same thing as 600 in octal, or 0600 with a leading zero typically used to mark something as octal in code.

I know people who talk about file modes as letters and plus/minus signs, and people who use the octal modes, but I don't know anyone who's far enough out there to use decimal values for these things. Obviously, someone did, because they wrote this code, but I never met them.

So what happened here? Well, it turns out that 33152 is 0100600. The code wanted to see 0600 and it was getting 0100600. What's with the extra bit? That's easy. It's just the kernel's way of saying "hey, this is a regular file". It was something new which hadn't been returned before, so the test failed on it.

I don't think the test really cared about making sure it was a regular file. It just wanted to see if it could create a file and have it happen with the right mode which would keep out everyone but the owner. As a result, the right fix was to stick a bitwise AND in there to make sure it was looking at just the things it needed to see.

Lesson learned: if the numbers seem completely bogus, try viewing them in another base. Whoever wrote it might have no idea what the usual conventions are for certain values.