summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Sul <ext-mykhaylo.sul@here.com>2019-05-23 15:38:42 +0300
committerPatrick Vacek <patrickvacek@gmail.com>2019-06-05 15:01:19 +0200
commitdfcb9669657051ab202e9d4569ea1a0360231401 (patch)
tree6c6e1b30f3096a779dfa81a2a4e352b80183c760
parent6f222fee48c4024d2f5f6ef097893073964204ef (diff)
downloadmeta-updater-dfcb9669657051ab202e9d4569ea1a0360231401.tar.gz
OTA-2541: IP Secondary tests (oe-selftest)
Signed-off-by: Mike Sul <ext-mykhaylo.sul@here.com> Signed-off-by: Patrick Vacek <patrickvacek@gmail.com>
-rw-r--r--lib/oeqa/selftest/cases/testutils.py53
-rw-r--r--lib/oeqa/selftest/cases/updater_qemux86_64.py151
2 files changed, 138 insertions, 66 deletions
diff --git a/lib/oeqa/selftest/cases/testutils.py b/lib/oeqa/selftest/cases/testutils.py
index 2ad99ad..f8b1904 100644
--- a/lib/oeqa/selftest/cases/testutils.py
+++ b/lib/oeqa/selftest/cases/testutils.py
@@ -7,49 +7,57 @@ from time import sleep
7from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars 7from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars
8from qemucommand import QemuCommand 8from qemucommand import QemuCommand
9 9
10logger = logging.getLogger("selftest")
10 11
11def qemu_launch(efi=False, machine=None, imagename=None): 12
12 logger = logging.getLogger("selftest") 13def qemu_launch(efi=False, machine=None, imagename='core-image-minimal', **kwargs):
13 if imagename is None: 14 qemu_bake_image(imagename)
14 imagename = 'core-image-minimal' 15 return qemu_boot_image(efi=efi, machine=machine, imagename=imagename, **kwargs)
15 logger.info('Running bitbake to build {}'.format(imagename)) 16
16 bitbake(imagename) 17
18def qemu_terminate(s):
19 try:
20 s.terminate()
21 s.wait(timeout=10)
22 except KeyboardInterrupt:
23 pass
24
25
26def qemu_boot_image(imagename, **kwargs):
17 # Create empty object. 27 # Create empty object.
18 args = type('', (), {})() 28 args = type('', (), {})()
19 args.imagename = imagename 29 args.imagename = imagename
20 args.mac = None 30 args.mac = kwargs.get('mac', None)
21 # Could use DEPLOY_DIR_IMAGE here but it's already in the machine 31 # Could use DEPLOY_DIR_IMAGE here but it's already in the machine
22 # subdirectory. 32 # subdirectory.
23 args.dir = 'tmp/deploy/images' 33 args.dir = 'tmp/deploy/images'
24 args.efi = efi 34 args.efi = kwargs.get('efi', False)
25 args.machine = machine 35 args.machine = kwargs.get('machine', None)
26 qemu_use_kvm = get_bb_var("QEMU_USE_KVM") 36 qemu_use_kvm = get_bb_var("QEMU_USE_KVM")
27 if qemu_use_kvm and \ 37 if qemu_use_kvm and \
28 (qemu_use_kvm == 'True' and 'x86' in machine or 38 (qemu_use_kvm == 'True' and 'x86' in args.machine or
29 get_bb_var('MACHINE') in qemu_use_kvm.split()): 39 get_bb_var('MACHINE') in qemu_use_kvm.split()):
30 args.kvm = True 40 args.kvm = True
31 else: 41 else:
32 args.kvm = None # Autodetect 42 args.kvm = None # Autodetect
33 args.no_gui = True 43 args.no_gui = kwargs.get('no_gui', True)
34 args.gdb = False 44 args.gdb = kwargs.get('gdb', False)
35 args.pcap = None 45 args.pcap = kwargs.get('pcap', None)
36 args.overlay = None 46 args.overlay = kwargs.get('overlay', None)
37 args.dry_run = False 47 args.dry_run = kwargs.get('dry_run', False)
38 args.secondary_network = False 48 args.secondary_network = kwargs.get('secondary_network', False)
39 49
40 qemu = QemuCommand(args) 50 qemu = QemuCommand(args)
41 cmdline = qemu.command_line() 51 cmdline = qemu.command_line()
42 print('Booting image with run-qemu-ota...') 52 print('Booting image with run-qemu-ota...')
43 s = subprocess.Popen(cmdline) 53 s = subprocess.Popen(cmdline)
44 sleep(10) 54 sleep(kwargs.get('wait_for_boot_time', 10))
45 return qemu, s 55 return qemu, s
46 56
47 57
48def qemu_terminate(s): 58def qemu_bake_image(imagename):
49 try: 59 logger.info('Running bitbake to build {}'.format(imagename))
50 s.terminate() 60 bitbake(imagename)
51 except KeyboardInterrupt:
52 pass
53 61
54 62
55def qemu_send_command(port, command, timeout=60): 63def qemu_send_command(port, command, timeout=60):
@@ -122,7 +130,6 @@ def verifyProvisioned(testInst, machine):
122 m = p.search(stdout.decode()) 130 m = p.search(stdout.decode())
123 testInst.assertTrue(m, 'Device ID could not be read: ' + stderr.decode() + stdout.decode()) 131 testInst.assertTrue(m, 'Device ID could not be read: ' + stderr.decode() + stdout.decode())
124 testInst.assertGreater(m.lastindex, 0, 'Device ID could not be read: ' + stderr.decode() + stdout.decode()) 132 testInst.assertGreater(m.lastindex, 0, 'Device ID could not be read: ' + stderr.decode() + stdout.decode())
125 logger = logging.getLogger("selftest")
126 logger.info('Device successfully provisioned with ID: ' + m.group(1)) 133 logger.info('Device successfully provisioned with ID: ' + m.group(1))
127 134
128# vim:set ts=4 sw=4 sts=4 expandtab: 135# vim:set ts=4 sw=4 sts=4 expandtab:
diff --git a/lib/oeqa/selftest/cases/updater_qemux86_64.py b/lib/oeqa/selftest/cases/updater_qemux86_64.py
index 9f32bcf..f951bc7 100644
--- a/lib/oeqa/selftest/cases/updater_qemux86_64.py
+++ b/lib/oeqa/selftest/cases/updater_qemux86_64.py
@@ -4,11 +4,12 @@ import logging
4import re 4import re
5import unittest 5import unittest
6from time import sleep 6from time import sleep
7from uuid import uuid4
7 8
8from oeqa.selftest.case import OESelftestTestCase 9from oeqa.selftest.case import OESelftestTestCase
9from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars 10from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars
10from testutils import qemu_launch, qemu_send_command, qemu_terminate, \ 11from testutils import qemu_launch, qemu_send_command, qemu_terminate, \
11 akt_native_run, verifyNotProvisioned, verifyProvisioned 12 akt_native_run, verifyNotProvisioned, verifyProvisioned, qemu_bake_image, qemu_boot_image
12 13
13 14
14class GeneralTests(OESelftestTestCase): 15class GeneralTests(OESelftestTestCase):
@@ -309,7 +310,91 @@ class HsmTests(OESelftestTestCase):
309 verifyProvisioned(self, machine) 310 verifyProvisioned(self, machine)
310 311
311 312
312class SecondaryTests(OESelftestTestCase): 313class IpSecondaryTests(OESelftestTestCase):
314
315 class Image:
316 def __init__(self, imagename, binaryname, machine='qemux86-64', bake=True, **kwargs):
317 self.machine = machine
318 self.imagename = imagename
319 self.boot_kwargs = kwargs
320 self.binaryname = binaryname
321 self.stdout = ''
322 self.stderr = ''
323 self.retcode = 0
324 if bake:
325 self.bake()
326
327 def bake(self):
328 self.configure()
329 qemu_bake_image(self.imagename)
330
331 def send_command(self, cmd):
332 stdout, stderr, retcode = qemu_send_command(self.qemu.ssh_port, cmd, timeout=60)
333 return str(stdout), str(stderr), retcode
334
335 def __enter__(self):
336 self.qemu, self.process = qemu_boot_image(machine=self.machine, imagename=self.imagename,
337 wait_for_boot_time=1, **self.boot_kwargs)
338 # wait until the VM is booted and is SSHable
339 self.wait_till_sshable()
340
341 def __exit__(self, exc_type, exc_val, exc_tb):
342 qemu_terminate(self.process)
343
344 def wait_till_sshable(self):
345 # qemu_send_command tries to ssh into the qemu VM and blocks until it gets there or timeout happens
346 # so it helps us to block q control flow until the VM is booted and a target binary/daemon is running there
347 self.stdout, self.stderr, self.retcode = self.send_command(self.binaryname + ' --help')
348
349 def was_successfully_booted(self):
350 return self.retcode == 0
351
352 class Secondary(Image):
353 def __init__(self, test_ctx):
354 self._test_ctx = test_ctx
355 self.sndry_serial = str(uuid4())
356 self.sndry_hw_id = 'qemux86-64-oeselftest-sndry'
357 self.id = (self.sndry_hw_id, self.sndry_serial)
358 super(IpSecondaryTests.Secondary, self).__init__('secondary-image', 'aktualizr-secondary',
359 secondary_network=True)
360
361 def configure(self):
362 self._test_ctx.append_config('SECONDARY_SERIAL_ID = "{}"'.format(self.sndry_serial))
363 self._test_ctx.append_config('SECONDARY_HARDWARE_ID = "{}"'.format(self.sndry_hw_id))
364
365 class Primary(Image):
366 def __init__(self, test_ctx):
367 self._test_ctx = test_ctx
368 super(IpSecondaryTests.Primary, self).__init__('primary-image', 'aktualizr', secondary_network=True)
369
370 def configure(self):
371 self._test_ctx.append_config('MACHINE = "qemux86-64"')
372 self._test_ctx.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "')
373
374 def is_ecu_registered(self, ecu_id):
375 max_number_of_tries = 20
376 try_counter = 0
377
378 # aktualizr-info is not always able to load ECU serials from DB
379 # so, let's run it a few times until it actually succeeds
380 while try_counter < max_number_of_tries:
381 device_status = self.get_info()
382 try_counter += 1
383 if device_status.find("load ECU serials") == -1:
384 break
385 sleep(1)
386
387 if not ((device_status.find(ecu_id[0]) != -1) and (device_status.find(ecu_id[1]) != -1)):
388 return False
389 not_registered_field = "Removed or not registered ecus:"
390 not_reg_start = device_status.find(not_registered_field)
391 return not_reg_start == -1 or (device_status.find(ecu_id[1], not_reg_start) == -1)
392
393 def get_info(self):
394 stdout, stderr, retcode = self.send_command('aktualizr-info')
395 self._test_ctx.assertEqual(retcode, 0, 'Unable to run aktualizr-info: {}'.format(stderr))
396 return stdout
397
313 def setUpLocal(self): 398 def setUpLocal(self):
314 layer = "meta-updater-qemux86-64" 399 layer = "meta-updater-qemux86-64"
315 result = runCmd('bitbake-layers show-layers') 400 result = runCmd('bitbake-layers show-layers')
@@ -323,57 +408,37 @@ class SecondaryTests(OESelftestTestCase):
323 runCmd('bitbake-layers add-layer "%s"' % self.meta_qemu) 408 runCmd('bitbake-layers add-layer "%s"' % self.meta_qemu)
324 else: 409 else:
325 self.meta_qemu = None 410 self.meta_qemu = None
326 self.append_config('MACHINE = "qemux86-64"') 411
327 self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "') 412 self.primary = IpSecondaryTests.Primary(self)
328 self.qemu, self.s = qemu_launch(machine='qemux86-64', imagename='secondary-image') 413 self.secondary = IpSecondaryTests.Secondary(self)
329 414
330 def tearDownLocal(self): 415 def tearDownLocal(self):
331 qemu_terminate(self.s)
332 if self.meta_qemu: 416 if self.meta_qemu:
333 runCmd('bitbake-layers remove-layer "%s"' % self.meta_qemu, ignore_status=True) 417 runCmd('bitbake-layers remove-layer "%s"' % self.meta_qemu, ignore_status=True)
334 418
335 def qemu_command(self, command): 419 def test_ip_secondary_registration_if_secondary_starts_first(self):
336 return qemu_send_command(self.qemu.ssh_port, command) 420 with self.secondary:
421 self.assertTrue(self.secondary.was_successfully_booted(),
422 'The secondary failed to boot: {}'.format(self.secondary.stderr))
337 423
338 def test_secondary_present(self): 424 with self.primary:
339 print('Checking aktualizr-secondary is present') 425 self.assertTrue(self.primary.was_successfully_booted(),
340 stdout, stderr, retcode = self.qemu_command('aktualizr-secondary --help') 426 'The primary failed to boot: {}'.format(self.primary.stderr))
341 self.assertEqual(retcode, 0, "Unable to run aktualizr-secondary --help")
342 self.assertEqual(stderr, b'', 'Error: ' + stderr.decode())
343 427
428 self.assertTrue(self.primary.is_ecu_registered(self.secondary.id),
429 "The secondary wasn't registered at the primary: {}".format(self.primary.get_info()))
344 430
345class PrimaryTests(OESelftestTestCase): 431 def test_ip_secondary_registration_if_primary_starts_first(self):
346 def setUpLocal(self): 432 with self.primary:
347 layer = "meta-updater-qemux86-64" 433 self.assertTrue(self.primary.was_successfully_booted(),
348 result = runCmd('bitbake-layers show-layers') 434 'The primary failed to boot: {}'.format(self.primary.stderr))
349 if re.search(layer, result.output) is None:
350 # Assume the directory layout for finding other layers. We could also
351 # make assumptions by using 'show-layers', but either way, if the
352 # layers we need aren't where we expect them, we are out of luck.
353 path = os.path.abspath(os.path.dirname(__file__))
354 metadir = path + "/../../../../../"
355 self.meta_qemu = metadir + layer
356 runCmd('bitbake-layers add-layer "%s"' % self.meta_qemu)
357 else:
358 self.meta_qemu = None
359 self.append_config('MACHINE = "qemux86-64"')
360 self.append_config('SOTA_CLIENT_PROV = " aktualizr-auto-prov "')
361 self.append_config('SOTA_CLIENT_FEATURES = "secondary-network"')
362 self.qemu, self.s = qemu_launch(machine='qemux86-64', imagename='primary-image')
363 435
364 def tearDownLocal(self): 436 with self.secondary:
365 qemu_terminate(self.s) 437 self.assertTrue(self.secondary.was_successfully_booted(),
366 if self.meta_qemu: 438 'The secondary failed to boot: {}'.format(self.secondary.stderr))
367 runCmd('bitbake-layers remove-layer "%s"' % self.meta_qemu, ignore_status=True)
368 439
369 def qemu_command(self, command): 440 self.assertTrue(self.primary.is_ecu_registered(self.secondary.id),
370 return qemu_send_command(self.qemu.ssh_port, command) 441 "The secondary wasn't registered at the primary: {}".format(self.primary.get_info()))
371
372 def test_aktualizr_present(self):
373 print('Checking aktualizr is present')
374 stdout, stderr, retcode = self.qemu_command('aktualizr --help')
375 self.assertEqual(retcode, 0, "Unable to run aktualizr --help")
376 self.assertEqual(stderr, b'', 'Error: ' + stderr.decode())
377 442
378 443
379class ResourceControlTests(OESelftestTestCase): 444class ResourceControlTests(OESelftestTestCase):