diff --git a/requirements.txt b/requirements.txt index 1da22d8f..bbbdf065 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,6 +5,9 @@ msgpack influxdb PyYAML +# FakeDataAgent +numpy + # Lakeshore240 pyserial @@ -25,3 +28,4 @@ pytest pytest-cov docker pytest-docker-compose +pytest-dependency diff --git a/tests/test_aggregator.py b/tests/test_aggregator.py index 8cd7eb56..a9a0322a 100644 --- a/tests/test_aggregator.py +++ b/tests/test_aggregator.py @@ -4,11 +4,29 @@ from unittest.mock import patch -import so3g -from spt3g import core +try: + import so3g + from spt3g import core -from ocs.agent.aggregator import Provider, g3_cast, make_filename + from ocs.agent.aggregator import Provider, g3_cast, make_filename +except ModuleNotFoundError as e: + print(f"Unable to import either so3g or spt3g: {e}") + +@pytest.mark.dependency(name="so3g") +def test_so3g_spt3g_import(): + """Test that we can import spt3g/so3g. Used to skip tests dependent on + these imports. + + """ + import so3g + from spt3g import core + + # Just to avoid flake8 complaining we aren't using these imports + print(so3g.__file__) + print(core.__file__) + +@pytest.mark.dependency(depends=["so3g"]) def test_passing_float_in_provider_to_frame(): """Float is the expected type we should be passing. @@ -31,6 +49,7 @@ def test_passing_float_in_provider_to_frame(): provider.to_frame(hksess=sess) +@pytest.mark.dependency(depends=["so3g"]) def test_passing_float_like_str_in_provider_to_frame(): """Here we test passing a string amongst ints. This shouldn't make it to the aggregator, and instead the Aggregator logs should display an error @@ -55,6 +74,7 @@ def test_passing_float_like_str_in_provider_to_frame(): provider.to_frame(hksess=sess) +@pytest.mark.dependency(depends=["so3g"]) def test_passing_non_float_like_str_in_provider_to_frame(): """Similar to passing a float like str, here we test passing a non-float like str. We can't put this into an so3g.IrregBlockDouble(), so this'll fail. @@ -80,6 +100,7 @@ def test_passing_non_float_like_str_in_provider_to_frame(): provider.to_frame(hksess=sess) +@pytest.mark.dependency(depends=["so3g"]) def test_sparsely_sampled_block(): """If a block is sparsely sampled and published, the aggregator was including its block_name anyway, even when missing. This test publishes two @@ -152,6 +173,7 @@ def test_sparsely_sampled_block(): # This is perhaps another problem, I'm passing irregular length data sets and # it's not raising any sort of alarm. How does this get handled? +@pytest.mark.dependency(depends=["so3g"]) def test_data_type_in_provider_save_to_block(): provider = Provider('test_provider', 'test_sessid', 3, 1) provider.frame_start_time = time.time() @@ -164,6 +186,7 @@ def test_data_type_in_provider_save_to_block(): provider.save_to_block(data) # 'data' field names +@pytest.mark.dependency(depends=["so3g"]) def test_passing_invalid_data_field_name1(): """Invalid data field names should get caught by the Feed, however, we check for them in the Aggregator as well. @@ -186,6 +209,7 @@ def test_passing_invalid_data_field_name1(): assert 'invalidkey' in provider.blocks['test'].data.keys() assert 'invalid.key' not in provider.blocks['test'].data.keys() +@pytest.mark.dependency(depends=["so3g"]) def test_passing_invalid_data_field_name2(): """Invalid data field names should get caught by the Feed, however, we check for them in the Aggregator as well. @@ -208,6 +232,7 @@ def test_passing_invalid_data_field_name2(): assert '__invalidkey' in provider.blocks['test'].data.keys() assert '__123invalid.key' not in provider.blocks['test'].data.keys() +@pytest.mark.dependency(depends=["so3g"]) def test_passing_too_long_data_field_name(): """Invalid data field names should get caught by the Feed, however, we check for them in the Aggregator as well. @@ -231,6 +256,7 @@ def test_passing_too_long_data_field_name(): assert 'a'*255 in provider.blocks['test'].data.keys() +@pytest.mark.dependency(depends=["so3g"]) def test_long_duplicate_name(): """Invalid data field names should get caught by the Feed, however, we check for them in the Aggregator as well. @@ -255,6 +281,7 @@ def test_long_duplicate_name(): assert 'a'*255 in provider.blocks['test'].data.keys() assert 'a'*252 + '_01' in provider.blocks['test'].data.keys() +@pytest.mark.dependency(depends=["so3g"]) def test_reducing_to_duplicate_field_names(): """Invalid data field names get modified by the Aggregator to comply with the set rules. This can result in duplicate field names under certain @@ -282,6 +309,7 @@ def test_reducing_to_duplicate_field_names(): assert 'aninvalidkey' in provider.blocks['test'].data.keys() assert 'aninvalidkey_01' in provider.blocks['test'].data.keys() +@pytest.mark.dependency(depends=["so3g"]) def test_space_replacement_in_field_names(): """Invalid data field names should get caught by the Feed, however, we check for them in the Aggregator as well. @@ -303,6 +331,7 @@ def test_space_replacement_in_field_names(): assert '_an_invalid_key' in provider.blocks['test'].data.keys() assert 'key2' in provider.blocks['test'].data.keys() +@pytest.mark.dependency(depends=["so3g"]) def test_empty_field_name(): """Invalid data field names should get caught by the Feed, however, we check for them in the Aggregator as well. @@ -323,6 +352,7 @@ def test_empty_field_name(): assert '' not in provider.blocks['test'].data.keys() +@pytest.mark.dependency(depends=["so3g"]) def test_enforced_field_which_becomes_empty(): """Invalid data field names should get caught by the Feed, however, we check for them in the Aggregator as well. @@ -346,6 +376,7 @@ def test_enforced_field_which_becomes_empty(): assert 'invalid_field_123' in provider.blocks['test'].data.keys() +@pytest.mark.dependency(depends=["so3g"]) def test_g3_cast(): correct_tests = [ ([1, 2, 3, 4], core.G3VectorInt), @@ -368,6 +399,7 @@ def test_g3_cast(): g3_cast(x) +@pytest.mark.dependency(depends=["so3g"]) def test_make_filename_directory_creation(tmpdir): """make_filename() should be able to create directories to store the .g3 files in. @@ -379,6 +411,7 @@ def test_make_filename_directory_creation(tmpdir): os.path.isdir(os.path.basename(fname)) +@pytest.mark.dependency(depends=["so3g"]) def test_make_filename_directory_creation_no_subdirs(tmpdir): """make_filename() should raise a FileNotFoundError if make_subdirs is False. @@ -389,6 +422,7 @@ def test_make_filename_directory_creation_no_subdirs(tmpdir): make_filename(test_dir, make_subdirs=False) +@pytest.mark.dependency(depends=["so3g"]) @patch('os.makedirs', side_effect=PermissionError('mocked permission error')) def test_make_filename_directory_creation_permissions(tmpdir): """make_filename() should raise a PermissionError if it runs into one when diff --git a/tests/test_crossbar_integration.py b/tests/test_crossbar_integration.py index 4e2f24a2..927ca380 100644 --- a/tests/test_crossbar_integration.py +++ b/tests/test_crossbar_integration.py @@ -9,13 +9,28 @@ import numpy as np from ocs.matched_client import MatchedClient -from so3g import hk + +try: + from so3g import hk +except ModuleNotFoundError as e: + print(f"Unable to import so3g: {e}") # Set OCS_CONFIG_DIR environment variable os.environ['OCS_CONFIG_DIR'] = os.getcwd() pytest_plugins = ("docker_compose",) +@pytest.mark.dependency(name="so3g") +def test_so3g_spt3g_import(): + """Test that we can import so3g. Used to skip tests dependent on + this import. + + """ + import so3g + + # Just to prevent flake8 from complaining + print(so3g.__file__) + # Fixture to wait for crossbar server to be available. @pytest.fixture(scope="function") def wait_for_crossbar(function_scoped_container_getter): @@ -90,6 +105,7 @@ def test_influxdb_publisher_after_crossbar_restart(wait_for_crossbar): """ pass +@pytest.mark.dependency(depends=["so3g"]) @pytest.mark.integtest def test_aggregator_after_crossbar_restart(wait_for_crossbar): """Test that the aggregator reconnects after a crossbar restart and that