Debugging OpenTAP Plugins in the Runner

When developing an OpenTAP plugin that will run inside the Runner, you can attach a debugger to the session process and step through your plugin code. The recommended approach is to install the Runner into your plugin’s build output directory, enable development mode, and then start the Runner from there.

Overview

In normal operation the Runner deploys sessions into isolated image directories under the system temp folder. This means the session process loads plugins from a deployed copy — not from your build output — making it impossible to hit breakpoints in your source code.

Development mode changes this behaviour so that every session runs directly from the Runner’s own installation directory. When the Runner is installed into your build output, sessions load your locally built plugin DLLs and you can attach a debugger to the session process.

Prerequisites

  • An OpenTAP installation with the Runner and NATS Server packages installed.
  • Your plugin project builds into (or copies output to) a directory that also contains the OpenTAP installation.

Step-by-step setup

1. Install the Runner in your plugin’s build output

Add the Runner and NATS Server packages to the OpenTAP installation located in your build output directory. If you are using the OpenTAP NuGet package, this is typically the bin/Debug/net8.0 (or equivalent) folder where tap.dll lives.

cd <your-plugin-build-output>
./tap package install "Runner"

After this step the build output directory contains both the Runner and your plugin DLLs side by side.

2. Set the development mode environment variable

Before starting the Runner, set OPENTAP_RUNNER_DEVELOPMENT_MODE to 1:

Linux / macOS

export OPENTAP_RUNNER_DEVELOPMENT_MODE=1
./tap runner start

Windows (PowerShell)

$env:OPENTAP_RUNNER_DEVELOPMENT_MODE = "1"
.\tap.exe runner start

Windows (cmd)

set OPENTAP_RUNNER_DEVELOPMENT_MODE=1
tap.exe runner start

On startup the Runner logs a warning to confirm the mode is active:

[WRN] Development mode is enabled!

3. Start a session and attach the debugger

Use any client (C# console app, KS8500, or the code examples in this documentation) to create a session on the Runner. Because development mode is enabled, the session process starts in the Runner’s own directory — your build output — and loads your plugin code.

Find the session’s process ID in the Runner logs or with your OS process tools and attach your IDE debugger to it.

Visual Studio: Debug > Attach to Process, filter for dotnet processes, select the session process.

JetBrains Rider: Run > Attach to Process, select the session process. Rider run configurations support AUTO_ATTACH_CHILDREN which can automatically attach to the spawned session process.

VS Code: Use the .NET: Attach launch configuration targeting the session process ID.

Once attached, set breakpoints in your plugin source and run a test plan that exercises your plugin. Execution pauses at your breakpoints as expected.

What development mode changes

Development mode adjusts several Runner behaviours to support an interactive debugging workflow:

Behaviour Normal Development mode
Session working directory Deployed image directory (under system temp) Runner’s own installation directory (your build output)
Image on StartImageSession Client-specified image is deployed Image is ignored — session always uses the local directory
Session heartbeat timeout 7 seconds 30 minutes
Watchdog termination timeout Client-controlled Always 30 minutes

The extended timeouts prevent the Runner from killing a session that is paused in a debugger. In normal operation, if a session stops sending heartbeats for more than 7 seconds the Runner terminates it. Development mode raises this to 30 minutes so you can step through code without the session being reaped.

The watchdog — which terminates idle sessions after a configurable period — is similarly overridden to 30 minutes regardless of the value set by the client.

IDE run configuration examples

JetBrains Rider / IntelliJ

Create a .NET Project run configuration that builds and launches the Runner with the environment variable set. Enable Auto Attach Children Processes so that Rider automatically attaches the debugger to session processes spawned by the Runner.

<envs>
    <env name="OPENTAP_RUNNER_DEVELOPMENT_MODE" value="1" />
</envs>

Visual Studio (launchSettings.json)

{
  "profiles": {
    "Runner (Dev)": {
      "commandName": "Project",
      "commandLineArgs": "runner start",
      "environmentVariables": {
        "OPENTAP_RUNNER_DEVELOPMENT_MODE": "1"
      }
    }
  }
}

VS Code (launch.json)

{
  "name": "Runner (Dev)",
  "type": "coreclr",
  "request": "launch",
  "program": "${workspaceFolder}/tap.dll",
  "args": ["runner", "start"],
  "env": {
    "OPENTAP_RUNNER_DEVELOPMENT_MODE": "1"
  }
}

Environment variable reference

Variable Values Description
OPENTAP_RUNNER_DEVELOPMENT_MODE 1 or true Enables development mode

Tips

  • Rebuild and restart: After rebuilding your plugin, restart the Runner so the new DLLs are loaded. Sessions started before the rebuild still reference the old assemblies.
  • Single session: In development mode, image resolution is skipped, so all sessions share the same directory and plugin set. Run one session at a time to avoid conflicts.
  • Breakpoints in test steps: Development mode is about attaching a system debugger to the session process. This is separate from the Runner’s built-in test plan breakpoints, which pause test plan execution at specific steps without a debugger. Both can be used together.