diff --git a/.github/workflows/github_actions_aws_rhel_python64.yml b/.github/workflows/github_actions_aws_rhel_python64.yml index a5230a68ec..b3ffbbc87f 100644 --- a/.github/workflows/github_actions_aws_rhel_python64.yml +++ b/.github/workflows/github_actions_aws_rhel_python64.yml @@ -16,7 +16,7 @@ on: - synchronize - reopened - # Allows you to run this workflow manually from the Actions tab. + # Allows you to run this workflow manually from the Actions tab. workflow_dispatch: jobs: do-the-job1: @@ -26,7 +26,7 @@ jobs: - self-hosted - linux - x64 - - rdss-nimibot-rhel-83-py64 + - rdss-nimibot-rhel-96-py64 timeout-minutes: 40 strategy: matrix: diff --git a/docs/nirfsg/examples.rst b/docs/nirfsg/examples.rst index e0cbb3685b..657bee6032 100644 --- a/docs/nirfsg/examples.rst +++ b/docs/nirfsg/examples.rst @@ -3,6 +3,15 @@ Examples `You can download all nirfsg examples for latest version here `_ +conftest.py +----------- + +.. literalinclude:: ../../src/nirfsg/examples/conftest.py + :language: python + :linenos: + :encoding: utf8 + :caption: `(conftest.py) `_ + nirfsg_arb_waveform.py ---------------------- diff --git a/src/nirfsg/examples/conftest.py b/src/nirfsg/examples/conftest.py new file mode 100644 index 0000000000..a3a401a7e5 --- /dev/null +++ b/src/nirfsg/examples/conftest.py @@ -0,0 +1,17 @@ +import pathlib +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) +import system_test_utilities # noqa: E402 + +_session_exitstatus = {} + + +def pytest_sessionfinish(session, exitstatus): + '''Capture the pytest result code for use during unconfigure.''' + _session_exitstatus['code'] = int(exitstatus) + + +def pytest_unconfigure(config): + '''Hard-exit after all reporting is done to skip the py3.10 native abort.''' + system_test_utilities.finalize_test_process(_session_exitstatus.get('code', 0)) diff --git a/src/nirfsg/system_tests/conftest.py b/src/nirfsg/system_tests/conftest.py new file mode 100644 index 0000000000..a3a401a7e5 --- /dev/null +++ b/src/nirfsg/system_tests/conftest.py @@ -0,0 +1,17 @@ +import pathlib +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).parent.parent.parent / 'shared')) +import system_test_utilities # noqa: E402 + +_session_exitstatus = {} + + +def pytest_sessionfinish(session, exitstatus): + '''Capture the pytest result code for use during unconfigure.''' + _session_exitstatus['code'] = int(exitstatus) + + +def pytest_unconfigure(config): + '''Hard-exit after all reporting is done to skip the py3.10 native abort.''' + system_test_utilities.finalize_test_process(_session_exitstatus.get('code', 0)) diff --git a/src/niscope/system_tests/test_system_niscope.py b/src/niscope/system_tests/test_system_niscope.py index 60702465e6..ca0827b310 100644 --- a/src/niscope/system_tests/test_system_niscope.py +++ b/src/niscope/system_tests/test_system_niscope.py @@ -38,6 +38,11 @@ daqmx_sim_5142_lock_file = os.path.join(tempfile.gettempdir(), 'daqmx_5142.lock') daqmx_sim_5142_lock = fasteners.InterProcessLock(daqmx_sim_5142_lock_file) +_ni_scope_daqmx_simulation_skip_reason = ( + 'Skipped due to Bug 3934983: nisimdev persistent simulation for ni-scope-daqmx devices ' + '(PXI-5124/PXI-5142) fails on RHEL 9.6, so skipping these test as the pipeline cannot execute.' +) + def check_fetched_data( data, # either waveforms or measurement_stats @@ -441,6 +446,7 @@ def test_configure_chan_characteristics(self, multi_instrument_session): multi_instrument_session.configure_chan_characteristics(50, 0) assert 50.0 == multi_instrument_session.input_impedance + @pytest.mark.skip(reason=_ni_scope_daqmx_simulation_skip_reason) def test_filter_coefficients(self, session_5142): assert [1.0] + [0.0] * 34 == session_5142.get_equalization_filter_coefficients() # coefficients list should have 35 items try: @@ -513,6 +519,7 @@ def test_import_export_file(self, multi_instrument_session): def test_configure_trigger_software(self, multi_instrument_session): multi_instrument_session.configure_trigger_software() + @pytest.mark.skip(reason=_ni_scope_daqmx_simulation_skip_reason) def test_configure_trigger_video(self, session_5124): session_5124.configure_trigger_video('0', niscope.VideoSignalFormat.PAL, niscope.VideoTriggerEvent.FIELD1, niscope.VideoPolarity.POSITIVE, niscope.TriggerCoupling.DC) assert niscope.VideoSignalFormat.PAL == session_5124.tv_trigger_signal_format diff --git a/src/shared/system_test_utilities.py b/src/shared/system_test_utilities.py index dea3b2d1cd..bf5812e33c 100644 --- a/src/shared/system_test_utilities.py +++ b/src/shared/system_test_utilities.py @@ -3,10 +3,39 @@ import pytest import re import subprocess +import sys import threading import time +def finalize_test_process(exitstatus): + '''Exit the process immediately to avoid the py3.10 native-teardown abort. + + On the RHEL 9.6 / Python 3.10 runner the NI native runtime aborts with a + fatal glibc robust-mutex assertion (SIGABRT, exit -6) during interpreter + finalization -- after every test has already passed and after faulthandler + itself has been torn down. The abort is in native teardown that runs after + Python shutdown, so it cannot be caught or fixed from Python. Python 3.11+ + finalizes in a different order and does not hit it. + + Calling os._exit() exits before interpreter finalization and skips that + native teardown entirely. Coverage data (started by `coverage run`) is + explicitly stopped and saved first so that it is not lost, then stdio is + flushed, then the process exits with the pytest result code. + ''' + try: + import coverage + cov = coverage.Coverage.current() + if cov is not None: + cov.stop() + cov.save() + except Exception: + pass + sys.stdout.flush() + sys.stderr.flush() + os._exit(int(exitstatus)) + + class GrpcServerProcess: def __init__(self, config_file_path): server_exe = self._get_grpc_server_exe()