mirror of
https://github.com/kernelkit/infix.git
synced 2026-08-06 23:43:20 +02:00
test: Add GPS test
Only possible to run on virtual Qemu instances right now.
This commit is contained in:
@@ -7,3 +7,6 @@
|
||||
|
||||
- name: Watchdog reset on system lockup
|
||||
case: watchdog/test.py
|
||||
|
||||
- name: GPS receiver basic test
|
||||
case: gps_simple/test.py
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
test.adoc
|
||||
@@ -0,0 +1,29 @@
|
||||
=== GPS receiver basic test
|
||||
|
||||
ifdef::topdoc[:imagesdir: {topdoc}../../test/case/hardware/gps_simple]
|
||||
|
||||
==== Description
|
||||
|
||||
Verify that a simulated GPS receiver is detected and reports a valid
|
||||
fix via the ietf-hardware operational datastore.
|
||||
|
||||
The test injects NMEA sentences through a QEMU pipe chardev FIFO,
|
||||
which appears as a virtio serial port inside the guest.
|
||||
|
||||
==== Topology
|
||||
|
||||
image::topology.svg[GPS receiver basic test topology, align=center, scaledwidth=75%]
|
||||
|
||||
==== Sequence
|
||||
|
||||
. Set up topology and attach to target DUT
|
||||
. Configure GPS hardware component
|
||||
. Verify GPS is activated
|
||||
. Verify GPS has a fix
|
||||
. Verify the position is near the coordinates you test with
|
||||
. Save the configuration to startup configuration and reboot
|
||||
. Verify GPS is activated
|
||||
. Verify GPS has a fix
|
||||
. Verify the position is near the coordinates you test with
|
||||
|
||||
|
||||
Executable
+119
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
"""GPS receiver basic test
|
||||
|
||||
Verify that two simulated GPS receivers are detected and report valid
|
||||
fixes via the ietf-hardware operational datastore.
|
||||
|
||||
The test injects NMEA sentences through QEMU pipe chardev FIFOs,
|
||||
which appear as virtio serial ports inside the guest.
|
||||
"""
|
||||
import infamy
|
||||
import infamy.gps as gps
|
||||
from infamy.util import until, wait_boot
|
||||
|
||||
# Fun facts: The top of mount everest
|
||||
test_lat = 27.9881
|
||||
test_lon = 86.9250
|
||||
test_alt = 8848.86
|
||||
|
||||
|
||||
def _near(a, b, tol):
|
||||
return abs(a - b) <= tol
|
||||
|
||||
def verify_position(target, name="gps0"):
|
||||
state = gps.get_gps_state(target, name)
|
||||
|
||||
try:
|
||||
lat = float(state["latitude"])
|
||||
lon = float(state["longitude"])
|
||||
alt = float(state["altitude"])
|
||||
except (KeyError, TypeError, ValueError):
|
||||
test.fail()
|
||||
|
||||
if not _near(lat, test_lat, 0.01):
|
||||
test.fail()
|
||||
if not _near(lon, test_lon, 0.01):
|
||||
test.fail()
|
||||
if not _near(alt, test_alt, 100):
|
||||
test.fail()
|
||||
|
||||
try:
|
||||
sat_used = int(state["satellites-used"])
|
||||
except (KeyError, TypeError, ValueError):
|
||||
test.fail()
|
||||
|
||||
if sat_used != 8:
|
||||
test.fail()
|
||||
|
||||
with infamy.Test() as test:
|
||||
with test.step("Set up topology and attach to target DUT"):
|
||||
env = infamy.Env()
|
||||
target = env.attach("target", "mgmt")
|
||||
|
||||
phys_name = env.ltop.mapping["target"][None]
|
||||
|
||||
if not target.has_feature("infix-hardware", "gps"):
|
||||
test.skip()
|
||||
|
||||
# These are hacks, will only work on virtual devices
|
||||
pipe0 = f"/tmp/{phys_name}-gps"
|
||||
pipe1 = f"/tmp/{phys_name}-gps1"
|
||||
|
||||
with gps.NMEAGenerator(pipe0, lat=test_lat, lon=test_lon, alt=test_alt), \
|
||||
gps.NMEAGenerator(pipe1, lat=test_lat, lon=test_lon, alt=test_alt):
|
||||
|
||||
with test.step("Configure GPS hardware components"):
|
||||
target.put_config_dicts({"ietf-hardware": {
|
||||
"hardware": {
|
||||
"component": [
|
||||
{
|
||||
"name": "gps0",
|
||||
"class": "infix-hardware:gps",
|
||||
"infix-hardware:gps-receiver": {}
|
||||
},
|
||||
{
|
||||
"name": "gps1",
|
||||
"class": "infix-hardware:gps",
|
||||
"infix-hardware:gps-receiver": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
}})
|
||||
|
||||
with test.step("Verify both GPS receivers are activated"):
|
||||
until(lambda: gps.is_activated(target, "gps0"), attempts=500)
|
||||
until(lambda: gps.is_activated(target, "gps1"), attempts=500)
|
||||
|
||||
with test.step("Verify both GPS receivers have a fix"):
|
||||
until(lambda: gps.has_fix(target, "gps0"), attempts=60)
|
||||
until(lambda: gps.has_fix(target, "gps1"), attempts=60)
|
||||
|
||||
with test.step("Verify gps0 position is near the coordinates"):
|
||||
verify_position(target, "gps0")
|
||||
|
||||
with test.step("Verify gps1 position is near the coordinates"):
|
||||
verify_position(target, "gps1")
|
||||
|
||||
with test.step("Save the configuration to startup configuration and reboot"):
|
||||
target.startup_override()
|
||||
target.copy("running", "startup")
|
||||
target.reboot()
|
||||
if not wait_boot(target, env):
|
||||
test.fail()
|
||||
target = env.attach("target", "mgmt", test_reset=False)
|
||||
|
||||
with test.step("Verify both GPS receivers are activated"):
|
||||
until(lambda: gps.is_activated(target, "gps0"), attempts=500)
|
||||
until(lambda: gps.is_activated(target, "gps1"), attempts=500)
|
||||
|
||||
with test.step("Verify both GPS receivers have a fix"):
|
||||
until(lambda: gps.has_fix(target, "gps0"), attempts=60)
|
||||
until(lambda: gps.has_fix(target, "gps1"), attempts=60)
|
||||
|
||||
with test.step("Verify gps0 position is near the coordinates"):
|
||||
verify_position(target, "gps0")
|
||||
|
||||
with test.step("Verify gps1 position is near the coordinates"):
|
||||
verify_position(target, "gps1")
|
||||
|
||||
test.succeed()
|
||||
@@ -0,0 +1,22 @@
|
||||
graph "1x1" {
|
||||
layout="neato";
|
||||
overlap="false";
|
||||
esep="+80";
|
||||
|
||||
node [shape=record, fontname="DejaVu Sans Mono, Book"];
|
||||
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];
|
||||
|
||||
host [
|
||||
label="host | { <mgmt> mgmt }",
|
||||
pos="0,12!",
|
||||
requires="controller",
|
||||
];
|
||||
|
||||
target [
|
||||
label="{ <mgmt> mgmt } | target",
|
||||
pos="10,12!",
|
||||
requires="infix gps",
|
||||
];
|
||||
|
||||
host:mgmt -- target:mgmt [requires="mgmt", color="lightgray"]
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
|
||||
<!-- Title: 1x1 Pages: 1 -->
|
||||
<svg width="424pt" height="45pt"
|
||||
viewBox="0.00 0.00 424.03 45.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 41)">
|
||||
<title>1x1</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-41 420.03,-41 420.03,4 -4,4"/>
|
||||
<!-- host -->
|
||||
<g id="node1" class="node">
|
||||
<title>host</title>
|
||||
<polygon fill="none" stroke="black" points="0,-0.5 0,-36.5 100,-36.5 100,-0.5 0,-0.5"/>
|
||||
<text text-anchor="middle" x="25" y="-14.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">host</text>
|
||||
<polyline fill="none" stroke="black" points="50,-0.5 50,-36.5 "/>
|
||||
<text text-anchor="middle" x="75" y="-14.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
|
||||
</g>
|
||||
<!-- target -->
|
||||
<g id="node2" class="node">
|
||||
<title>target</title>
|
||||
<polygon fill="none" stroke="black" points="300.03,-0.5 300.03,-36.5 416.03,-36.5 416.03,-0.5 300.03,-0.5"/>
|
||||
<text text-anchor="middle" x="325.03" y="-14.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
|
||||
<polyline fill="none" stroke="black" points="350.03,-0.5 350.03,-36.5 "/>
|
||||
<text text-anchor="middle" x="383.03" y="-14.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">target</text>
|
||||
</g>
|
||||
<!-- host--target -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>host:mgmt--target:mgmt</title>
|
||||
<path fill="none" stroke="lightgray" stroke-width="2" d="M100,-18.5C100,-18.5 300.03,-18.5 300.03,-18.5"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
Reference in New Issue
Block a user