afterbridge

How AfterBridge Was Tested

AfterBridge makes four promises. The files it reads are never written. Nothing a request sends reaches SQL or the file system. A file that is half written is never served. And every answer is exactly what the file holds, values and types alike. Most of the testing went into the third and the fourth, because that’s where reading someone else’s files goes wrong.

Half files

The main test has a writer rewriting an export over and over, in random pieces, sometimes stopping in the middle of a line, with short pauses, while requests keep coming. Every answer has to be one complete version of the file: the right number of rows, all from the same version, none from two.

Writing that test found the first real bug before anyone else looked. AfterBridge first waited for a file to stay the same across two checks. A writer that paused longer than a check got caught at a line boundary, and the first part of the file was served as if it were all of it. The fix is a settle time: a file is read only once it has been left alone for two seconds.

The second came from Go’s own CSV reader, which skips blank lines. In a file with one column, a blank line is a row with an empty value, and it disappeared. Blank lines are now refused.

Exact values

Another test writes random CSV files with every column type, including text full of quotes, commas, line breaks and non-English letters, and reads them back through the API. Each value must come back exactly, and as the same type: a whole number stays an integer, 15.0 stays a number.

SQLite got its own checks: reals with every digit, integers beyond what JavaScript can hold, NUL and unusual line separators inside text. The sqlite3 program’s JSON output turned out to mangle text that isn’t valid UTF-8, so AfterBridge now reads text as hex and refuses anything that isn’t UTF-8.

Nothing reaches SQL

One test puts a recorder in front of sqlite3 and sends requests built to inject SQL and shell commands. The recorder must see nothing new from them. Another reads a database and a CSV file through many requests and checks every file byte for byte afterwards, and that no new file has appeared.

What the review found

An independent review spent a while trying to break it. It found one serious problem: a .sql dump cut off between two statements was still valid SQL, so the rows written so far were served as the whole table. Dumps now wait to settle too, and one that doesn’t end cleanly, or opens a transaction it never commits, is refused.

Two medium ones: a file dated in the future made the bridge wait forever at startup, and the health check didn’t answer meanwhile. And the UTF-8 problem above. Smaller ones included numbers in Go’s own spellings like 0x1p4 being accepted, whole numbers above 2^53 rounded in number columns, unknown query parameter names showing up in the log, and a fixed path hidden behind an {id} path. A second, shorter review confirmed every fix and found a few small things more, also fixed.

Every finding has its own test. The recorded run has 530 tests, all passing with Go’s race detector on, on Linux and macOS, and the release smoke test runs a live bridge on every system it ships for. The raw results are in test/results in the code repository.