diff options
Diffstat (limited to 'lib')
20 files changed, 1008 insertions, 0 deletions
diff --git a/lib/oeqa/runtime/cases/cyclictest.py b/lib/oeqa/runtime/cases/cyclictest.py new file mode 100644 index 00000000..8890651a --- /dev/null +++ b/lib/oeqa/runtime/cases/cyclictest.py @@ -0,0 +1,39 @@ +from oeqa.runtime.case import OERuntimeTestCase +from oeqa.core.decorator.depends import OETestDepends +from oeqa.runtime.decorator.package import OEHasPackage +import os +import subprocess +import datetime + +class CyclicTest(OERuntimeTestCase): + + @OEHasPackage(['rt-tests']) + @OETestDepends(['ssh.SSHTest.test_ssh']) + def test_cyclic(self): + # Cyclictest command and argument based on public setup for Intel(R) Core(TM) i7-6700 + # https://www.osadl.org/Latency-plot-of-system-in-rack-9-slot.qa-latencyplot-r9s5.0.html?shadow=1 + # Command line: cyclictest -l100000000 -m -Sp99 -i200 -h400 -q + status, output = self.target.run('cyclictest -l100000000 -m -Sp99 -i200 -h400') + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + test_log_dir = self.td.get('TEST_LOG_DIR', '') + + if not test_log_dir: + test_log_dir = os.path.join(self.td.get('WORKDIR', ''), 'testimage') + + cyclic_log_dir = os.path.join(test_log_dir, '%s.%s' % ('cyclic_test', datetime.datetime.now().strftime('%Y%m%d%H%M%S'))) + os.makedirs(cyclic_log_dir) + log_path = os.path.join(cyclic_log_dir, 'cyclic_log') + with open(log_path, 'w') as f: + f.write(output) + + max_latency = subprocess.check_output(('grep "Max Latencies" %s | tr " " "\n" | sort -n | tail -1 | sed s/^0*//') % log_path, shell=True).strip() + max_latency = int(max_latency) + + # Default target latency based on max latency (24us) captured at public execution multiple by 1.2 (20% buffer) + # https://www.osadl.org/Latency-plot-of-system-in-rack-9-slot.qa-latencyplot-r9s5.0.html?shadow=1 + target_latency = 1.2*24 + user_defined_target_latency = self.tc.td.get("RTKERNEL_TARGET_LATENCY") + if user_defined_target_latency: + target_latency = int(user_defined_target_latency) + self.assertTrue(max_latency < target_latency, + msg="Max latency (%sus) is greater than target (%sus)." % (max_latency, target_latency)) diff --git a/lib/oeqa/runtime/cases/dldt_inference_engine.py b/lib/oeqa/runtime/cases/dldt_inference_engine.py new file mode 100644 index 00000000..288f7261 --- /dev/null +++ b/lib/oeqa/runtime/cases/dldt_inference_engine.py @@ -0,0 +1,109 @@ +from oeqa.runtime.case import OERuntimeTestCase +from oeqa.runtime.decorator.package import OEHasPackage +from oeqa.core.decorator.depends import OETestDepends +from oeqa.runtime.miutils.targets.oeqatarget import OEQATarget +from oeqa.runtime.miutils.tests.squeezenet_model_download_test import SqueezenetModelDownloadTest +from oeqa.runtime.miutils.tests.dldt_model_optimizer_test import DldtModelOptimizerTest +from oeqa.runtime.miutils.tests.dldt_inference_engine_test import DldtInferenceEngineTest +from oeqa.runtime.miutils.dldtutils import get_testdata_config + +class DldtInferenceEngine(OERuntimeTestCase): + + @classmethod + def setUpClass(cls): + cls.sqn_download = SqueezenetModelDownloadTest(OEQATarget(cls.tc.target), '/tmp/ie/md') + cls.sqn_download.setup() + cls.dldt_mo = DldtModelOptimizerTest(OEQATarget(cls.tc.target), '/tmp/ie/ir') + cls.dldt_mo.setup() + cls.dldt_ie = DldtInferenceEngineTest(OEQATarget(cls.tc.target), '/tmp/ie/inputs') + cls.dldt_ie.setup() + cls.ir_files_dir = cls.dldt_mo.work_dir + + @classmethod + def tearDownClass(cls): + cls.dldt_ie.tear_down() + cls.dldt_mo.tear_down() + cls.sqn_download.tear_down() + + @OEHasPackage(['dldt-model-optimizer']) + @OEHasPackage(['wget']) + def test_dldt_ie_can_create_ir_and_download_input(self): + proxy_port = get_testdata_config(self.tc.td, 'DLDT_PIP_PROXY') + if not proxy_port: + self.skipTest('Need to configure bitbake configuration (DLDT_PIP_PROXY="proxy.server:port").') + (status, output) = self.sqn_download.test_can_download_squeezenet_model(proxy_port) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + (status, output) = self.sqn_download.test_can_download_squeezenet_prototxt(proxy_port) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + mo_exe_dir = get_testdata_config(self.tc.td, 'DLDT_MO_EXE_DIR') + if not mo_exe_dir: + self.skipTest('Need to configure bitbake configuration (DLDT_MO_EXE_DIR="directory_to_mo.py").') + mo_files_dir = self.sqn_download.work_dir + (status, output) = self.dldt_mo.test_dldt_mo_can_create_ir(mo_exe_dir, mo_files_dir) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + (status, output) = self.dldt_ie.test_can_download_input_file(proxy_port) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OETestDepends(['dldt_inference_engine.DldtInferenceEngine.test_dldt_ie_can_create_ir_and_download_input']) + @OEHasPackage(['dldt-inference-engine']) + @OEHasPackage(['dldt-inference-engine-samples']) + def test_dldt_ie_classification_with_cpu(self): + (status, output) = self.dldt_ie.test_dldt_ie_classification_with_device('CPU', self.ir_files_dir) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OETestDepends(['dldt_inference_engine.DldtInferenceEngine.test_dldt_ie_can_create_ir_and_download_input']) + @OEHasPackage(['dldt-inference-engine']) + @OEHasPackage(['dldt-inference-engine-samples']) + @OEHasPackage(['intel-compute-runtime']) + @OEHasPackage(['opencl-icd-loader']) + def test_dldt_ie_classification_with_gpu(self): + (status, output) = self.dldt_ie.test_dldt_ie_classification_with_device('GPU', self.ir_files_dir) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OETestDepends(['dldt_inference_engine.DldtInferenceEngine.test_dldt_ie_can_create_ir_and_download_input']) + @OEHasPackage(['dldt-inference-engine']) + @OEHasPackage(['dldt-inference-engine-samples']) + @OEHasPackage(['dldt-inference-engine-vpu-firmware']) + def test_dldt_ie_classification_with_myriad(self): + device = 'MYRIAD' + (status, output) = self.dldt_ie.test_check_if_openvino_device_available(device) + if not status: + self.skipTest('OpenVINO %s device not available on target machine(availalbe devices: %s)' % (device, output)) + (status, output) = self.dldt_ie.test_dldt_ie_classification_with_device(device, self.ir_files_dir) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OETestDepends(['dldt_inference_engine.DldtInferenceEngine.test_dldt_ie_can_create_ir_and_download_input']) + @OEHasPackage(['dldt-inference-engine']) + @OEHasPackage(['dldt-inference-engine-python3']) + @OEHasPackage(['python3-opencv']) + @OEHasPackage(['python3-numpy']) + def test_dldt_ie_classification_python_api_with_cpu(self): + (status, output) = self.dldt_ie.test_dldt_ie_classification_python_api_with_device('CPU', self.ir_files_dir) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OETestDepends(['dldt_inference_engine.DldtInferenceEngine.test_dldt_ie_can_create_ir_and_download_input']) + @OEHasPackage(['dldt-inference-engine']) + @OEHasPackage(['dldt-inference-engine-python3']) + @OEHasPackage(['intel-compute-runtime']) + @OEHasPackage(['opencl-icd-loader']) + @OEHasPackage(['python3-opencv']) + @OEHasPackage(['python3-numpy']) + def test_dldt_ie_classification_python_api_with_gpu(self): + (status, output) = self.dldt_ie.test_dldt_ie_classification_python_api_with_device('GPU', self.ir_files_dir) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OETestDepends(['dldt_inference_engine.DldtInferenceEngine.test_dldt_ie_can_create_ir_and_download_input']) + @OEHasPackage(['dldt-inference-engine']) + @OEHasPackage(['dldt-inference-engine-python3']) + @OEHasPackage(['dldt-inference-engine-vpu-firmware']) + @OEHasPackage(['python3-opencv']) + @OEHasPackage(['python3-numpy']) + def test_dldt_ie_classification_python_api_with_myriad(self): + device = 'MYRIAD' + (status, output) = self.dldt_ie.test_check_if_openvino_device_available(device) + if not status: + self.skipTest('OpenVINO %s device not available on target machine(availalbe devices: %s)' % (device, output)) + (status, output) = self.dldt_ie.test_dldt_ie_classification_python_api_with_device(device, self.ir_files_dir) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) diff --git a/lib/oeqa/runtime/cases/dldt_model_optimizer.py b/lib/oeqa/runtime/cases/dldt_model_optimizer.py new file mode 100644 index 00000000..736ea661 --- /dev/null +++ b/lib/oeqa/runtime/cases/dldt_model_optimizer.py @@ -0,0 +1,38 @@ +from oeqa.runtime.case import OERuntimeTestCase +from oeqa.runtime.decorator.package import OEHasPackage +from oeqa.runtime.miutils.targets.oeqatarget import OEQATarget +from oeqa.runtime.miutils.tests.squeezenet_model_download_test import SqueezenetModelDownloadTest +from oeqa.runtime.miutils.tests.dldt_model_optimizer_test import DldtModelOptimizerTest +from oeqa.runtime.miutils.dldtutils import get_testdata_config + +class DldtModelOptimizer(OERuntimeTestCase): + + @classmethod + def setUpClass(cls): + cls.sqn_download = SqueezenetModelDownloadTest(OEQATarget(cls.tc.target), '/tmp/mo/md') + cls.sqn_download.setup() + cls.dldt_mo = DldtModelOptimizerTest(OEQATarget(cls.tc.target), '/tmp/mo/ir') + cls.dldt_mo.setup() + + @classmethod + def tearDownClass(cls): + cls.dldt_mo.tear_down() + cls.sqn_download.tear_down() + + @OEHasPackage(['dldt-model-optimizer']) + @OEHasPackage(['wget']) + def test_dldt_mo_can_create_ir(self): + proxy_port = get_testdata_config(self.tc.td, 'DLDT_PIP_PROXY') + if not proxy_port: + self.skipTest('Need to configure bitbake configuration (DLDT_PIP_PROXY="proxy.server:port").') + (status, output) = self.sqn_download.test_can_download_squeezenet_model(proxy_port) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + (status, output) = self.sqn_download.test_can_download_squeezenet_prototxt(proxy_port) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + mo_exe_dir = get_testdata_config(self.tc.td, 'DLDT_MO_EXE_DIR') + if not mo_exe_dir: + self.skipTest('Need to configure bitbake configuration (DLDT_MO_EXE_DIR="directory_to_mo.py").') + mo_files_dir = self.sqn_download.work_dir + (status, output) = self.dldt_mo.test_dldt_mo_can_create_ir(mo_exe_dir, mo_files_dir) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) diff --git a/lib/oeqa/runtime/cases/intel_mediasdk.py b/lib/oeqa/runtime/cases/intel_mediasdk.py new file mode 100644 index 00000000..4ae7d580 --- /dev/null +++ b/lib/oeqa/runtime/cases/intel_mediasdk.py @@ -0,0 +1,34 @@ +from oeqa.runtime.case import OERuntimeTestCase +from oeqa.runtime.decorator.package import OEHasPackage +from oeqa.core.decorator.depends import OETestDepends + +class MsdkTest(OERuntimeTestCase): + + @classmethod + def tearDownClass(cls): + cls.tc.target.run("rm /tmp/mtest_h264.mp4") + + @OEHasPackage(['gstreamer1.0-plugins-base']) + @OEHasPackage(['gstreamer1.0-plugins-good']) + @OEHasPackage(['gstreamer1.0-plugins-bad']) + @OEHasPackage(['intel-mediasdk']) + @OEHasPackage(['intel-media-driver', 'libigfxcmrt7']) + def test_gstreamer_can_encode_with_msdk_and_intel_media_driver(self): + (status, output) = self.target.run('gst-inspect-1.0 msdk') + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + (status, output) = self.target.run('export LIBVA_DRIVER_NAME=iHD; ' + 'gst-launch-1.0 -ev videotestsrc num-buffers=120 ! timeoverlay ! ' + 'msdkh264enc ! video/x-h264,profile=main ! h264parse ! ' + 'filesink location=/tmp/mtest_h264.mp4') + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OETestDepends(['intel_mediasdk.MsdkTest.test_gstreamer_can_encode_with_msdk_and_intel_media_driver']) + def test_gstreamer_can_decode_with_msdk_and_intel_media_driver(self): + (status, output) = self.target.run('export LIBVA_DRIVER_NAME=iHD; ' + 'gst-launch-1.0 filesrc location=/tmp/mtest_h264.mp4 ! ' + 'h264parse ! msdkh264dec ! ' + 'msdkh265enc rate-control=cbr bitrate=5000 gop-size=30 b-frames=2 ! ' + 'video/x-h265,profile=main ! h265parse ! fakesink') + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + diff --git a/lib/oeqa/runtime/cases/intel_vaapi_driver.py b/lib/oeqa/runtime/cases/intel_vaapi_driver.py new file mode 100644 index 00000000..85d2dd39 --- /dev/null +++ b/lib/oeqa/runtime/cases/intel_vaapi_driver.py @@ -0,0 +1,29 @@ +from oeqa.runtime.case import OERuntimeTestCase +from oeqa.runtime.decorator.package import OEHasPackage +from oeqa.core.decorator.depends import OETestDepends + +class VaapiDriverTest(OERuntimeTestCase): + + @classmethod + def tearDownClass(cls): + cls.tc.target.run("rm /tmp/vtest_h264.mp4") + + @OEHasPackage(['gstreamer1.0-plugins-base']) + @OEHasPackage(['gstreamer1.0-plugins-good']) + @OEHasPackage(['gstreamer1.0-vaapi']) + @OEHasPackage(['intel-vaapi-driver']) + def test_gstreamer_can_encode_with_intel_vaapi_driver(self): + (status, output) = self.target.run('gst-inspect-1.0 vaapi') + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + (status, output) = self.target.run('export LIBVA_DRIVER_NAME=i965; ' + 'gst-launch-1.0 -ev videotestsrc num-buffers=60 ! ' + 'timeoverlay ! vaapih264enc ! mp4mux ! filesink location=/tmp/vtest_h264.mp4') + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OETestDepends(['intel_vaapi_driver.VaapiDriverTest.test_gstreamer_can_encode_with_intel_vaapi_driver']) + def test_gstreamer_can_decode_with_intel_vaapi_driver(self): + (status, output) = self.target.run('export LIBVA_DRIVER_NAME=i965; ' + 'gst-launch-1.0 filesrc location=/tmp/vtest_h264.mp4 ! ' + 'qtdemux ! h264parse ! vaapih264dec ! vaapisink') + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) diff --git a/lib/oeqa/runtime/cases/isal.py b/lib/oeqa/runtime/cases/isal.py new file mode 100644 index 00000000..5025f986 --- /dev/null +++ b/lib/oeqa/runtime/cases/isal.py @@ -0,0 +1,24 @@ +import os +from oeqa.runtime.decorator.package import OEHasPackage +from oeqa.runtime.case import OERuntimeTestCase +from oeqa.core.decorator.depends import OETestDepends + +class IsalTest(OERuntimeTestCase): + + @OEHasPackage(['isa-l']) + def test_isal_igzip_version(self): + command = 'igzip -V' + (status, output) = self.target.run(command) + self.assertEqual(status, 0, msg="Error messages: %s" % output) + + @OETestDepends(['isal.IsalTest.test_isal_igzip_version']) + def test_isal_igzip_can_compress(self): + command = 'echo "hello" > /tmp/igzip_sample' + (status, output) = self.target.run(command) + self.assertEqual(status, 0, msg="Error messages: %s" % output) + command = 'igzip -z /tmp/igzip_sample' + (status, output) = self.target.run(command) + self.assertEqual(status, 0, msg="Error messages: %s" % output) + command = 'rm /tmp/igzip_sample*' + (status, output) = self.target.run(command) + self.assertEqual(status, 0, msg="Error messages: %s" % output) diff --git a/lib/oeqa/runtime/cases/jhi.py b/lib/oeqa/runtime/cases/jhi.py new file mode 100644 index 00000000..7a24b6da --- /dev/null +++ b/lib/oeqa/runtime/cases/jhi.py @@ -0,0 +1,41 @@ +import os +from oeqa.runtime.decorator.package import OEHasPackage +from oeqa.runtime.case import OERuntimeTestCase +from oeqa.core.decorator.depends import OETestDepends + +class JhiTest(OERuntimeTestCase): + + @classmethod + def tearDownClass(cls): + _, output = cls.tc.target.run('pidof jhid') + cls.tc.target.run('kill %s' % output) + + @OEHasPackage(['openssh-sshd']) + @OEHasPackage(['jhi']) + def test_jhi_mei_driver(self): + command = 'ls /dev/mei*' + (status, output) = self.target.run(command) + self.assertEqual(status, 0, msg="Error messages: %s" % output) + + @OETestDepends(['jhi.JhiTest.test_jhi_mei_driver']) + def test_jhi_daemon_version(self): + command = 'jhid -v' + (status, output) = self.target.run(command) + self.assertEqual(status, 0, msg="Error messages: %s" % output) + + @OETestDepends(['jhi.JhiTest.test_jhi_mei_driver']) + def test_jhi_daemon_can_initialized(self): + command = 'jhid -d' + (status, output) = self.target.run(command) + self.assertEqual(status, 0, msg="Error messages: %s" % output) + + @OEHasPackage(['jhi-test']) + @OETestDepends(['jhi.JhiTest.test_jhi_daemon_can_initialized']) + def test_jhi_bist(self): + (status, output) = self.target.run('uname -m') + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + if 'x86_64' not in output: + self.skipTest("Skipped jhi bist test if not x86_64 machine (current machine: %s)." % output) + command = 'bist' + (status, output) = self.target.run(command) + self.assertEqual(status, 0, msg="Error messages: %s" % output) diff --git a/lib/oeqa/runtime/cases/libipt.py b/lib/oeqa/runtime/cases/libipt.py new file mode 100644 index 00000000..4adb13f0 --- /dev/null +++ b/lib/oeqa/runtime/cases/libipt.py @@ -0,0 +1,23 @@ +from oeqa.runtime.case import OERuntimeTestCase +from oeqa.runtime.decorator.package import OEHasPackage +from oeqa.core.decorator.depends import OETestDepends + +class LibiptTest(OERuntimeTestCase): + libipt_bin_dir = '/usr/bin/libipt/' + + @classmethod + def tearDownClass(cls): + cls.tc.target.run('rm /tmp/loop-tnt*') + + @OEHasPackage(['libipt', 'libipt2']) + @OEHasPackage(['libipt-test']) + @OEHasPackage(['yasm']) + def test_libipt_can_generate_trace_packet(self): + (status, output) = self.target.run('cd /tmp; %spttc %s/tests/loop-tnt.ptt' % + (self.libipt_bin_dir, self.libipt_bin_dir)) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OETestDepends(['libipt.LibiptTest.test_libipt_can_generate_trace_packet']) + def test_libipt_can_perform_trace_packet_dump(self): + (status, output) = self.target.run('cd /tmp; %sptdump loop-tnt.pt' % self.libipt_bin_dir) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) diff --git a/lib/oeqa/runtime/cases/libxcam.py b/lib/oeqa/runtime/cases/libxcam.py new file mode 100644 index 00000000..57192f07 --- /dev/null +++ b/lib/oeqa/runtime/cases/libxcam.py @@ -0,0 +1,37 @@ +from oeqa.runtime.case import OERuntimeTestCase +from oeqa.runtime.decorator.package import OEHasPackage +from oeqa.core.decorator.depends import OETestDepends + +class LibxcamTest(OERuntimeTestCase): + yuv_file = 'vtest.yuv' + soft_test_app_file = 'test-soft-image' + libxcam_test_app_dir = '/usr/bin/libxcam/' + libxcam_file_dir = '/tmp/' + + @classmethod + def tearDownClass(cls): + cls.tc.target.run("rm %s%s" % (cls.libxcam_file_dir, cls.yuv_file)) + + @OEHasPackage(['gstreamer1.0-plugins-base']) + @OEHasPackage(['gstreamer1.0-plugins-good']) + @OEHasPackage(['gstreamer1.0-vaapi']) + @OEHasPackage(['intel-vaapi-driver']) + def test_libxcam_can_generate_yuv_file_with_gstreamer(self): + (status, output) = self.target.run('gst-inspect-1.0 vaapi') + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + (status, output) = self.target.run('gst-launch-1.0 -ev videotestsrc num-buffers=60 ! ' + 'timeoverlay ! filesink location=%s%s' % + (self.libxcam_file_dir, self.yuv_file)) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OEHasPackage(['libxcam']) + @OEHasPackage(['libxcam-test']) + @OETestDepends(['libxcam.LibxcamTest.test_libxcam_can_generate_yuv_file_with_gstreamer']) + def test_libxcam_can_execute_soft_image_sample_app(self): + (status, output) = self.target.run('%s%s --type remap --input0 %s%s --output soft_out.nv12 --save false' % + (self.libxcam_test_app_dir, + self.soft_test_app_file, + self.libxcam_file_dir, + self.yuv_file)) + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) diff --git a/lib/oeqa/runtime/cases/microcode.py b/lib/oeqa/runtime/cases/microcode.py new file mode 100644 index 00000000..6ce36a6f --- /dev/null +++ b/lib/oeqa/runtime/cases/microcode.py @@ -0,0 +1,36 @@ +from oeqa.runtime.case import OERuntimeTestCase +from oeqa.runtime.decorator.package import OEHasPackage +import re + +class MicrocodeTest(OERuntimeTestCase): + + def get_revision_from_microcode_string_list(self, microcode_string_list, re_pattern): + re_compile = re.compile(re_pattern) + rev_list = [] + for s in microcode_string_list: + matched_revs = re_compile.findall(s) + if matched_revs: + for mr in matched_revs: + rev_list.append(int(mr, 16)) + return rev_list + + @OEHasPackage(["iucode-tool"]) + def test_microcode_update(self): + (status, output) = self.target.run('iucode_tool /lib/firmware/intel-ucode/ -tb -lS | grep rev') + if status: + self.skipTest("The iucode_tool detected no microcode for update.") + + selected_microcodes = output.splitlines() + selected_rev_list = self.get_revision_from_microcode_string_list(selected_microcodes, "rev (\w*)") + self.assertTrue(selected_rev_list, msg="Could not find any rev from iucode_tool selected microcode.") + + (status, output) = self.target.run('dmesg | grep microcode') + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + updated_microcodes = output.splitlines() + updated_rev_list = self.get_revision_from_microcode_string_list(updated_microcodes, "revision=(\w*)") + self.assertTrue(updated_rev_list, msg="Could not find any updated revision from microcode dmesg.") + + for ul in updated_rev_list: + self.assertTrue(ul in selected_rev_list, msg="Updated revision, %s, not in selected revision list (%s)" % + (ul, selected_rev_list)) diff --git a/lib/oeqa/runtime/cases/mkl_dnn.py b/lib/oeqa/runtime/cases/mkl_dnn.py new file mode 100644 index 00000000..c7994b13 --- /dev/null +++ b/lib/oeqa/runtime/cases/mkl_dnn.py @@ -0,0 +1,67 @@ +from oeqa.runtime.case import OERuntimeTestCase +from oeqa.runtime.decorator.package import OEHasPackage +from oeqa.core.decorator.depends import OETestDepends +from oeqa.runtime.miutils.targets.oeqatarget import OEQATarget +from oeqa.runtime.miutils.tests.mkl_dnn_test import MkldnnTest + +class MklDnn(OERuntimeTestCase): + + @classmethod + def setUpClass(cls): + cls.mkldnntest = MkldnnTest(OEQATarget(cls.tc.target)) + + @classmethod + def tearDownClass(cls): + cls.mkldnntest.tear_down() + + @OEHasPackage(['libdnnl', 'libdnnl1']) + @OEHasPackage(['libdnnl-src']) + @OEHasPackage(['libdnnl-dev']) + @OEHasPackage(['gcc']) + @OEHasPackage(['gcc-symlinks']) + @OEHasPackage(['libstdc++-dev']) + @OEHasPackage(['binutils']) + def test_mkldnn_can_compile_and_execute(self): + (status, output) = self.mkldnntest.test_mkldnn_can_compile_and_execute() + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OEHasPackage(['mkl-dnn', 'libdnnl1']) + @OEHasPackage(['mkl-dnn-test', 'libdnnl-test']) + def test_mkldnn_benchdnn_package_available(self): + (status, output) = self.mkldnntest.test_mkldnn_benchdnn_package_available() + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OETestDepends(['mkl_dnn.MklDnn.test_mkldnn_benchdnn_package_available']) + def test_mkldnn_conv_api(self): + (status, output) = self.mkldnntest.test_mkldnn_conv_api() + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OETestDepends(['mkl_dnn.MklDnn.test_mkldnn_benchdnn_package_available']) + def test_mkldnn_bnorm_api(self): + (status, output) = self.mkldnntest.test_mkldnn_bnorm_api() + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OETestDepends(['mkl_dnn.MklDnn.test_mkldnn_benchdnn_package_available']) + def test_mkldnn_deconv_api(self): + (status, output) = self.mkldnntest.test_mkldnn_deconv_api() + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OETestDepends(['mkl_dnn.MklDnn.test_mkldnn_benchdnn_package_available']) + def test_mkldnn_ip_api(self): + (status, output) = self.mkldnntest.test_mkldnn_ip_api() + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OETestDepends(['mkl_dnn.MklDnn.test_mkldnn_benchdnn_package_available']) + def test_mkldnn_reorder_api(self): + (status, output) = self.mkldnntest.test_mkldnn_reorder_api() + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OETestDepends(['mkl_dnn.MklDnn.test_mkldnn_benchdnn_package_available']) + def test_mkldnn_rnn_api(self): + (status, output) = self.mkldnntest.test_mkldnn_rnn_api() + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OETestDepends(['mkl_dnn.MklDnn.test_mkldnn_benchdnn_package_available']) + def test_mkldnn_shuffle_api(self): + (status, output) = self.mkldnntest.test_mkldnn_shuffle_api() + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) diff --git a/lib/oeqa/runtime/cases/thermald.py b/lib/oeqa/runtime/cases/thermald.py new file mode 100644 index 00000000..b0efecd8 --- /dev/null +++ b/lib/oeqa/runtime/cases/thermald.py @@ -0,0 +1,45 @@ +from oeqa.runtime.case import OERuntimeTestCase +from oeqa.core.decorator.depends import OETestDepends +from oeqa.runtime.decorator.package import OEHasPackage +import threading +import time +import re + +class ThermaldTest(OERuntimeTestCase): + def get_thermal_zone_with_target_type(self, target_type): + i = 0 + while True: + status, output = self.target.run('cat /sys/class/thermal/thermal_zone%s/type' % i) + if status: + return -1 + if output == target_type: + return i + i = i + 1 + + def run_thermald_emulation_to_exceed_setpoint_then_end_thermald_process(self, run_args): + time.sleep(2) + self.target.run('echo 106000 > /sys/class/thermal/thermal_zone%s/emul_temp' % run_args) + time.sleep(2) + __, output = self.target.run('pidof thermald') + self.target.run('kill -9 %s' % output) + + def test_thermald_emulation_mode(self): + # Thermald test depend on thermal emulation, where CONFIG_THERMAL_EMULATION=y was required + # To enable thermal emulation, refer to https://github.com/intel/thermal_daemon/blob/master/test/readme_test.txt + (status, output) = self.target.run('gzip -dc /proc/config.gz | grep CONFIG_THERMAL_EMULATION=y') + self.assertEqual(status, 0, msg='status and output: %s and %s' % (status, output)) + + @OEHasPackage(['thermald']) + @OETestDepends(['thermald.ThermaldTest.test_thermald_emulation_mode']) + def test_thermald_can_track_thermal_exceed_setpoint(self): + x86_thermal_zone_index = self.get_thermal_zone_with_target_type('x86_pkg_temp') + if x86_thermal_zone_index < 0: + self.skipTest('Could not get the thermal zone index for target type (%s)' % 'x86_pkg_temp') + td_thread = threading.Thread(target=self.run_thermald_emulation_to_exceed_setpoint_then_end_thermald_process, + args=(x86_thermal_zone_index,)) + td_thread.start() + status, output = self.target.run('thermald --no-daemon --loglevel=info') + regex_search = ".*thd_cdev_set_state.*106000" + regex_comp = re.compile(regex_search) + m = regex_comp.search(output) + self.assertTrue(m, msg='status and output: %s and %s' % (status, output)) diff --git a/lib/oeqa/runtime/files/dldt-inference-engine/classification_sample.py b/lib/oeqa/runtime/files/dldt-inference-engine/classification_sample.py new file mode 100644 index 00000000..1906e9fe --- /dev/null +++ b/lib/oeqa/runtime/files/dldt-inference-engine/classification_sample.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python3 +""" + Copyright (C) 2018-2019 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +""" +from __future__ import print_function +import sys +import os +from argparse import ArgumentParser, SUPPRESS +import cv2 +import numpy as np +import logging as log +from time import time +from openvino.inference_engine import IENetwork, IECore + + +def build_argparser(): + parser = ArgumentParser(add_help=False) + args = parser.add_argument_group('Options') + args.add_argument('-h', '--help', action='help', default=SUPPRESS, help='Show this help message and exit.') + args.add_argument("-m", "--model", help="Required. Path to an .xml file with a trained model.", required=True, + type=str) + args.add_argument("-i", "--input", help="Required. Path to a folder with images or path to an image files", + required=True, + type=str, nargs="+") + args.add_argument("-l", "--cpu_extension", + help="Optional. Required for CPU custom layers. " + "MKLDNN (CPU)-targeted custom layers. Absolute path to a shared library with the" + " kernels implementations.", type=str, default=None) + args.add_argument("-d", "--device", + help="Optional. Specify the target device to infer on; CPU, GPU, FPGA, HDDL, MYRIAD or HETERO: is " + "acceptable. The sample will look for a suitable plugin for device specified. Default " + "value is CPU", + default="CPU", type=str) + args.add_argument("--labels", help="Optional. Path to a labels mapping file", default=None, type=str) + args.add_argument("-nt", "--number_top", help="Optional. Number of top results", default=10, type=int) + + return parser + + +def main(): + log.basicConfig(format="[ %(levelname)s ] %(message)s", level=log.INFO, stream=sys.stdout) + args = build_argparser().parse_args() + model_xml = args.model + model_bin = os.path.splitext(model_xml)[0] + ".bin" + + # Plugin initialization for specified device and load extensions library if specified + log.info("Creating Inference Engine") + ie = IECore() + if args.cpu_extension and 'CPU' in args.device: + ie.add_extension(args.cpu_extension, "CPU") + # Read IR + log.info("Loading network files:\n\t{}\n\t{}".format(model_xml, model_bin)) + net = IENetwork(model=model_xml, weights=model_bin) + + if "CPU" in args.device: + supported_layers = ie.query_network(net, "CPU") + not_supported_layers = [l for l in net.layers.keys() if l not in supported_layers] + if len(not_supported_layers) != 0: + log.error("Following layers are not supported by the plugin for specified device {}:\n {}". + format(args.device, ', '.join(not_supported_layers))) + log.error("Please try to specify cpu extensions library path in sample's command line parameters using -l " + "or --cpu_extension command line argument") + sys.exit(1) + + assert len(net.inputs.keys()) == 1, "Sample supports only single input topologies" + assert len(net.outputs) == 1, "Sample supports only single output topologies" + + log.info("Preparing input blobs") + input_blob = next(iter(net.inputs)) + out_blob = next(iter(net.outputs)) + net.batch_size = len(args.input) + + # Read and pre-process input images + n, c, h, w = net.inputs[input_blob].shape + images = np.ndarray(shape=(n, c, h, w)) + for i in range(n): + image = cv2.imread(args.input[i]) + if image.shape[:-1] != (h, w): + log.warning("Image {} is resized from {} to {}".format(args.input[i], image.shape[:-1], (h, w))) + image = cv2.resize(image, (w, h)) + image = image.transpose((2, 0, 1)) # Change data layout from HWC to CHW + images[i] = image + log.info("Batch size is {}".format(n)) + + # Loading model to the plugin + log.info("Loading model to the plugin") + exec_net = ie.load_network(network=net, device_name=args.device) + + # Start sync inference + log.info("Starting inference in synchronous mode") + res = exec_net.infer(inputs={input_blob: images}) + + # Processing output blob + log.info("Processing output blob") + res = res[out_blob] + log.info("Top {} results: ".format(args.number_top)) + if args.labels: + with open(args.labels, 'r') as f: + labels_map = [x.split(sep=' ', maxsplit=1)[-1].strip() for x in f] + else: + labels_map = None + classid_str = "classid" + probability_str = "probability" + for i, probs in enumerate(res): + probs = np.squeeze(probs) + top_ind = np.argsort(probs)[-args.number_top:][::-1] + print("Image {}\n".format(args.input[i])) + print(classid_str, probability_str) + print("{} {}".format('-' * len(classid_str), '-' * len(probability_str))) + for id in top_ind: + det_label = labels_map[id] if labels_map else "{}".format(id) + label_length = len(det_label) + space_num_before = (len(classid_str) - label_length) // 2 + space_num_after = len(classid_str) - (space_num_before + label_length) + 2 + space_num_before_prob = (len(probability_str) - len(str(probs[id]))) // 2 + print("{}{}{}{}{:.7f}".format(' ' * space_num_before, det_label, + ' ' * space_num_after, ' ' * space_num_before_prob, + probs[id])) + print("\n") + log.info("This sample is an API example, for any performance measurements please use the dedicated benchmark_app tool\n") + +if __name__ == '__main__': + sys.exit(main() or 0) diff --git a/lib/oeqa/runtime/miutils/dldtutils.py b/lib/oeqa/runtime/miutils/dldtutils.py new file mode 100644 index 00000000..45bf2e12 --- /dev/null +++ b/lib/oeqa/runtime/miutils/dldtutils.py @@ -0,0 +1,3 @@ + +def get_testdata_config(testdata, config): + return testdata.get(config) diff --git a/lib/oeqa/runtime/miutils/targets/oeqatarget.py b/lib/oeqa/runtime/miutils/targets/oeqatarget.py new file mode 100644 index 00000000..a9f7f1b4 --- /dev/null +++ b/lib/oeqa/runtime/miutils/targets/oeqatarget.py @@ -0,0 +1,11 @@ + +class OEQATarget(object): + + def __init__(self, target): + self.target = target + + def run(self, cmd): + return self.target.run(cmd) + + def copy_to(self, source, destination_dir): + self.target.copyTo(source, destination_dir) diff --git a/lib/oeqa/runtime/miutils/tests/dldt_inference_engine_test.py b/lib/oeqa/runtime/miutils/tests/dldt_inference_engine_test.py new file mode 100644 index 00000000..31bfb539 --- /dev/null +++ b/lib/oeqa/runtime/miutils/tests/dldt_inference_engine_test.py @@ -0,0 +1,56 @@ +import os +script_path = os.path.dirname(os.path.realpath(__file__)) +files_path = os.path.join(script_path, '../../files/') + +class DldtInferenceEngineTest(object): + ie_input_files = {'ie_python_sample': 'classification_sample.py', + 'input': 'chicky_512.png', + 'input_download': 'https://raw.githubusercontent.com/opencv/opencv/master/samples/data/chicky_512.png', + 'model': 'squeezenet_v1.1.xml'} + + def __init__(self, target, work_dir): + self.target = target + self.work_dir = work_dir + + def setup(self): + self.target.run('mkdir -p %s' % self.work_dir) + self.target.copy_to(os.path.join(files_path, 'dldt-inference-engine', self.ie_input_files['ie_python_sample']), + self.work_dir) + python_cmd = 'from openvino.inference_engine import IENetwork, IECore; ie = IECore(); print(ie.available_devices)' + __, output = self.target.run('python3 -c "%s"' % python_cmd) + self.available_devices = output + + def tear_down(self): + self.target.run('rm -rf %s' % self.work_dir) + + def test_check_if_openvino_device_available(self, device): + if device not in self.available_devices: + return False, self.available_devices + return True, self.available_devices + + def test_can_download_input_file(self, proxy_port): + return self.target.run('cd %s; wget %s -e https_proxy=%s' % + (self.work_dir, + self.ie_input_files['input_download'], + proxy_port)) + + def test_dldt_ie_classification_with_device(self, device, ir_files_dir): + return self.target.run('classification_sample_async -d %s -i %s -m %s' % + (device, + os.path.join(self.work_dir, self.ie_input_files['input']), + os.path.join(ir_files_dir, self.ie_input_files['model']))) + + def test_dldt_ie_classification_python_api_with_device(self, device, ir_files_dir, extension=''): + if extension: + return self.target.run('python3 %s -d %s -i %s -m %s -l %s' % + (os.path.join(self.work_dir, self.ie_input_files['ie_python_sample']), + device, + os.path.join(self.work_dir, self.ie_input_files['input']), + os.path.join(ir_files_dir, self.ie_input_files['model']), + extension)) + else: + return self.target.run('python3 %s -d %s -i %s -m %s' % + (os.path.join(self.work_dir, self.ie_input_files['ie_python_sample']), + device, + os.path.join(self.work_dir, self.ie_input_files['input']), + os.path.join(ir_files_dir, self.ie_input_files['model']))) diff --git a/lib/oeqa/runtime/miutils/tests/dldt_model_optimizer_test.py b/lib/oeqa/runtime/miutils/tests/dldt_model_optimizer_test.py new file mode 100644 index 00000000..7d3db15b --- /dev/null +++ b/lib/oeqa/runtime/miutils/tests/dldt_model_optimizer_test.py @@ -0,0 +1,23 @@ +import os + +class DldtModelOptimizerTest(object): + mo_input_files = {'model': 'squeezenet_v1.1.caffemodel', + 'prototxt': 'deploy.prototxt'} + mo_exe = 'mo.py' + + def __init__(self, target, work_dir): + self.target = target + self.work_dir = work_dir + + def setup(self): + self.target.run('mkdir -p %s' % self.work_dir) + + def tear_down(self): + self.target.run('rm -rf %s' % self.work_dir) + + def test_dldt_mo_can_create_ir(self, mo_exe_dir, mo_files_dir): + return self.target.run('python3 %s --input_model %s --input_proto %s --output_dir %s --data_type FP16' % + (os.path.join(mo_exe_dir, self.mo_exe), + os.path.join(mo_files_dir, self.mo_input_files['model']), + os.path.join(mo_files_dir, self.mo_input_files['prototxt']), + self.work_dir)) diff --git a/lib/oeqa/runtime/miutils/tests/mkl_dnn_test.py b/lib/oeqa/runtime/miutils/tests/mkl_dnn_test.py new file mode 100644 index 00000000..13afd1a4 --- /dev/null +++ b/lib/oeqa/runtime/miutils/tests/mkl_dnn_test.py @@ -0,0 +1,57 @@ + +class MkldnnTest(object): + mkldnn_target_test_filename = 'mkl-dnn-c' + + def __init__(self, target): + self.target = target + + def tear_down(self): + self.target.run('rm /tmp/%s' % self.mkldnn_target_test_filename) + + def test_mkldnn_can_compile_and_execute(self): + mkldnn_src_dir = '/usr/src/debug/mkl-dnn/' + mkldnn_src_test_filename = 'api.c' + mkldnn_src_test_file = '' + + (status, output) = self.target.run('cd %s; find -name %s' % (mkldnn_src_dir, mkldnn_src_test_filename)) + if status: + return status, output + + mkldnn_src_test_file = os.path.join(mkldnn_src_dir, output) + (status, output) = self.target.run('gcc %s -o /tmp/%s -ldnnl' % (mkldnn_src_test_file, self.mkldnn_target_test_filename)) + if status: + return status, output + + (status, output) = self.target.run('cd /tmp; ./%s' % self.mkldnn_target_test_filename) + return status, output + + def test_mkldnn_benchdnn_package_available(self): + (status, output) = self.target.run('ls /usr/bin/mkl-dnn/tests/benchdnn') + return status, output + + def _run_mkldnn_benchdnn_test(self, cmd): + (status, output) = self.target.run('cd /usr/bin/mkl-dnn/tests/benchdnn; %s' % cmd) + return status, output + + def test_mkldnn_conv_api(self): + return self._run_mkldnn_benchdnn_test('./benchdnn --conv --batch=inputs/conv/test_conv_3d') + + def test_mkldnn_bnorm_api(self): + return self._run_mkldnn_benchdnn_test('./benchdnn --bnorm --batch=inputs/bnorm/test_bnorm_regressions') + + def test_mkldnn_deconv_api(self): + return self._run_mkldnn_benchdnn_test('./benchdnn --deconv --batch=inputs/deconv/test_deconv_bfloat16') + + def test_mkldnn_ip_api(self): + return self._run_mkldnn_benchdnn_test('./benchdnn --ip --batch=inputs/ip/test_ip_bfloat16') + + def test_mkldnn_reorder_api(self): + return self._run_mkldnn_benchdnn_test('./benchdnn --reorder --batch=inputs/reorder/test_reorder_bfloat16') + + def test_mkldnn_rnn_api(self): + # test_rnn_inference was not yet ready and was expected to fail + # while waiting it to be ready, use test_rnn_small for now + return self._run_mkldnn_benchdnn_test('./benchdnn --rnn --batch=inputs/rnn/test_rnn_small') + + def test_mkldnn_shuffle_api(self): + return self._run_mkldnn_benchdnn_test('./benchdnn --shuffle --batch=inputs/shuffle/test_shuffle_bfloat16')
\ No newline at end of file diff --git a/lib/oeqa/runtime/miutils/tests/squeezenet_model_download_test.py b/lib/oeqa/runtime/miutils/tests/squeezenet_model_download_test.py new file mode 100644 index 00000000..a3e46a0a --- /dev/null +++ b/lib/oeqa/runtime/miutils/tests/squeezenet_model_download_test.py @@ -0,0 +1,25 @@ +class SqueezenetModelDownloadTest(object): + download_files = {'squeezenet1.1.prototxt': 'https://raw.githubusercontent.com/DeepScale/SqueezeNet/a47b6f13d30985279789d08053d37013d67d131b/SqueezeNet_v1.1/deploy.prototxt', + 'squeezenet1.1.caffemodel': 'https://github.com/DeepScale/SqueezeNet/raw/a47b6f13d30985279789d08053d37013d67d131b/SqueezeNet_v1.1/squeezenet_v1.1.caffemodel'} + + def __init__(self, target, work_dir): + self.target = target + self.work_dir = work_dir + + def setup(self): + self.target.run('mkdir -p %s' % self.work_dir) + + def tear_down(self): + self.target.run('rm -rf %s' % self.work_dir) + + def test_can_download_squeezenet_model(self, proxy_port): + return self.target.run('cd %s; wget %s -e https_proxy=%s' % + (self.work_dir, + self.download_files['squeezenet1.1.caffemodel'], + proxy_port)) + + def test_can_download_squeezenet_prototxt(self, proxy_port): + return self.target.run('cd %s; wget %s -e https_proxy=%s' % + (self.work_dir, + self.download_files['squeezenet1.1.prototxt'], + proxy_port)) diff --git a/lib/oeqa/selftest/cases/secureboot.py b/lib/oeqa/selftest/cases/secureboot.py new file mode 100644 index 00000000..4c059e25 --- /dev/null +++ b/lib/oeqa/selftest/cases/secureboot.py @@ -0,0 +1,176 @@ +#!/usr/bin/env python +# ex:ts=4:sw=4:sts=4:et +# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- +# +# Copyright (c) 2017, Intel Corporation. +# All rights reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License version 2 as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# AUTHORS +# Mikko Ylinen <mikko.ylinen@linux.intel.com> +# +# Based on meta/lib/oeqa/selftest/* and meta-refkit/lib/oeqa/selftest/* + +"""Test cases for secure boot with QEMU running OVMF.""" + +import os +import unittest +import re +import glob +from shutil import rmtree, copy + +from oeqa.core.decorator.depends import OETestDepends +from oeqa.selftest.case import OESelftestTestCase +from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars, runqemu + +class SecureBootTests(OESelftestTestCase): + """Secure Boot test class.""" + + ovmf_keys_enrolled = False + ovmf_qemuparams = '' + ovmf_dir = '' + test_image_unsigned = 'secureboot-selftest-image-unsigned' + test_image_signed = 'secureboot-selftest-image-signed' + correct_key = 'refkit-db' + incorrect_key = 'incorrect' + + @classmethod + def setUpLocal(self): + + if not SecureBootTests.ovmf_keys_enrolled: + bitbake('ovmf ovmf-shell-image-enrollkeys', output_log=self.logger) + + bb_vars = get_bb_vars(['TMPDIR', 'DEPLOY_DIR_IMAGE']) + + SecureBootTests.ovmf_dir = os.path.join(bb_vars['TMPDIR'], 'oeselftest', 'secureboot', 'ovmf') + bb.utils.mkdirhier(SecureBootTests.ovmf_dir) + + # Copy (all) OVMF in a temporary location + for src in glob.glob('%s/ovmf.*' % bb_vars['DEPLOY_DIR_IMAGE']): + copy(src, SecureBootTests.ovmf_dir) + + SecureBootTests.ovmf_qemuparams = '-drive if=pflash,format=qcow2,file=%s/ovmf.secboot.qcow2' % SecureBootTests.ovmf_dir + + cmd = ("runqemu " + "qemuparams='%s' " + "ovmf-shell-image-enrollkeys wic intel-corei7-64 " + "nographic slirp") % SecureBootTests.ovmf_qemuparams + print('Running "%s"' % cmd) + status = runCmd(cmd) + + if not re.search('info: success', status.output, re.M): + self.fail('Failed to enroll keys. EFI shell log:\n%s' % status.output) + else: + # keys enrolled in ovmf.secboot.vars + SecureBootTests.ovmf_keys_enrolled = True + + @classmethod + def tearDownLocal(self): + # Seems this is mandatory between the tests (a signed image is booted + # when running test_boot_unsigned_image after test_boot_signed_image). + # bitbake('-c clean %s' % test_image, output_log=self.logger) + # + # Whatever the problem was, it no longer seems to be necessary, so + # we can skip the time-consuming clean + full rebuild (5:04 min instead + # of 6:55min here). + pass + + @classmethod + def tearDownClass(self): + bitbake('ovmf-shell-image-enrollkeys:do_cleanall', output_log=self.logger) + rmtree(self.ovmf_dir, ignore_errors=True) + + def secureboot_with_image(self, boot_timeout=300, signing_key=None): + """Boot the image with UEFI SecureBoot enabled and see the result. """ + + config = "" + + if signing_key: + test_image = self.test_image_signed + config += 'SECURE_BOOT_SIGNING_KEY = "${THISDIR}/files/%s.key"\n' % signing_key + config += 'SECURE_BOOT_SIGNING_CERT = "${THISDIR}/files/%s.crt"\n' % signing_key + else: + test_image = self.test_image_unsigned + + self.write_config(config) + bitbake(test_image, output_log=self.logger) + self.remove_config(config) + + # Some of the cases depend on the timeout to expire. Allow overrides + # so that we don't have to wait 1000s which is the default. + overrides = { + 'TEST_QEMUBOOT_TIMEOUT': boot_timeout, + } + + print('Booting %s' % test_image) + + try: + with runqemu(test_image, ssh=False, + runqemuparams='nographic slirp', + qemuparams=self.ovmf_qemuparams, + overrides=overrides, + image_fstype='wic') as qemu: + + cmd = 'uname -a' + + status, output = qemu.run_serial(cmd) + + self.assertTrue(status, 'Could not run \'uname -a\' (status=%s):\n%s' % (status, output)) + + # if we got this far without a correctly signed image, something went wrong + if signing_key != self.correct_key: + self.fail('The image not give a Security violation when expected. Boot log:\n%s' % output) + + + except Exception: + + # Currently runqemu() fails if 'login:' prompt is not seen and it's + # not possible to login as 'root'. Those conditions aren't met when + # booting to EFI shell (See [YOCTO #11438]). We catch the failure + # and parse the boot log to determine the success. Note: the + # timeout triggers verbose bb.error() but that's normal with some + # of the test cases. + + workdir = get_bb_var('WORKDIR', test_image) + bootlog = "%s/testimage/qemu_boot_log" % workdir + + with open(bootlog, "r") as log: + + # This isn't right but all we can do at this point. The right + # approach would run commands in the EFI shell to determine + # the BIOS rejects unsigned and/or images signed with keys in + # dbx key store but that needs changes in oeqa framework. + + output = log.read() + + # PASS if we see a security violation on unsigned or incorrectly signed images, otherwise fail + if signing_key == self.correct_key: + self.fail('Correctly signed image failed to boot. Boot log:\n%s' % output) + elif not re.search('Security Violation', output): + self.fail('The image not give a Security violation when expected. Boot log:\n%s' % output) + + def test_boot_unsigned_image(self): + """ Boot unsigned image with secureboot enabled in UEFI.""" + self.secureboot_with_image(boot_timeout=120, signing_key=None) + + @OETestDepends(['secureboot.SecureBootTests.test_boot_unsigned_image']) + def test_boot_incorrectly_signed_image(self): + """ Boot (correctly) signed image with secureboot enabled in UEFI.""" + self.secureboot_with_image(boot_timeout=120, signing_key=self.incorrect_key) + + @OETestDepends(['secureboot.SecureBootTests.test_boot_incorrectly_signed_image']) + def test_boot_correctly_signed_image(self): + """ Boot (correctly) signed image with secureboot enabled in UEFI.""" + self.secureboot_with_image(boot_timeout=150, signing_key=self.correct_key) |