Hello Endpoint test
Hello World ran on the controller's own machine. Hello Endpoint is the simplest test that runs on an
endpoint: one flow sends one step to the machine chosen in the run panel, and the step runs the
hostname command there and logs the answer. It needs an endpoint registered and licensed in the
controller, as Adding endpoints walks through.
Open the test's folder in your IDE and let's review its three files:
orcraft-test-suite-tutorial/test_group_endpoints/test_hello_endpoint/
The test
class TestHelloEndpointConfig(OrcraftTestConfig):
name = OrcraftConfigField.Text(default="Hello Endpoint")
description = OrcraftConfigField.Text(
default=(
"The simplest test that runs on an endpoint.\n"
"One flow sends one step to the Test Endpoint; the step runs the hostname command there and logs the answer.\n"
"With the default localhost the step runs on the controller's machine; choose an endpoint in the run panel and it runs there."
)
)
test_endpoint = OrcraftConfigField.Endpoint(default="localhost", label="Test Endpoint")
The config adds one field to what Hello World had: an
Endpoint field named
test_endpoint. Its value is one of the endpoints registered in the controller, and the run panel
shows it as Test Endpoint with a pencil to choose the machine. The default,
localhost, is the controller's own machine.
class TestHelloEndpointResult(OrcraftTestResult):
hostname = OrcraftResultField.Text(default="", label="Hostname")
class TestHelloEndpoint(OrcraftTest):
def __init__(self, config: TestHelloEndpointConfig | None = None) -> None:
super().__init__(config or TestHelloEndpointConfig())
def _run_case(self, case: OrcraftTestCase) -> OrcraftTestResult:
case.result = TestHelloEndpointResult()
flow = FlowHelloEndpoint(FlowHelloEndpointConfig())
flow_result = flow.run()
if self.handle_errors(flow_result, case.result):
return case.result
case.result.hostname = flow_result.hostname
return case.result
The test case runs one flow and copies the host name
the flow brings back into its own result field.
handle_errors ends the case when the flow failed or errored, so the result below is filled
only on a pass.
The flow
class FlowHelloEndpoint(OrcraftTestFlow):
result_type = FlowHelloEndpointResult
def __init__(self, config: FlowHelloEndpointConfig) -> None:
super().__init__(config)
def _run_flow(self) -> None:
# No endpoint is named here: the step goes to the test's Test Endpoint.
step_result = self.run_step(StepHostname)
if self.handle_errors(step_result, self.result):
return
self.result.hostname = step_result.hostname
A step is run through a flow's run_step. The call names no endpoint, so the step goes to the
test's Test Endpoint. That is the whole mechanism: the flow and the step never mention a
machine, and the run panel decides where they run.
The step
class StepHostname(OrcraftTestStep):
def __init__(self, config: StepHostnameConfig | None = None) -> None:
super().__init__(config or StepHostnameConfig())
def _run_step(self) -> OrcraftTestStepResult:
self.result = StepHostnameResult()
# The step's body runs on the endpoint it was sent to, so the command
# answers with that machine's name.
completed = subprocess.run(["hostname"], capture_output=True, text=True)
hostname = completed.stdout.strip()
self.checkpoint(
completed.returncode == 0 and bool(hostname),
f"hostname answered: {hostname}",
f"hostname failed with exit code {completed.returncode}: {completed.stderr.strip()}",
)
Logger.log(f"Hello from {hostname}", color=Logger.Color.BLUE)
self.result.hostname = hostname
return self.result
The body of _run_step is what runs on the endpoint. It is plain Python: it calls the
hostname command with subprocess, checks the answer with a
checkpoint, logs one line and returns the name in the
step's result. The step's log and result travel back to the controller like any other step's.
Running from CLI
The test imports its flow and step as packages of the suite, so it runs as a module from the suite's folder. With no endpoint chosen, the step runs on this machine:
cd orcraft-test-suite-tutorial
python -m test_group_endpoints.test_hello_endpoint.test_hello_endpoint
Orcraft Controller (v0.1.0.dev306+l1)
-------------------------------------
Test: Hello Endpoint | Description
The simplest test that runs on an endpoint.
One flow sends one step to the Test Endpoint; the step runs the hostname command there and logs the answer.
With the default localhost the step runs on the controller's machine; choose an endpoint in the run panel and it runs there.
Test: Hello Endpoint | Configuration
Name | Upload Test Package | Update Endpoint App | Test Endpoint | Start Time
-----------------------------------------------------------------------------------------------------------
Test: Hello Endpoint | if_missing | on_mismatch | localhost | 2026-10-23 14:56:43.921
Skipping lock for local target localhost
Flow: Hello Endpoint | Configuration
Start Time
------------------------
2026-10-23 14:56:43.926
Step: Hostname | Configuration
Start Time | Target Endpoint
------------------------------------------
2026-10-23 14:56:43.926 | localhost
Checkpoint Pass hostname answered: GMG-DESKTOP
[StepHostname] Hello from GMG-DESKTOP
Step: Hostname | Result
Name | Status | Finish Time | Elapsed Time | Hostname
-------------------------------------------------------------------------------
Step: Hostname | PASS | 2026-10-23 14:56:43.941 | 0.015 s | GMG-DESKTOP
Flow: Hello Endpoint | Result
Name | Status | Finish Time | Elapsed Time | Hostname
-------------------------------------------------------------------------------------
Flow: Hello Endpoint | PASS | 2026-10-23 14:56:43.942 | 0.016 s | GMG-DESKTOP
Test: Hello Endpoint | Result
Name | Test: Hello Endpoint
Status | PASS
Finish Time | 2026-10-23 14:56:43.944
Elapsed Time | 0.023 sThe step's configuration table shows its Target Endpoint, localhost, and the
Hello from line names the controller's machine.
Running on an endpoint
In the controller, select Hello Endpoint and click the pencil at the right of Test Endpoint. Choose the endpoint:
Click Run and confirm. Changing only the endpoint needs no
Update Plan: the plan counts cases, and the endpoint is not one. The step's table now shows the endpoint as its Target Endpoint, and
Hello from names that machine:
Before the first step ran, the controller uploaded the suite's code to the endpoint: the Upload Test Package row of the run panel, set to If Missing, does that once and again whenever the code changes. The Packages Uploading page explains it.