Lua Scripting Guide

Drift testcases can be extended using Lua 5.4. This allows you to export functions to bind to testcase values or respond to lifecycle events with custom logic.

Script Structure

Every Drift script must return a Lua Table containing event_handlers and exported_functions.

local function bearer_token(token)
    return "12345678"
end

local exports = {
  event_handlers = {
    -- Respond to lifecycle events here
    ["operation:started"] = function(event, data)
      print("Starting: " .. data[2]) -- Prints operation ID
    end
  },

  exported_functions = {
    -- Map Lua functions to names used in YAML
    token = bearer_token
  }
}

return exports

Event Handlers

Events are strings structured with colons (e.g., namespace:event). You can use the * wildcard to match event patterns.

Wildcard Patterns

  • *: Matches all events.

  • operation:*: Matches all events in the operation namespace (e.g., operation:startedoperation:finished).

  • *:failed: Matches any event ending with failed (e.g., operation:failed).

  • Multiple namespaces are supported (e.g., xxx:yyy:zzz)

Core Framework Events

Event

Triggered When

plugin:loaded

A plugin is loaded.

plugin:unloaded

A plugin is unloaded.

file:loaded

A test file is loaded.

script:loaded

A Lua script is loaded.

testcase:loaded

A testcase file is loaded.

testcase:started

Testcase execution begins.

testcase:finished

Testcase execution completes.

operation:started

An operation execution begins.

operation:prepared

An operation has been prepared and is ready for invocation.

operation:invoked

An operation has been invoked (request sent).

operation:passed

Operation verification passes.

operation:failed

Operation verification fails.

operation:finished

Operation verification is complete.

http:request

(OAS Plugin) An HTTP request is created.

Event Data Modification

Some events allow the event data to be modified. To do that, return the modified table from your event handler function. Drift then merges that data before passing it to subsequent handlers.

For example, HTTP events allow you to modify headers or bodies before the request is sent:

["http:request"] = function(event, data)
  data.headers["authorization"] = "bearer 12345678"
  return data  -- Return modified data
end

Note that most events are purely informational - returning modified data will only affect subsequent event handlers, not the original event.

Bound Functions

Bound functions allow you to inject dynamic values into your yaml or validate expected values.

YAML Usage

parameters:
  authentication:
    scheme: bearer
    token: ${functions:token} # 'functions' is the namespace in sources

Function Signatures

Exported functions are invoked with a single parameter:

  • Generation mode (parameter is nil): Return a generated value for the testcase to use.

Example: Simple Token Generation

local function bearer_token(token)
  if token then
    -- Validation: Check if token is valid
    if #token < 8 then
      return error("Token too short")
    end
  else
    -- Generation: Create a new token
    return "12345678"
  end
end

Lua Dependencies

You can import other Lua scripts using standard Lua mechanisms, as long as they don't use native extensions:

local date = require "date"  -- Load another Lua module from the file system

LuaRocks Packages

LuaRocks packages are supported, with the following requirements:

  • Only pure Lua packages are supported. Native C/FFI extensions cannot be used.

  • System-wide rocks should work without modification.

  • User-local rocks must be installed to the standard LuaRocks directory:

    • Unix-like systems: $HOME/.luarocks/share/lua/5.4

Provided Helper Functions

Drift injects convenience functions directly into the Lua environment.

dbg(data)

Returns a human-readable string representation of complex Lua Tables. Useful for debugging event data.

Example:

["operation:started"] = function(event, data)
  print(dbg(data))  -- Pretty-prints the data structure
end

Output:

Table(
  Integer(1) => String("Operation description"),
  Integer(2) => String("operationId"),
  Integer(3) => String("Test case title")
)

http(request_table)

Executes synchronous HTTP requests. Essential because most Lua HTTP libraries use unsupported native extensions.

Request Fields

Field

Type

Description

url

String

Request URL (required).

method

String

HTTP method. Defaults to GET if not provided.

query

String or Table

Query parameters. If a Table, entries are formatted as key=value and separated by &.

headers

Table

HTTP request headers.

body

String or Table

Request body. If a Table, it will be rendered as JSON.

Response Fields

Field

Type

Description

status

Integer

HTTP response status code.

headers

Table

Response headers.

body

String or Table

Response body. JSON payloads are automatically parsed into Tables; other content types are returned as Strings.

Example

local res = http({
  url = "http://localhost:8080/api/users",
  method = "POST",
  headers = {
    ["Content-Type"] = "application/json",
    ["Authorization"] = "Bearer token123"
  },
  body = { name = "John", email = "john@example.com" }
})

if res.status == 201 then
  print("User created: " .. res.body.id)
else
  print("Error: " .. res.status)
end

Script Requirements & Limitations

Lua Engine must be embedded Lua 5.4 VM.

Capabilities

Scripts have access to:

  • OS environment (via standard Lua os module)

  • File system (via standard Lua io module)

  • Networking (via the provided http() function and other Lua networking libraries)

  • Using other Lua scripts (via require() for pure Lua modules)

  • LuaRocks packages (as long as they are pure Lua)

Restrictions

No C/FFI extensions are supported. This means that ative Lua extensions cannot be used and LuaRocks packages must be pure Lua only. Pure Lua LuaRocks packages can be used if installed to the standard location:Unix-like systems: $HOME/.luarocks/share/lua/5.4

Publication date: