Writing a hooks handler for a new language
Dredd itself is written in JavaScript, so having hooks in JavaScript is native to it. Other languages need so-called hooks handlers.
Several hooks handlers already exist, either maintained by Dredd authors or external contributors. If you didn’t find your favorite language among them, at this place you can learn how to create a new hooks handler.
Note
Deserve eternal praise and contribute hooks handler for Java! See #875
What is a hooks handler?
Hooks handler is a process running separately from Dredd, usually started by Dredd as a child process when invoking Dredd with the --language
option. When Dredd performs testing, it communicates with the hooks handler over TCP socket. The hooks handler runs hooks for each HTTP transaction and lets Dredd know whether something got modified.
Hooks handler life cycle
Dredd starts the command given in the
--language
option as its child process (subprocess). Paths to files with hooks given in--hookfiles
are resolved to absolute paths and given to the child process as arguments.The hooks handler reads paths to hooks from arguments and loads the hooks code.
The hooks handler opens a TCP socket on localhost, port 61321.
Dredd waits for a moment and then tries to connect to localhost, port 61321.
For each type of hooks Dredd creates a message and sends it to the socket. The message contains UUID and serialized transaction object (or an array of them, in case of beforeAll, afterAll). Individual messages are sent as JSON documents separated by a newline.
Hooks handler reads a message, calls a corresponding hook code, and sends back a message with modified contents.
Dredd awaits a message with corresponding UUID. Once it arrives, Dredd overwrites its internal HTTP transaction data with the ones from the incoming message.
Implementation guide
A hooks handler is a CLI command, which implements following:
It accepts paths to hook files as arguments. They are already passed resolved as absolute paths, in the right order.
It allows users to register hook functions in the hook files, i.e. it provides a hooks API similar to those in other hooks handler implementations (see JavaScript, Python, Ruby). It allows to register all types of hooks supported by Dredd.
It loads the hook files and registers any hook functions found in them for later execution.
It runs a TCP socket server on port 61321 and prints
Starting
tostdout
when ready.
Handling hooks
When any data is received by the TCP server, the hooks handler:
Adds every received character to a buffer.
When the delimiter
LINE FEED (LF)
character encoded as UTF-8 (0A
hex,\n
in most languages) is received:Parses the message in the buffer as JSON.
Finds the hook type in the
event
key of the received object and executes respective registered hook function(s). Beware,beforeEach
andafterEach
are overloaded - read the TCP socket message format carefully.
When a hook function is being executed:
Passes the value of the
data
key of the received object to the executed hook function.Allows the hook function to modify the data.
When a hook function is done:
Takes the modified data and serializes it back to JSON with the same
uuid
as it has receivedSends the JSON back as a TCP message
Sends a
LINE FEED (LF)
character encoded as UTF-8 (0A
hex,\n
in most languages) as TCP message delimiter
TCP socket message format
transaction (object)
uuid:
234567-asdfghjkl
(string) - ID used for unique identification of the message on both server and client sidesevent:
event
(enum) - Hook typebeforeAll (string) - Signals the hooks handler to run the
beforeAll
hooksbeforeEach (string) - Signals the hooks handler to run the
beforeEach
andbefore
hooksbeforeEachValidation (string) - Signals the hooks handler to run the
beforeEachValidation
andbeforeValidation
hooksafterEach (string) - Signals the hooks handler to run the
after
andafterEach
hooksafterAll (string) - Signals the hooks handler to run the
afterAll
hooks
data (enum) - Data passed as an argument to the hook function
(object) - Single transaction object
(array) - An array of transaction objects, containing all transactions Dredd currently works with; sent for
beforeAll
andafterAll
events
Termination
When there is an error or when the testing is done, Dredd signals the hooks handler process to terminate. This is done repeatedly with delays. When termination timeout is over, Dredd loses its patience and kills the process forcefully.
retry delays can be configured by
--hooks-worker-term-retry
timeout can be configured by
--hooks-worker-term-timeout
On Linux or macOS, Dredd uses the SIGTERM
signal to tell the hooks handler process it should terminate. On Windows, where signals do not exist, Dredd sends the END OF TEXT
character (03
hex, which is ASCII representation of Ctrl+C) to standard input of the process.
End-to-end test suite
There is a BDD test suite called dredd-hooks-template, which ensures that the public interface of each hooks handler works as Dredd expects. The test suite is written in Gherkin and uses Cucumber as a test runner.
When developing a new hooks handler, make sure it passes the test suite. Third party hooks handlers not passing the test suite cannot be endorsed by Dredd maintainers, integrated with Dredd’s --language
option, or added to Dredd’s documentation.
If you have any issues integrating the test suite to your project, reach out to the maintainers in Dredd issues, we’re happy to help!
Configuration options
There are several configuration options, which can help you during development of the hooks handler:
Warning
Behavior of the following options is currently broken (see #917) and it is recommended to stick to localhost and port 61321 until fixed:
Note
The options mention hooks worker in their names, but it stands for the same as hooks handler. There is a proposal to rename the options in the future: #1101