Code Examples
Compatibility
Runner Client 3.x exposes asynchronous APIs and is the recommended client for Runner 2.x servers.
- Working with Images and starting Sessions based on Images
- Simple session creation based on Runner installation
- Create and execute a test plan
- Load and execute a test plan
- Receiving results, logs and events from a Session
- How to work with component settings
- Configuring a Runner for default execution and using stored test plans on the Runner
Image creation
For this example we have a Runner started which has the ID: HKZ6QN3
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using NATS.Client.Core;
using OpenTap.Runner.Client;
await using INatsConnection connection = new NatsConnection(new NatsOpts { Url = RunnerClient.DefaultUrl });
RunnerClient runner = new RunnerClient(connection);
Image image = new Image
{
Packages = new List<PackageSpecifier>
{
new PackageSpecifier { Name = "Demonstration" },
new PackageSpecifier { Name = "HTTP", Version = "1.0.0" },
// We can even specify a different runner version for the session
new PackageSpecifier { Name = "Runner", Version = "1.2.1" }
},
Repositories = new List<string> { "https://packages.opentap.io" }
};
Image? resolvedImage = await runner.ResolveImageAsync(new List<Image> { image });
if (resolvedImage is null)
throw new InvalidOperationException("Image resolution failed.");
SessionClient newSession = await runner.StartImageSessionAsync(resolvedImage);
// Use the session for test automation
await runner.ShutdownSessionAsync(newSession.Id);
In this example, we successfully resolved an image, started and stopped a session based on the image. This can be verified in the Runner
logs:
Session creation
Although the Image approach offers flexibility, some use-cases can be kept simple by just using a Runner Session
based on the Runner
installation.
using NATS.Client.Core;
using OpenTap.Runner.Client;
await using INatsConnection connection = new NatsConnection(new NatsOpts { Url = RunnerClient.DefaultUrl });
RunnerClient runner = new RunnerClient(connection);
SessionClient newSession = await runner.StartSessionAsync();
// Use the session for test automation. Plugins available in this session
// come from the packages installed in the Runner.
await runner.ShutdownSessionAsync(newSession.Id);
Create and Run Test Plan
In this example, we use the simple session from the Session creation example above, but before shutting down the session, we setup and run a simple test plan.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NATS.Client.Core;
using OpenTap.Runner.Client;
await using INatsConnection connection = new NatsConnection(new NatsOpts { Url = RunnerClient.DefaultUrl });
RunnerClient runner = new RunnerClient(connection);
SessionClient newSession = await runner.StartSessionAsync();
List<TestStepType> types = await newSession.GetStepTypesAsync();
TestPlan plan = await newSession.GetTestPlanAsync(null);
plan.ChildTestSteps.Clear();
plan.ChildTestSteps.Add(types.First(step => step.TypeName.Contains("Delay")));
plan = await newSession.SetTestPlanAsync(plan);
Settings delayStepSettings = await newSession.GetSettingsAsync(plan.ChildTestSteps[0].Id);
if (delayStepSettings.FirstOrDefault(s => s.PropertyName == "DelaySecs") is TextBoxControl textBox)
textBox.StringValue = "3 s";
delayStepSettings = await newSession.SetSettingsAsync(plan.ChildTestSteps[0].Id, delayStepSettings);
RunStatus status = await newSession.RunTestPlanAsync(new List<Parameter>());
while (status.SessionState != SessionState.Idle)
{
await Task.Delay(1000);
status = await newSession.GetStatusAsync();
}
Console.WriteLine(status.Verdict);
await runner.ShutdownSessionAsync(newSession.Id);
In this example, we retrieved the available test step types using GetStepTypes
and chose a Delay
step and inserted into the Test Plan using SetTestPlan
.
Afterwards, we retrieved the Delay
step settings and modified the Time Delay
to be 3 s
.
Lastly, we ran the Test Plan and contiunually asked for the status until the SessionState
turned back to Idle
. The Verdict of the Test Plan was logged and the output of this program would be NotSet
.
Load and Run Test Plan
In this example, we use the simple session from the Session creation example above, but before shutting down the session, we load and run a Test Plan locally stored on the disk.
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using NATS.Client.Core;
using OpenTap.Runner.Client;
await using INatsConnection connection = new NatsConnection(new NatsOpts { Url = RunnerClient.DefaultUrl });
RunnerClient runner = new RunnerClient(connection);
SessionClient newSession = await runner.StartSessionAsync();
await newSession.SetTestPlanXMLAsync(File.ReadAllText("MyTestPlan.TapPlan"));
RunStatus status = await newSession.RunTestPlanAsync(new List<Parameter>());
while (status.SessionState != SessionState.Idle)
{
await Task.Delay(1000);
status = await newSession.GetStatusAsync();
}
Console.WriteLine(status.Verdict);
await runner.ShutdownSessionAsync(newSession.Id);
Results, Logs and Events
In this example, we use the simple session from the Create and Run Test Plan section above, but with results, logs and events logged.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NATS.Client.Core;
using OpenTap.Runner.Client;
await using INatsConnection connection = new NatsConnection(new NatsOpts { Url = RunnerClient.DefaultUrl });
RunnerClient runner = new RunnerClient(connection);
SessionClient newSession = await runner.StartSessionAsync();
newSession.ConnectSessionLogs(LogHandler);
Task LogHandler(LogList? list)
{
if (list?.Logs != null)
foreach (var log in list.Logs)
Console.WriteLine($"{log.Source,-12}: {log.Message}");
return Task.CompletedTask;
}
newSession.ConnectSessionResults(ResultHandler, RunHandler);
Task ResultHandler(Result? result)
{
if (result != null)
Console.WriteLine($"Result: {result.Status}");
return Task.CompletedTask;
}
Task RunHandler(TestRun? run)
{
if (run != null)
Console.WriteLine($"Run: {run.Status}");
return Task.CompletedTask;
}
newSession.ConnectSessionEvents(EventHandler);
Task EventHandler(SessionEvent? evt)
{
if (evt != null)
Console.WriteLine($"Event: {evt.GetType().Name}");
return Task.CompletedTask;
}
List<TestStepType> types = await newSession.GetStepTypesAsync();
TestPlan plan = await newSession.GetTestPlanAsync(null);
plan.ChildTestSteps.Clear();
plan.ChildTestSteps.Add(types.First(step => step.TypeName.Contains("Delay")));
plan = await newSession.SetTestPlanAsync(plan);
Settings delayStepSettings = await newSession.GetSettingsAsync(plan.ChildTestSteps[0].Id);
if (delayStepSettings.FirstOrDefault(s => s.PropertyName == "DelaySecs") is TextBoxControl textBox)
textBox.StringValue = "3 s";
delayStepSettings = await newSession.SetSettingsAsync(plan.ChildTestSteps[0].Id, delayStepSettings);
RunStatus status = await newSession.RunTestPlanAsync(new List<Parameter>());
while (status.SessionState != SessionState.Idle)
{
await Task.Delay(1000);
status = await newSession.GetStatusAsync();
}
Console.WriteLine(status.Verdict);
await runner.ShutdownSessionAsync(newSession.Id);
This code should produce the following output, where events, runs and results are prepended with “Event: “, “Run: “, and “Result: “.
Working with ComponentSettings
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NATS.Client.Core;
using OpenTap.Runner.Client;
await using INatsConnection connection = new NatsConnection(new NatsOpts { Url = RunnerClient.DefaultUrl });
RunnerClient runner = new RunnerClient(connection);
SessionClient newSession = await runner.StartSessionAsync();
try
{
List<ComponentSettingsIdentifier> componentSettings = await newSession.GetComponentSettingsOverviewAsync();
foreach (var componentSetting in componentSettings)
Console.WriteLine($"Component Setting: {componentSetting.Name} ({componentSetting.GroupName})");
// Outputs:
// Component Setting: DUTs(Bench)
// Component Setting: Engine(-)
// Component Setting: Instruments(Bench)
// Component Setting: Connections(Bench)
// Component Setting: Results(-)
// Component Setting: Editor(-)
// Component Setting: Cloud Drive(-)
ComponentSettingsIdentifier instrumentIdentifier = componentSettings
.First(s => s.Name == "Instruments" && s.GroupName == "Bench");
List<ListItemType> instrumentTypes = await newSession.GetComponentSettingsListAvailableTypesAsync(
instrumentIdentifier.GroupName,
instrumentIdentifier.Name);
foreach (var instrumentType in instrumentTypes)
Console.WriteLine($"Instrument Type: {string.Join("/", instrumentType.TypeDisplay.Group)}/{instrumentType.TypeDisplay.Name}");
// Outputs:
// Instrument Type: / Generic SCPI Instrument
// Instrument Type: Demo / Battery Test / Power Analyzer
// Instrument Type: Demo / Battery Test / Temperature Chamber
// Instrument Type: Demo / Results And Timing/ Timing Instrument
ComponentSettingsBase instruments = await newSession.GetComponentSettingsAsync(
instrumentIdentifier.GroupName,
instrumentIdentifier.Name);
if (instruments is ComponentSettingsList list)
foreach (var instrument in list.Items)
Console.WriteLine($"Instrument: {instrument.Name}");
// Outputs:
// Instrument: SCPI
// Instrument: PSU
// Instrument: TEMP
ComponentSettingsBase updated = await newSession.AddComponentSettingsListItemAsync(
instrumentIdentifier.GroupName,
instrumentIdentifier.Name,
instrumentTypes.First(type => type.TypeDisplay.Name == "Power Analyzer").TypeName);
if (updated is ComponentSettingsList listWithNewItem)
{
foreach (var instrument in listWithNewItem.Items)
Console.WriteLine($"Instrument: {instrument.Name}");
// Outputs:
// Instrument: SCPI
// Instrument: PSU
// Instrument: TEMP
// Instrument: PSU (1)
foreach (var setting in listWithNewItem.Items[^1].Settings)
{
Console.WriteLine($"Setting: {setting.Display.Name}");
if (setting is TextBoxControl textBox)
Console.WriteLine(textBox.StringValue);
}
}
// Outputs:
// Setting: Cell Size Factor
// 0.005
}
finally
{
await runner.ShutdownSessionAsync(newSession.Id);
}
Default Endpoints
Default endpoints are endpoints that affect each other. They are:
- SetDefaultImage: Sets a default image in the Runner environment. The image includes essential packages.
- GetDefaultImage: Retrieves the currently set default image.
- SetDefaultSettings: Applies default settings for the Runner. Settings might have various package dependencies.
- GetDefaultSettings: Retrieves the current settings from the Runner.
- StartDefaultSession: Starts a session using the default settings and image.
- StartDefaultSessionOverrideImage: Begins a session with an overridden image for specific use cases.
- SetTestPlans: Sets a list of test plans to be used in the Runner.
- AddTestPlan: Adds a single test plan to the current list in the Runner.
- GetTestPlans: Retrieves the list of test plans stored in the Runner.
A Session’s plugin configuration depends on:
- The dependencies of the TestPlan.
- The dependencies of the Settings.
- The packages defined in a “default image”.
- Optionally, the packages defined in an “image override”.
The following example demonstrates how to use the RunnerClient for managing test plans in a Runner session.
public static async Task DefaultTestPlanShowcaseAsync(RunnerClient runnerClient)
{
Image baseImage = new()
{
Packages = new List<PackageSpecifier>
{
new PackageSpecifier { Name = "Runner", Version = "1.7.0" }
},
Repositories = new List<string>
{
"https://packages.opentap.io"
}
};
await runnerClient.Default.SetImageAsync(baseImage); // Apply the base image configuration
RepositoryPackageReference settingsPackageReference = new()
{
Repository = "https://test-automation.pw.keysight.com/api/packages",
Path = "/users/dennis.rasmussen@keysight.com/BatterySettings.TapPackage",
Version = "0.2.0"
};
await runnerClient.Default.SetSettingsAsync(settingsPackageReference); // Apply settings package
RepositoryPackageReference testPlanReference = new()
{
Repository = "https://test-automation.pw.keysight.com/api/packages",
Path = "/users/dennis.rasmussen@keysight.com/BatteryPlan.TapPlan",
Version = "0.1.0-Draft.5"
};
SessionClient session = await runnerClient.Default.StartSessionAsync(testPlanReference);
try
{
RunStatus status = await session.RunTestPlanAsync(new List<Parameter>());
while (status.SessionState != SessionState.Idle)
{
await Task.Delay(1000);
status = await session.GetStatusAsync();
}
Console.WriteLine($"Verdict: {status.Verdict}");
}
finally
{
await session.ShutdownAsync();
await runnerClient.ShutdownSessionAsync(session.Id);
}
}
Future code examples:
- Editing Step and TestPlan settings
- Load from and save to Repository