Hornet
A test language for a pricing rules engine, and the compiler front end that runs it.
Product screens
Overview
I designed Hornet Lingo in 2012, a domain-specific language for data-driven tests of a bank's payment pricing rules, and built its toolchain: ANTLR grammars that compile test scripts into an executable model, a concurrent engine that runs them against the rules service, and a workbench that highlights the language as you type.
Problem statement
A rules engine priced every international payment quote: client type, tier, margin, fee, promotion and expiry, across more than 160 currencies, client segments, channels and business hours. Testers checked it with hand-built SOAP requests, so coverage ended where someone's patience for XML did, and every new rule meant another batch of requests to write and compare by eye.
Solution
I wanted testers to write what a rule should do, not how to call the service: a few readable lines per rule, a list of values instead of a loop, and a tool that turns those lines into hundreds of checked requests.
A language for one domain.
A Hornet Lingo test case is a header of properties, then SETUP, TEST and TEARDOWN blocks of operations, each pairing its inputs with an EXPECT section. The lexer types every value as a string, number, boolean, date or one of 164 ISO 4217 currency codes, so a mistyped currency is a syntax error rather than a failed test.
Defined as grammars.
I wrote the language as three ANTLR 3 grammars: a lexer, a parser whose rewrite rules build an abstract syntax tree, and a tree grammar that walks that tree into the Java objects the engine runs. The syntax went through four iterations, from comma-separated text to typed, space-separated lists, and about 300 lines of grammar generate 6,700 lines of parser code.
Lists instead of loops.
Any parameter takes a list of values. The engine expands each operation into data rows, pairing values row by row and repeating shorter lists, so one GET-RULE with ten amounts and three currencies becomes ten priced quotes, each checked on its own.
Templates and environments.
Each operation maps to a request template with {{placeholders}}, and environment files supply the endpoint, SOAP action, headers, proxy, request delay and thread-pool size, so the same script runs against SIT, UAT or pre-production unchanged.
A concurrent engine, local or remote.
The engine sends data rows from a thread pool and reports a tree of results: run, test case, block, operation, data row and field. It runs inside the workbench or as a remote engine published as a SOAP web service, so long regressions can run on a test server.
A workbench that knows the language.
A Swing workbench edits scripts in tabs with syntax highlighting from a JFlex lexer I wrote for the language, loads test cases, templates and environments from HP Quality Center through a client I built for its protocol, and streams the execution log as tests run.
Outcome
I designed the language and built the toolchain end to end: grammars, engine, workbench and Quality Center client. Hornet was used in production to regression-test the pricing rules, and a rule test became a short script a tester could read, review and keep in Quality Center beside its requirement. The screenshots are the original 2012 build, run again in 2026 against a mock rules service, with client names and data replaced.
Technologies used
Data volumes & scale
- 3 ANTLR 3 grammars, ~300 lines
- ~6,700 lines of generated parser code
- 164 currency codes typed by the lexer
- 4 iterations of the syntax
- ~8,400 lines of hand-written Java
- 6 levels of result reporting
