Examples¶
The examples are split into three directories:
charts
Contains the helm charts to deploy all the sample devices
single_device_proxy
The Tango device under test (Consumer) has a single
tango.DeviceProxy
to another Tango device (Provider)Includes devices and sample tests
multi_device_proxy
The Tango device under test (Consumer) has multiple
tango.DeviceProxy
to Tango devices (Providers)Includes devices and sample tests
Pact testing Tango devices (Consumer side)¶
A simple test sample:
from tango.test_context import MultiDeviceTestContext, DeviceTestContext
from tango import DeviceAttribute
from consumer_device import ConsumerDevice
from ska_pact_tango import Consumer, Provider, Interaction
devices_info = [
{"class": ConsumerDevice, "devices": ({"name": "test/consumer/2", "properties": {}},)}
]
def test_consumer_to_provider_attribute_read():
"""Test the attribute read"""
device_attribute_response = DeviceAttribute()
device_attribute_response.value = 99.99
pact = Consumer("test/consumer/1", consumer_cls=ConsumerDevice).has_pact_with(
providers=[
Provider("test/provider/1").add_interaction(
Interaction()
.given("The provider is in Init State", "Init")
.upon_receiving("A read attribute request for the attribute random_float")
.with_request("read_attribute", "random_float")
.will_respond_with(DeviceAttribute, device_attribute_response)
)
]
)
with pact:
with MultiDeviceTestContext(devices_info, process=True) as context:
consumer = context.get_device("test/consumer/2")
assert consumer.read_provider_random_float() == device_attribute_response.value
For more examples refer to ska-pact-tango/examples
.
Tango to with_request
mapping¶
Tango syntax |
with_request |
---|---|
provider_device.random_float = 5.0 |
with_request(“attribute”, “random_float”, 5.0) |
provider_device.write_attribute(“random_float”, 5.0) |
with_request(“method”, “write_attribute”, “random_float”, 5.0) |
with_request(“write_attribute”, “random_float”, 5.0) |
|
provider_device.random_float |
with_request(“attribute”, “random_float”) |
provider_device.read_attribute(“random_float”) |
with_request(“read_attribute”, “random_float”) |
provider_device.SomeCommand() |
with_request(“command”, “SomeCommand”) |
provider_device.SomeCommand(1.0) |
with_request(“command”, “SomeCommand”, 1.0) |
provider_device.command_inout(“SomeCommand”) |
with_request(“method”, “command_inout”, “SomeCommand”) |
with_request(“command_inout”, “SomeCommand”) |
|
provider_device.command_inout(“SomeCommand”, 1.0) |
with_request(“method”, “command_inout”, “SomeCommand”, 1.0) |
with_request(“command_inout”, “SomeCommand”, 1.0) |
Verifying the Pact contract with the provider¶
Every Pact contract should be verified against a Tango device (Provider) to ensure it’s valid.
There’s a helper decorator (verifier
) that exposes the interaction to verify as well as the device name.
The verifier decorator takes to location of the pact file and the interaction description as parameters.
The description is used to get the interaction that you want to verify as there could be several in the Pact file.
Use the command line tool¶
Once the package is installed there should be a script named pact-tango-verify
on the PATH
.
This can be used to verify the Pact contract file.
root@ska-pact-tango# pact-tango-verify -h
usage: pact-tango-verify [-h] [-v] pact_file_path
Verify a Pact file against the provider
positional arguments:
pact_file_path
optional arguments:
-h, --help show this help message and exit
-v, --verbose Print test output
Example¶
root@ska-pact-tango# pact-tango-verify ./examples/multi_device_proxy/verifier_test.json -v
Loading Pact from ./examples/multi_device_proxy/verifier_test.json
Done
Checking against provider [test/multiprovider/1]
Checking interaction [A request to run add_int_to_five]
Write custom tests¶
Put the Provider in a desired state¶
You can add commands (and parameters) to execute as part of given
and and_given
in the pact definition.
During the setup_provider
step in your test they will be executed in order against the Provider.
This will update the Provider so that it’s in the correct state prior to running verify_interaction
.
See comments in the code sample below.
Example¶
import pytest
import tango
from ska_pact_tango.verifier import verifier
from ska_pact_tango.provider import Provider, Interaction
from ska_pact_tango.consumer import Consumer
pact = Consumer("test/consumer/1", consumer_cls=ProviderDevice).has_pact_with(
providers=[
Provider("test/nodb/providerdevice").add_interaction(
Interaction()
.given("The provider is in Init State", "Init")
.and_given("with_arg_command has ran", "with_arg_command", 5)
.and_given("no_arg_command has ran", "no_arg_command")
.and_given("Only description")
.upon_receiving("A request to run add_int_to_five")
.with_request("command", "add_int_to_five", 5)
.will_respond_with(int, 10)
)
]
)
@verifier("/path/to/pact_file.json", "A request to run add_int_to_five")
def verify_provider(*args, **kwargs):
interaction = kwargs["interaction"]
device_name = kwargs["device_name"]
proxy = tango.DeviceProxy(device_name)
# Here you can run commands on proxy that was not defined in the `given`s
proxy.Standby()
# setup_provider runs through the provider_states and executes the commands
# In our case it will be:
# - proxy.Init()
# - proxy.with_arg_command(5)
# - proxy.no_arg_command()
interaction.setup_provider(proxy)
# verify_interaction will execute the `with_request` and compare it to `will_respond_with`
interaction.verify_interaction(proxy)
Device test playground¶
For setting up an environment where you can run tests and experiment with them, follow the steps below:
Setup¶
Introduction¶
Deploy the sample devices by means of a local helm chart in a Kubernetes namespace.
A development container where tests can be edited and executed is also included.
Each container mounts the ska-pact-tango
directory in /app/
Install¶
Ensure you are in the
ska-pact-tango
directory.Ensure that
helm
andkubectl
has been set up.Deploy the chart of sample devices into a namespace (using
pact
below).
3.1. If you want to use the Jupyter Notebook, set your Ingress hostname
kubectl create namespace pact
helm install test ./examples/charts/pact-example -n pact --dependency-update --set pact_example.hostpath=$(pwd) --set ingress.hostname=<Your hostname>
3.2. If you don’t have Ingress configured you can omit the hostname. You will not be able to access Jupyter.
kubectl create namespace pact
helm install test ./examples/charts/pact-example -n pact --dependency-update --set pact_example.hostpath=$(pwd)
Open a shell to run commands in the container¶
kubectl exec --stdin --tty $(kubectl get pods -o name | grep pact-example) -c dev-test -n pact -- /bin/bash
Run the sample tests:
python3 -m pytest /app/ska-pact-tango/examples/sample_tests.py
Access a Jupyter Notebook to run arbitrary code¶
Navigate to:
http://<your-hostname>/jupyter/
Password: pact
Clean up¶
helm delete test -n pact
kubectl delete namespaces pact