Some integration tests

This commit is contained in:
Jan Käberich 2022-11-14 00:09:19 +01:00
parent b03c8b3958
commit 60c280b454
11 changed files with 282 additions and 0 deletions

2
Software/.gitignore vendored
View File

@ -1,3 +1,5 @@
/.metadata/
RemoteSystemsTempFiles
build-*
*.pyc

View File

@ -0,0 +1,60 @@
{
"Description": "Dummy ideal calibration kit",
"Manufacturer": "LibreVNA",
"Serialnumber": "1234",
"standards": [
{
"params": {
"C0": 0.0,
"C1": 0.0,
"C2": 0.0,
"C3": 0.0,
"Z0": 50.0,
"delay": 0.0,
"id": 13726173464103258082,
"loss": 0.0,
"name": "Default"
},
"type": "Open"
},
{
"params": {
"L0": 0.0,
"L1": 0.0,
"L2": 0.0,
"L3": 0.0,
"Z0": 50.0,
"delay": 0.0,
"id": 13573063103112146609,
"loss": 0.0,
"name": "Default"
},
"type": "Short"
},
{
"params": {
"Cfirst": true,
"Cparallel": 0.0,
"Lseries": 0.0,
"Z0": 50.0,
"delay": 0.0,
"id": 11987083411312060381,
"loss": 0.0,
"name": "Default",
"resistance": 50.0
},
"type": "Load"
},
{
"params": {
"Z0": 50.0,
"delay": 0.0,
"id": 2916288069679020801,
"loss": 0.0,
"name": "Default"
},
"type": "Through"
}
],
"version": "1.5.0-alpha.1-9b7f457aa"
}

View File

@ -0,0 +1,22 @@
import unittest
testmodules = [
'tests.TestConnect',
'tests.TestMode',
'tests.TestVNASweep',
'tests.TestCalibration',
]
suite = unittest.TestSuite()
for t in testmodules:
try:
# If the module defines a suite() function, call it to get the suite.
mod = __import__(t, globals(), locals(), ['suite'])
suitefn = getattr(mod, 'suite')
suite.addTest(suitefn())
except (ImportError, AttributeError):
# else, just load all the test cases from the module.
suite.addTest(unittest.defaultTestLoader.loadTestsFromName(t))
unittest.TextTestRunner().run(suite)

View File

@ -0,0 +1,39 @@
import unittest
from tests.libreVNA import libreVNA as libreVNA
import tests.definitions as defs
import subprocess
import time
import select
from signal import SIGINT
class TestBase(unittest.TestCase):
def setUp(self):
self.gui = subprocess.Popen([defs.GUI_PATH, '-p', '19543'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# wait for the SCPI server to become available
timeout = time.time() + 3;
poll_obj = select.poll()
poll_obj.register(self.gui.stdout, select.POLLIN)
while time.time() < timeout:
poll_result = poll_obj.poll(0)
if poll_result:
line = self.gui.stdout.readline().decode().strip()
if "Listening on port 19543" in line:
break
time.sleep(0.2)
self.vna = libreVNA('localhost', 19543)
self.vna.cmd(":DEV:CONN")
if self.vna.query(":DEV:CONN?") == "Not connected":
self.tearDown()
raise AssertionError("Not connected")
def tearDown(self):
self.gui.send_signal(SIGINT)
try:
self.gui.wait(timeout = 0.1)
except subprocess.TimeoutExpired:
self.gui.kill()

View File

@ -0,0 +1,82 @@
from tests.TestBase import TestBase
import time
class TestCalibration(TestBase):
def cal_measure(self, number):
self.vna.cmd(":VNA:CAL:MEAS "+str(number))
# wait for the measurement to finish
timeout = time.time() + 3
while self.vna.query(":VNA:CAL:BUSY?") == "TRUE":
if time.time() > timeout:
raise AssertionError("Calibration measurement timed out")
time.sleep(0.1)
def test_dummy_calibration(self):
# This test just iterates through the calibration steps. As no actual standards
# are applied to the ports, the calibration result is just random data
# Set up the sweep first
self.vna.cmd(":DEV:MODE VNA")
self.vna.cmd(":VNA:SWEEP FREQUENCY")
self.vna.cmd(":VNA:STIM:LVL -10")
self.vna.cmd(":VNA:ACQ:IFBW 50000")
self.vna.cmd(":VNA:ACQ:AVG 1")
self.vna.cmd(":VNA:ACQ:POINTS 501")
self.vna.cmd(":VNA:FREQuency:START 1000000")
self.vna.cmd(":VNA:FREQuency:STOP 6000000000")
self.vna.cmd(":VNA:CAL:RESET")
# No measurements yet, activating should fail
self.assertEqual(self.vna.query(":VNA:CAL:ACT SOLT_1"), "ERROR")
# Load calibration kit
self.assertEqual(self.vna.query(":VNA:CAL:KIT:LOAD? DUMMY.CALKIT"), "TRUE")
# Lets take the measurements for port 1 first
self.vna.cmd(":VNA:CAL:ADD OPEN")
self.vna.cmd(":VNA:CAL:ADD SHORT")
self.vna.cmd(":VNA:CAL:ADD LOAD")
self.vna.cmd(":VNA:CAL:PORT 0 1")
self.vna.cmd(":VNA:CAL:PORT 1 1")
self.vna.cmd(":VNA:CAL:PORT 2 1")
self.cal_measure(0)
self.cal_measure(1)
self.cal_measure(2)
# SOLT_1 should now be available
self.assertEqual(self.vna.query(":VNA:CAL:ACT SOLT_1"), "")
# SOLT_2 and SOLT_12 should still be unavailable
self.assertEqual(self.vna.query(":VNA:CAL:ACT SOLT_2"), "ERROR")
self.assertEqual(self.vna.query(":VNA:CAL:ACT SOLT_12"), "ERROR")
# Take measurements for SOLT_2
self.vna.cmd(":VNA:CAL:ADD OPEN")
self.vna.cmd(":VNA:CAL:ADD SHORT")
self.vna.cmd(":VNA:CAL:ADD LOAD")
self.vna.cmd(":VNA:CAL:PORT 3 2")
self.vna.cmd(":VNA:CAL:PORT 4 2")
self.vna.cmd(":VNA:CAL:PORT 5 2")
self.cal_measure(3)
self.cal_measure(4)
self.cal_measure(5)
# SOLT_1 and SOLT_2 should now be available
self.assertEqual(self.vna.query(":VNA:CAL:ACT SOLT_1"), "")
self.assertEqual(self.vna.query(":VNA:CAL:ACT SOLT_2"), "")
# SOLT_12 should still be unavailable
self.assertEqual(self.vna.query(":VNA:CAL:ACT SOLT_12"), "ERROR")
# Take the final through measurement for SOLT_12
self.vna.cmd(":VNA:CAL:ADD THROUGH")
self.vna.cmd(":VNA:CAL:PORT 6 1 2")
self.cal_measure(6)
# SOLT_1, SOLT_2 and SOLT_12 should now be available
self.assertEqual(self.vna.query(":VNA:CAL:ACT SOLT_1"), "")
self.assertEqual(self.vna.query(":VNA:CAL:ACT SOLT_2"), "")
self.assertEqual(self.vna.query(":VNA:CAL:ACT SOLT_12"), "")

View File

@ -0,0 +1,13 @@
from tests.TestBase import TestBase
class TestConnect(TestBase):
def test_connection(self):
self.vna.cmd(":DEV:DISC")
self.assertEqual(self.vna.query(":DEV:CONN?"), "Not connected")
self.vna.cmd(":DEV:CONN")
self.assertNotEqual(self.vna.query(":DEV:CONN?"), "Not connected")
def test_list(self):
list = self.vna.query(":DEV:LIST?")
serials = list.split(',')
self.assertEqual(len(serials), 1)

View File

@ -0,0 +1,8 @@
from tests.TestBase import TestBase
class TestMode(TestBase):
def test_Mode(self):
modes = ["VNA", "GEN", "SA"]
for m in modes:
self.vna.cmd(":DEV:MODE "+m)
self.assertEqual(self.vna.query(":DEV:MODE?"), m)

View File

@ -0,0 +1,54 @@
from tests.TestBase import TestBase
import time
class TestVNASweep(TestBase):
def test_sweep_frequency(self):
self.vna.cmd(":DEV:MODE VNA")
self.vna.cmd(":VNA:SWEEP FREQUENCY")
self.vna.cmd(":VNA:STIM:LVL -10")
self.vna.cmd(":VNA:ACQ:IFBW 10000")
self.vna.cmd(":VNA:ACQ:AVG 1")
self.vna.cmd(":VNA:ACQ:POINTS 501")
self.vna.cmd(":VNA:FREQuency:START 1000000")
self.vna.cmd(":VNA:FREQuency:STOP 6000000000")
while self.vna.query(":VNA:ACQ:FIN?") == "FALSE":
time.sleep(0.1)
S11 = self.vna.parse_trace_data(self.vna.query(":VNA:TRACE:DATA? S11"))
self.assertEqual(S11[0][0], 1000000)
self.assertEqual(S11[-1][0], 6000000000)
def test_sweep_zerospan(self):
self.vna.cmd(":DEV:MODE VNA")
self.vna.cmd(":VNA:SWEEP FREQUENCY")
self.vna.cmd(":VNA:STIM:LVL -10")
self.vna.cmd(":VNA:ACQ:IFBW 10000")
self.vna.cmd(":VNA:ACQ:AVG 1")
self.vna.cmd(":VNA:ACQ:POINTS 501")
self.vna.cmd(":VNA:FREQuency:START 500000000")
self.vna.cmd(":VNA:FREQuency:STOP 1500000000")
self.vna.cmd(":VNA:FREQuency:ZERO 1500000000")
while self.vna.query(":VNA:ACQ:FIN?") == "FALSE":
time.sleep(0.1)
S11 = self.vna.parse_trace_data(self.vna.query(":VNA:TRACE:DATA? S11"))
self.assertEqual(S11[0][0], 0.0)
# Sweep should take about 0.125 seconds
self.assertGreater(S11[-1][0], 0.1)
self.assertLess(S11[-1][0], 0.5)
def test_sweep_power(self):
self.vna.cmd(":DEV:MODE VNA")
self.vna.cmd(":VNA:SWEEP POWER")
self.vna.cmd(":VNA:STIM:LVL -10")
self.vna.cmd(":VNA:ACQ:IFBW 10000")
self.vna.cmd(":VNA:ACQ:AVG 1")
self.vna.cmd(":VNA:ACQ:POINTS 501")
self.vna.cmd(":VNA:POWER:START -30")
self.vna.cmd(":VNA:POWER:STOP -10")
while self.vna.query(":VNA:ACQ:FIN?") == "FALSE":
time.sleep(0.1)
S11 = self.vna.parse_trace_data(self.vna.query(":VNA:TRACE:DATA? S11"))
self.assertEqual(S11[0][0], -30)
self.assertEqual(S11[-1][0], -10)

View File

@ -0,0 +1 @@
GUI_PATH = "../PC_Application/LibreVNA-GUI/LibreVNA-GUI"

View File

@ -0,0 +1 @@
../../../Documentation/UserManual/SCPI_Examples/libreVNA.py