REST-API vs Runner
The OpenTAP Runner represents an evolution from the previous OpenTAP REST-API. Our experience highlighted challenges in supporting cloud scenarios with the OpenTAP REST-API, particularly when attempting to access a PC behind a firewall or within a subnet.
To address these challenges, we integrated NATS technology, retaining the core business logic of the OpenTAP REST-API, but replacing ASP.NET Core with NATS.
Given the nature of the changes involved in this transition, particularly the shift in the underlying transport mechanism, some breaking changes were unavoidable. To signal this significant change and the departure from the REST-API model, we established the OpenTAP Runner.
In the past, we provided an autogenerated C# client for the OpenTAP REST-API (OpenTAP.RestApi.Clients.CSharp). However, in light of our experiences, we elected to manually create a C# client (OpenTAP.Runner.Client) and a TypeScript client (OpenTap Runner Client) for the OpenTAP Runner. These have been designed with improvements derived from our experiences with the REST-API client.
Migrating from REST-API to Runner
Migrating from OpenTAP REST-API to OpenTAP Runner is trivial if the provided C# or TypeScript clients were consumed. If so, the migration consists of two steps:
- Exchange the client package
C# Client: Remove the NuGet REST-API client dependency OpenTAP.RestApi.Clients.CSharp and instead add the Runner client dependency OpenTAP.Runner.Client
TypeScript Client: Remove the NPM REST-API client dependency opentap-restapi-clients and instead add the Runner client dependency @opentap/runner-client
- Migrate the code by using synchronous APIs instead of asynchronous.
The API is generally the same, except for minor optimizations. However, they are all made synchronous.
The following C# example converts a code snippet which retrieves test step types, adds a delay step to the testplan, modifies the Time Delay
property on the delay step to 3s
, runs the test plan and waits for the test plan execution to complete.
The REST-API code would look like this:
var types = await sessionClient.GetTestStepTypesAsync();
var plan = await sessionClient.GetTestPlanAsync(null);
plan.ChildTestSteps.Clear();
plan.ChildTestSteps.Add(types.FirstOrDefault(s => s.TypeName.Contains("Delay")));
plan = await sessionClient.SetTestPlanAsync(plan);
var delayStepSettings = await sessionClient.GetSettingsAsync(plan.ChildTestSteps[0].Id);
if (delayStepSettings.FirstOrDefault(s => s.PropertyName == "DelaySecs") is TextBoxControl textBox)
textBox.StringValue = "3 s";
delayStepSettings = await sessionClient.SetSettingsAsync(plan.ChildTestSteps[0].Id, delayStepSettings);
var status = await sessionClient.RunTestPlanAsync();
while (status.ExecutionState != ExecutionState.Idle)
{
await Task.Delay(1000);
status = await sessionClient.GetStatusAsync(0);
}
The migrated Runner code:
var types = sessionClient.GetStepTypes();
var plan = sessionClient.GetTestPlan(null);
plan.ChildTestSteps.Clear();
plan.ChildTestSteps.Add(types.FirstOrDefault(s => s.TypeName.Contains("Delay")));
plan = sessionClient.SetTestPlan(plan);
var delayStepSettings = sessionClient.GetSettings(plan.ChildTestSteps[0].Id);
if (delayStepSettings.FirstOrDefault(s => s.PropertyName == "DelaySecs") is TextBoxControl textBox)
textBox.StringValue = "3 s";
delayStepSettings = sessionClient.SetSettings(plan.ChildTestSteps[0].Id, delayStepSettings);
var status = sessionClient.RunTestPlan(new List<Parameter>());
while (status.ExecutionState != ExecutionState.Idle)
{
await Task.Delay(1000);
status = sessionClient.GetStatus();
}
Although the majority of the code migration is trivial, the RunnerClient and SessionClient creation is different due to the underlying transport mechanism change from REST to NATS.
The following snippets demonstrates the migration of REST client construction to Runner client construction:
HttpClient httpClient = new HttpClient(handler);
SessionManagerClient sessionManagerClient = new SessionManagerClient(httpClient) { BaseUrl = "https://localhost:20116" };
var session = await sessionManagerClient.StartSessionAsync();
SessionClient sessionClient1 = new SessionClient(httpClient) { BaseUrl = session.Url };
The migrated code:
var options = ConnectionFactory.GetDefaultOptions();
options.Servers = new string[] { "nats://127.0.0.1:20111" };
IConnection connection = new ConnectionFactory().CreateConnection(options);
RunnerClient runner = new RunnerClient("UBTXJ2ZEM32HLTEXD2VCTSNN5DIGABOBKR2E2JJR53X5KX2WVJRBE3X6", connection);
SessionClient sessionClient = runner.StartSession();