diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b3c828b535..b746bbedb3 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -33,7 +33,7 @@ Added * Continue introducing `pants `_ to improve DX (Developer Experience) working on StackStorm, improve our security posture, and improve CI reliability thanks in part to pants' use of PEX lockfiles. This is not a user-facing addition. - #6118 #6141 #6133 #6120 #6181 #6183 #6200 #6237 #6229 + #6118 #6141 #6133 #6120 #6181 #6183 #6200 #6237 #6229 #6240 Contributed by @cognifloyd * Build of ST2 EL9 packages #6153 Contributed by @amanda11 diff --git a/contrib/runners/python_runner/tests/unit/test_pythonrunner.py b/contrib/runners/python_runner/tests/unit/test_pythonrunner.py index a178bd20ff..22d9e14b36 100644 --- a/contrib/runners/python_runner/tests/unit/test_pythonrunner.py +++ b/contrib/runners/python_runner/tests/unit/test_pythonrunner.py @@ -36,13 +36,15 @@ from st2common.constants.action import LIVEACTION_STATUS_TIMED_OUT from st2common.constants.action import MAX_PARAM_LENGTH from st2common.constants.pack import COMMON_LIB_DIR -from st2common.constants.pack import SYSTEM_PACK_NAME +from st2common.constants.pack import SYSTEM_PACK_NAMES from st2common.persistence.execution import ActionExecutionOutput from python_runner.python_action_wrapper import PythonActionWrapper from st2tests.base import RunnerTestCase from st2tests.base import CleanDbTestCase from st2tests.base import blocking_eventlet_spawn from st2tests.base import make_mock_stream_readline +from st2tests.fixtures.packs.dummy_pack_1.fixture import PACK_NAME as DUMMY_PACK_1 +from st2tests.fixtures.packs.dummy_pack_5.fixture import PACK_NAME as DUMMY_PACK_5 from st2tests.fixtures.packs.dummy_pack_9.fixture import PACK_PATH as DUMMY_PACK_9_PATH from st2tests.fixtures.packs.test_content_version_fixture.fixture import ( PACK_NAME as TEST_CONTENT_VERSION, @@ -100,6 +102,10 @@ MOCK_EXECUTION.id = "598dbf0c0640fd54bffc688b" +# Use DUMMY_PACK_1 instead of depending on everything in the core (SYSTEM_PACK_NAME) pack. +@mock.patch( + "st2common.util.sandboxing.SYSTEM_PACK_NAMES", [DUMMY_PACK_1, *SYSTEM_PACK_NAMES] +) @mock.patch("python_runner.python_runner.sys", mock_sys) class PythonRunnerTestCase(RunnerTestCase, CleanDbTestCase): register_packs = True @@ -229,12 +235,10 @@ def test_simple_action_no_status_backward_compatibility(self): self.assertEqual(output["result"], [1, 2]) def test_simple_action_config_value_provided_overriden_in_datastore(self): - pack = "dummy_pack_5" user = "joe" # No values provided in the datastore - runner = self._get_mock_runner_obj_from_container(pack=pack, user=user) - + runner = self._get_mock_runner_obj_from_container(pack=DUMMY_PACK_5, user=user) self.assertEqual(runner._config["api_key"], "some_api_key") # static value self.assertEqual(runner._config["regions"], ["us-west-1"]) # static value self.assertEqual(runner._config["api_secret"], None) @@ -242,19 +246,19 @@ def test_simple_action_config_value_provided_overriden_in_datastore(self): # api_secret overriden in the datastore (user scoped value) config_service.set_datastore_value_for_config_key( - pack_name="dummy_pack_5", + pack_name=DUMMY_PACK_5, key_name="api_secret", - user="joe", + user=user, value="foosecret", secret=True, ) # private_key_path overriden in the datastore (global / non-user scoped value) config_service.set_datastore_value_for_config_key( - pack_name="dummy_pack_5", key_name="private_key_path", value="foopath" + pack_name=DUMMY_PACK_5, key_name="private_key_path", value="foopath" ) - runner = self._get_mock_runner_obj_from_container(pack=pack, user=user) + runner = self._get_mock_runner_obj_from_container(pack=DUMMY_PACK_5, user=user) self.assertEqual(runner._config["api_key"], "some_api_key") # static value self.assertEqual(runner._config["regions"], ["us-west-1"]) # static value self.assertEqual(runner._config["api_secret"], "foosecret") @@ -603,7 +607,7 @@ def test_pythonpath_env_var_contains_common_libs_config_enabled(self, mock_popen _, call_kwargs = mock_popen.call_args actual_env = call_kwargs["env"] - pack_common_lib_path = "fixtures/packs/core/lib" + pack_common_lib_path = f"fixtures/packs/{DUMMY_PACK_1}/lib" self.assertIn("PYTHONPATH", actual_env) self.assertIn(pack_common_lib_path, actual_env["PYTHONPATH"]) @@ -626,7 +630,7 @@ def test_pythonpath_env_var_not_contains_common_libs_config_disabled( _, call_kwargs = mock_popen.call_args actual_env = call_kwargs["env"] pack_common_lib_path = ( - "/mnt/src/storm/st2/st2tests/st2tests/fixtures/packs/core/lib" + f"/mnt/src/storm/st2/st2tests/st2tests/fixtures/packs/{DUMMY_PACK_1}/lib" ) self.assertIn("PYTHONPATH", actual_env) self.assertNotIn(pack_common_lib_path, actual_env["PYTHONPATH"]) @@ -714,7 +718,7 @@ def test_python_action_wrapper_script_doesnt_get_added_to_sys_path(self): def test_python_action_wrapper_action_script_file_doesnt_exist_friendly_error(self): # File in a directory which is not a Python package wrapper = PythonActionWrapper( - pack="dummy_pack_5", file_path="/tmp/doesnt.exist", user="joe" + pack=DUMMY_PACK_5, file_path="/tmp/doesnt.exist", user="joe" ) expected_msg = ( @@ -724,7 +728,7 @@ def test_python_action_wrapper_action_script_file_doesnt_exist_friendly_error(se # File in a directory which is a Python package wrapper = PythonActionWrapper( - pack="dummy_pack_5", file_path=ACTION_1_PATH, user="joe" + pack=DUMMY_PACK_5, file_path=ACTION_1_PATH, user="joe" ) expected_msg = ( @@ -738,7 +742,7 @@ def test_python_action_wrapper_action_script_file_contains_invalid_syntax_friend self, ): wrapper = PythonActionWrapper( - pack="dummy_pack_5", file_path=ACTION_2_PATH, user="joe" + pack=DUMMY_PACK_5, file_path=ACTION_2_PATH, user="joe" ) expected_msg = ( r'Failed to load action class from file ".*?invalid_syntax.py" ' @@ -994,7 +998,7 @@ def test_content_version_old_git_version(self, mock_run_command): runner.runner_parameters = {"content_version": "v0.10.0"} expected_msg = ( - r'Failed to create git worktree for pack "core": Installed git version ' + rf'Failed to create git worktree for pack "{DUMMY_PACK_1}": Installed git version ' "doesn't support git worktree command. To be able to utilize this " "functionality you need to use git >= 2.5.0." ) @@ -1015,7 +1019,7 @@ def test_content_version_pack_repo_not_git_repository(self, mock_run_command): runner.runner_parameters = {"content_version": "v0.10.0"} expected_msg = ( - r'Failed to create git worktree for pack "core": Pack directory ' + rf'Failed to create git worktree for pack "{DUMMY_PACK_1}": Pack directory ' '".*" is not a ' "git repository. To utilize this functionality, pack directory needs to " "be a git repository." @@ -1036,7 +1040,7 @@ def test_content_version_invalid_git_revision(self, mock_run_command): runner.runner_parameters = {"content_version": "vinvalid"} expected_msg = ( - r'Failed to create git worktree for pack "core": Invalid content_version ' + rf'Failed to create git worktree for pack "{DUMMY_PACK_1}": Invalid content_version ' '"vinvalid" provided. Make sure that git repository is up ' "to date and contains that revision." ) @@ -1052,7 +1056,9 @@ def test_missing_config_item_user_friendly_error(self): self.assertIsNotNone(output) self.assertIn("{}", output["stdout"]) self.assertIn("default_value", output["stdout"]) - self.assertIn('Config for pack "core" is missing key "key"', output["stderr"]) + self.assertIn( + f'Config for pack "{DUMMY_PACK_1}" is missing key "key"', output["stderr"] + ) self.assertIn( 'make sure you run "st2ctl reload --register-configs"', output["stderr"] ) @@ -1107,7 +1113,7 @@ def _get_mock_action_obj(self): """ action = mock.Mock() action.ref = "dummy.action" - action.pack = SYSTEM_PACK_NAME + action.pack = DUMMY_PACK_1 action.entry_point = "foo.py" action.runner_type = {"name": "python-script"} return action diff --git a/st2api/tests/unit/controllers/v1/test_packs.py b/st2api/tests/unit/controllers/v1/test_packs.py index c665b7d062..a238ed0f66 100644 --- a/st2api/tests/unit/controllers/v1/test_packs.py +++ b/st2api/tests/unit/controllers/v1/test_packs.py @@ -34,6 +34,9 @@ PACK_NAME as DUMMY_PACK_1, PACK_PATH as DUMMY_PACK_1_PATH, ) +from st2tests.fixtures.packs.dummy_pack_2.fixture import ( + PACK_NAME as DUMMY_PACK_2, +) from st2tests.fixtures.packs.dummy_pack_10.fixture import ( PACK_DIR_NAME as DUMMY_PACK_10, PACK_PATH as DUMMY_PACK_10_PATH, @@ -589,7 +592,7 @@ def test_packs_register_endpoint(self, mock_get_packs): resp = self.app.post_json( "/v1/packs/register", { - "packs": ["dummy_pack_2"], + "packs": [DUMMY_PACK_2], "fail_on_failure": False, "types": ["policies"], }, diff --git a/st2api/tests/unit/controllers/v1/test_packs_views.py b/st2api/tests/unit/controllers/v1/test_packs_views.py index e2e3f93783..97381e5e34 100644 --- a/st2api/tests/unit/controllers/v1/test_packs_views.py +++ b/st2api/tests/unit/controllers/v1/test_packs_views.py @@ -20,6 +20,13 @@ from st2common.persistence.pack import Pack from st2tests.api import FunctionalTest +from st2tests.fixtures.packs.dummy_pack_1.fixture import ( + PACK_NAME as DUMMY_PACK_1, +) +from st2tests.fixtures.packs.dummy_pack_16.fixture import ( + PACK_NAME as DUMMY_PACK_16, +) + @mock.patch("st2common.bootstrap.base.REGISTERED_PACKS_CACHE", {}) class PacksViewsControllerTestCase(FunctionalTest): @@ -31,7 +38,7 @@ def setUpClass(cls): actions_registrar.register_actions(use_pack_cache=False) def test_get_pack_files_success(self): - resp = self.app.get("/v1/packs/views/files/dummy_pack_1") + resp = self.app.get(f"/v1/packs/views/files/{DUMMY_PACK_1}") self.assertEqual(resp.status_int, http_client.OK) self.assertTrue(len(resp.json) > 1) item = [_item for _item in resp.json if _item["file_path"] == "pack.yaml"][0] @@ -53,12 +60,12 @@ def test_get_pack_files_binary_files_are_excluded(self): "etc/generate_new_token.png", ] - pack_db = Pack.get_by_ref("dummy_pack_1") + pack_db = Pack.get_by_ref(DUMMY_PACK_1) all_files_count = len(pack_db.files) non_binary_files_count = all_files_count - len(binary_files) - resp = self.app.get("/v1/packs/views/files/dummy_pack_1") + resp = self.app.get(f"/v1/packs/views/files/{DUMMY_PACK_1}") self.assertEqual(resp.status_int, http_client.OK) self.assertEqual(len(resp.json), non_binary_files_count) @@ -71,7 +78,7 @@ def test_get_pack_files_binary_files_are_excluded(self): self.assertFalse(item) def test_get_pack_file_success(self): - resp = self.app.get("/v1/packs/views/file/dummy_pack_1/pack.yaml") + resp = self.app.get(f"/v1/packs/views/file/{DUMMY_PACK_1}/pack.yaml") self.assertEqual(resp.status_int, http_client.OK) self.assertIn(b"name : dummy_pack_1", resp.body) @@ -84,46 +91,46 @@ def test_get_pack_file_pack_doesnt_exist(self): @mock.patch("st2api.controllers.v1.pack_views.MAX_FILE_SIZE", 1) def test_pack_file_file_larger_then_maximum_size(self): resp = self.app.get( - "/v1/packs/views/file/dummy_pack_1/pack.yaml", expect_errors=True + f"/v1/packs/views/file/{DUMMY_PACK_1}/pack.yaml", expect_errors=True ) self.assertEqual(resp.status_int, http_client.BAD_REQUEST) self.assertIn("File pack.yaml exceeds maximum allowed file size", resp) def test_headers_get_pack_file(self): - resp = self.app.get("/v1/packs/views/file/dummy_pack_1/pack.yaml") + resp = self.app.get(f"/v1/packs/views/file/{DUMMY_PACK_1}/pack.yaml") self.assertEqual(resp.status_int, http_client.OK) self.assertIn(b"name : dummy_pack_1", resp.body) self.assertIsNotNone(resp.headers["ETag"]) self.assertIsNotNone(resp.headers["Last-Modified"]) def test_no_change_get_pack_file(self): - resp = self.app.get("/v1/packs/views/file/dummy_pack_1/pack.yaml") + resp = self.app.get(f"/v1/packs/views/file/{DUMMY_PACK_1}/pack.yaml") self.assertEqual(resp.status_int, http_client.OK) self.assertIn(b"name : dummy_pack_1", resp.body) # Confirm NOT_MODIFIED resp = self.app.get( - "/v1/packs/views/file/dummy_pack_1/pack.yaml", + f"/v1/packs/views/file/{DUMMY_PACK_1}/pack.yaml", headers={"If-None-Match": resp.headers["ETag"]}, ) self.assertEqual(resp.status_code, http_client.NOT_MODIFIED) resp = self.app.get( - "/v1/packs/views/file/dummy_pack_1/pack.yaml", + f"/v1/packs/views/file/{DUMMY_PACK_1}/pack.yaml", headers={"If-Modified-Since": resp.headers["Last-Modified"]}, ) self.assertEqual(resp.status_code, http_client.NOT_MODIFIED) # Confirm value is returned if header do not match resp = self.app.get( - "/v1/packs/views/file/dummy_pack_1/pack.yaml", + f"/v1/packs/views/file/{DUMMY_PACK_1}/pack.yaml", headers={"If-None-Match": "ETAG"}, ) self.assertEqual(resp.status_code, http_client.OK) self.assertIn(b"name : dummy_pack_1", resp.body) resp = self.app.get( - "/v1/packs/views/file/dummy_pack_1/pack.yaml", + f"/v1/packs/views/file/{DUMMY_PACK_1}/pack.yaml", headers={"If-Modified-Since": "Last-Modified"}, ) self.assertEqual(resp.status_code, http_client.OK) @@ -131,11 +138,13 @@ def test_no_change_get_pack_file(self): def test_get_pack_files_and_pack_file_ref_doesnt_equal_pack_name(self): # Ref is not equal to the name, controller should still work - resp = self.app.get("/v1/packs/views/files/dummy_pack_16") + resp = self.app.get(f"/v1/packs/views/files/{DUMMY_PACK_16}") self.assertEqual(resp.status_int, http_client.OK) - self.assertEqual(len(resp.json), 4) + # 4 if running in workspace (BUILD file present) + # 3 if pants is running it (no BUILD file present) + self.assertIn(len(resp.json), [4, 3]) self.assertIn("pack.yaml", [f["file_path"] for f in resp.json]) - resp = self.app.get("/v1/packs/views/file/dummy_pack_16/pack.yaml") + resp = self.app.get(f"/v1/packs/views/file/{DUMMY_PACK_16}/pack.yaml") self.assertEqual(resp.status_int, http_client.OK) self.assertIn(b"ref: dummy_pack_16", resp.body) diff --git a/st2api/tests/unit/controllers/v1/test_sensortypes.py b/st2api/tests/unit/controllers/v1/test_sensortypes.py index c59a1c28e2..ea32f0e904 100644 --- a/st2api/tests/unit/controllers/v1/test_sensortypes.py +++ b/st2api/tests/unit/controllers/v1/test_sensortypes.py @@ -23,6 +23,10 @@ from st2tests.api import FunctionalTest from st2tests.api import APIControllerWithIncludeAndExcludeFilterTestCase +from st2tests.fixtures.packs.dummy_pack_1.fixture import ( + PACK_NAME as DUMMY_PACK_1, +) + http_client = six.moves.http_client __all__ = ["SensorTypeControllerTestCase"] @@ -75,7 +79,7 @@ def test_get_all_filters(self): resp = self.app.get("/v1/sensortypes?name=SampleSensor2") self.assertEqual(len(resp.json), 1) self.assertEqual(resp.json[0]["name"], "SampleSensor2") - self.assertEqual(resp.json[0]["ref"], "dummy_pack_1.SampleSensor2") + self.assertEqual(resp.json[0]["ref"], f"{DUMMY_PACK_1}.SampleSensor2") resp = self.app.get("/v1/sensortypes?name=SampleSensor3") self.assertEqual(len(resp.json), 1) @@ -85,7 +89,7 @@ def test_get_all_filters(self): resp = self.app.get("/v1/sensortypes?pack=foobar") self.assertEqual(len(resp.json), 0) - resp = self.app.get("/v1/sensortypes?pack=dummy_pack_1") + resp = self.app.get(f"/v1/sensortypes?pack={DUMMY_PACK_1}") self.assertEqual(len(resp.json), 3) # ?enabled filter @@ -99,20 +103,20 @@ def test_get_all_filters(self): self.assertEqual(resp.json[1]["enabled"], True) # ?trigger filter - resp = self.app.get("/v1/sensortypes?trigger=dummy_pack_1.event3") + resp = self.app.get(f"/v1/sensortypes?trigger={DUMMY_PACK_1}.event3") self.assertEqual(len(resp.json), 1) - self.assertEqual(resp.json[0]["trigger_types"], ["dummy_pack_1.event3"]) + self.assertEqual(resp.json[0]["trigger_types"], [f"{DUMMY_PACK_1}.event3"]) - resp = self.app.get("/v1/sensortypes?trigger=dummy_pack_1.event") + resp = self.app.get(f"/v1/sensortypes?trigger={DUMMY_PACK_1}.event") self.assertEqual(len(resp.json), 2) - self.assertEqual(resp.json[0]["trigger_types"], ["dummy_pack_1.event"]) - self.assertEqual(resp.json[1]["trigger_types"], ["dummy_pack_1.event"]) + self.assertEqual(resp.json[0]["trigger_types"], [f"{DUMMY_PACK_1}.event"]) + self.assertEqual(resp.json[1]["trigger_types"], [f"{DUMMY_PACK_1}.event"]) def test_get_one_success(self): - resp = self.app.get("/v1/sensortypes/dummy_pack_1.SampleSensor") + resp = self.app.get(f"/v1/sensortypes/{DUMMY_PACK_1}.SampleSensor") self.assertEqual(resp.status_int, http_client.OK) self.assertEqual(resp.json["name"], "SampleSensor") - self.assertEqual(resp.json["ref"], "dummy_pack_1.SampleSensor") + self.assertEqual(resp.json["ref"], f"{DUMMY_PACK_1}.SampleSensor") def test_get_one_doesnt_exist(self): resp = self.app.get("/v1/sensortypes/1", expect_errors=True) @@ -120,7 +124,7 @@ def test_get_one_doesnt_exist(self): def test_disable_and_enable_sensor(self): # Verify initial state - resp = self.app.get("/v1/sensortypes/dummy_pack_1.SampleSensor") + resp = self.app.get(f"/v1/sensortypes/{DUMMY_PACK_1}.SampleSensor") self.assertEqual(resp.status_int, http_client.OK) self.assertTrue(resp.json["enabled"]) @@ -129,24 +133,28 @@ def test_disable_and_enable_sensor(self): # Disable sensor data = copy.deepcopy(sensor_data) data["enabled"] = False - put_resp = self.app.put_json("/v1/sensortypes/dummy_pack_1.SampleSensor", data) + put_resp = self.app.put_json( + f"/v1/sensortypes/{DUMMY_PACK_1}.SampleSensor", data + ) self.assertEqual(put_resp.status_int, http_client.OK) - self.assertEqual(put_resp.json["ref"], "dummy_pack_1.SampleSensor") + self.assertEqual(put_resp.json["ref"], f"{DUMMY_PACK_1}.SampleSensor") self.assertFalse(put_resp.json["enabled"]) # Verify sensor has been disabled - resp = self.app.get("/v1/sensortypes/dummy_pack_1.SampleSensor") + resp = self.app.get(f"/v1/sensortypes/{DUMMY_PACK_1}.SampleSensor") self.assertEqual(resp.status_int, http_client.OK) self.assertFalse(resp.json["enabled"]) # Enable sensor data = copy.deepcopy(sensor_data) data["enabled"] = True - put_resp = self.app.put_json("/v1/sensortypes/dummy_pack_1.SampleSensor", data) + put_resp = self.app.put_json( + f"/v1/sensortypes/{DUMMY_PACK_1}.SampleSensor", data + ) self.assertEqual(put_resp.status_int, http_client.OK) self.assertTrue(put_resp.json["enabled"]) # Verify sensor has been enabled - resp = self.app.get("/v1/sensortypes/dummy_pack_1.SampleSensor") + resp = self.app.get(f"/v1/sensortypes/{DUMMY_PACK_1}.SampleSensor") self.assertEqual(resp.status_int, http_client.OK) self.assertTrue(resp.json["enabled"]) diff --git a/st2common/st2common/content/loader.py b/st2common/st2common/content/loader.py index 7e57ef6ec0..582834a45d 100644 --- a/st2common/st2common/content/loader.py +++ b/st2common/st2common/content/loader.py @@ -149,6 +149,8 @@ def get_content_from_pack(self, pack_dir, content_type): def _get_packs_from_dir(self, base_dir): result = {} for pack_name in os.listdir(base_dir): + if pack_name == "__pycache__": + continue pack_dir = os.path.join(base_dir, pack_name) pack_manifest_file = os.path.join(pack_dir, MANIFEST_FILE_NAME) @@ -160,6 +162,8 @@ def _get_packs_from_dir(self, base_dir): def _get_content_from_dir(self, base_dir, content_type): content = {} for pack in os.listdir(base_dir): + if pack == "__pycache__": + continue # TODO: Use function from util which escapes the name pack_dir = os.path.join(base_dir, pack) diff --git a/st2common/tests/resources/BUILD b/st2common/tests/resources/BUILD new file mode 100644 index 0000000000..a514672a5c --- /dev/null +++ b/st2common/tests/resources/BUILD @@ -0,0 +1,8 @@ +resource( + name="logging", + source="logging.conf", +) + +python_sources( + dependencies=[":logging"], +) diff --git a/st2common/tests/resources/fixture.py b/st2common/tests/resources/fixture.py new file mode 100644 index 0000000000..f6d0d3e940 --- /dev/null +++ b/st2common/tests/resources/fixture.py @@ -0,0 +1,16 @@ +# Copyright 2024 The StackStorm Authors. +# +# 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 st2tests import fixturesloader + +FIXTURE_NAME, FIXTURE_PATH = fixturesloader.get_fixture_name_and_path(__file__) diff --git a/st2common/tests/resources/loadableplugin/BUILD b/st2common/tests/resources/loadableplugin/BUILD new file mode 100644 index 0000000000..bd7354bb91 --- /dev/null +++ b/st2common/tests/resources/loadableplugin/BUILD @@ -0,0 +1,11 @@ +resources( + name="metadata", + sources=["*.yaml"], +) + +python_sources( + dependencies=[ + ":metadata", + "./plugin", + ], +) diff --git a/st2common/tests/resources/loadableplugin/fixture.py b/st2common/tests/resources/loadableplugin/fixture.py new file mode 100644 index 0000000000..f6d0d3e940 --- /dev/null +++ b/st2common/tests/resources/loadableplugin/fixture.py @@ -0,0 +1,16 @@ +# Copyright 2024 The StackStorm Authors. +# +# 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 st2tests import fixturesloader + +FIXTURE_NAME, FIXTURE_PATH = fixturesloader.get_fixture_name_and_path(__file__) diff --git a/st2common/tests/resources/packs/BUILD b/st2common/tests/resources/packs/BUILD new file mode 100644 index 0000000000..8280f255bd --- /dev/null +++ b/st2common/tests/resources/packs/BUILD @@ -0,0 +1,8 @@ +resources( + name="packs_directories", + sources=["**/.gitignore"], +) + +python_sources( + dependencies=[":packs_directories"], +) diff --git a/st2common/tests/resources/packs/fixture.py b/st2common/tests/resources/packs/fixture.py new file mode 100644 index 0000000000..995f0ea33f --- /dev/null +++ b/st2common/tests/resources/packs/fixture.py @@ -0,0 +1,16 @@ +# Copyright 2024 The StackStorm Authors. +# +# 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 st2tests import fixturesloader + +_, PACKS_BASE_PATH = fixturesloader.get_fixture_name_and_path(__file__) diff --git a/st2common/tests/resources/packs2/BUILD b/st2common/tests/resources/packs2/BUILD new file mode 100644 index 0000000000..8280f255bd --- /dev/null +++ b/st2common/tests/resources/packs2/BUILD @@ -0,0 +1,8 @@ +resources( + name="packs_directories", + sources=["**/.gitignore"], +) + +python_sources( + dependencies=[":packs_directories"], +) diff --git a/st2common/tests/resources/packs2/fixture.py b/st2common/tests/resources/packs2/fixture.py new file mode 100644 index 0000000000..995f0ea33f --- /dev/null +++ b/st2common/tests/resources/packs2/fixture.py @@ -0,0 +1,16 @@ +# Copyright 2024 The StackStorm Authors. +# +# 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 st2tests import fixturesloader + +_, PACKS_BASE_PATH = fixturesloader.get_fixture_name_and_path(__file__) diff --git a/st2common/tests/resources/packs3/BUILD b/st2common/tests/resources/packs3/BUILD new file mode 100644 index 0000000000..eaed03e50e --- /dev/null +++ b/st2common/tests/resources/packs3/BUILD @@ -0,0 +1,8 @@ +resources( + name="packs_overrides", + sources=["**/*.yaml"], +) + +python_sources( + dependencies=[":packs_overrides"], +) diff --git a/st2common/tests/resources/packs3/fixture.py b/st2common/tests/resources/packs3/fixture.py new file mode 100644 index 0000000000..995f0ea33f --- /dev/null +++ b/st2common/tests/resources/packs3/fixture.py @@ -0,0 +1,16 @@ +# Copyright 2024 The StackStorm Authors. +# +# 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 st2tests import fixturesloader + +_, PACKS_BASE_PATH = fixturesloader.get_fixture_name_and_path(__file__) diff --git a/st2common/tests/resources/overrides/_global.yaml b/st2common/tests/resources/packs3/overrides/_global.yaml similarity index 100% rename from st2common/tests/resources/overrides/_global.yaml rename to st2common/tests/resources/packs3/overrides/_global.yaml diff --git a/st2common/tests/resources/overrides/overpack1.yaml b/st2common/tests/resources/packs3/overrides/overpack1.yaml similarity index 100% rename from st2common/tests/resources/overrides/overpack1.yaml rename to st2common/tests/resources/packs3/overrides/overpack1.yaml diff --git a/st2common/tests/resources/overrides/overpack2.yaml b/st2common/tests/resources/packs3/overrides/overpack2.yaml similarity index 100% rename from st2common/tests/resources/overrides/overpack2.yaml rename to st2common/tests/resources/packs3/overrides/overpack2.yaml diff --git a/st2common/tests/resources/overrides/overpack3.yaml b/st2common/tests/resources/packs3/overrides/overpack3.yaml similarity index 100% rename from st2common/tests/resources/overrides/overpack3.yaml rename to st2common/tests/resources/packs3/overrides/overpack3.yaml diff --git a/st2common/tests/resources/overrides/overpack4.yaml b/st2common/tests/resources/packs3/overrides/overpack4.yaml similarity index 100% rename from st2common/tests/resources/overrides/overpack4.yaml rename to st2common/tests/resources/packs3/overrides/overpack4.yaml diff --git a/st2common/tests/unit/test_content_loader.py b/st2common/tests/unit/test_content_loader.py index 6edba192d4..700cd19d30 100644 --- a/st2common/tests/unit/test_content_loader.py +++ b/st2common/tests/unit/test_content_loader.py @@ -37,39 +37,36 @@ from st2common.constants.meta import yaml_safe_load from st2tests import config -CURRENT_DIR = os.path.dirname(os.path.realpath(__file__)) -RESOURCES_DIR = os.path.abspath(os.path.join(CURRENT_DIR, "../resources")) +from tests.resources.packs.fixture import PACKS_BASE_PATH as PACKS_BASE_PATH_1 +from tests.resources.packs2.fixture import PACKS_BASE_PATH as PACKS_BASE_PATH_2 +from tests.resources.packs3.fixture import PACKS_BASE_PATH as PACKS_BASE_PATH_3 class ContentLoaderTest(unittest.TestCase): def test_get_sensors(self): - packs_base_path = os.path.join(RESOURCES_DIR, "packs/") loader = ContentPackLoader() pack_sensors = loader.get_content( - base_dirs=[packs_base_path], content_type="sensors" + base_dirs=[PACKS_BASE_PATH_1], content_type="sensors" ) self.assertIsNotNone(pack_sensors.get("pack1", None)) def test_get_sensors_pack_missing_sensors(self): loader = ContentPackLoader() - fail_pack_path = os.path.join(RESOURCES_DIR, "packs/pack2") + fail_pack_path = os.path.join(PACKS_BASE_PATH_1, "pack2") self.assertTrue(os.path.exists(fail_pack_path)) self.assertEqual(loader._get_sensors(fail_pack_path), None) def test_invalid_content_type(self): - packs_base_path = os.path.join(RESOURCES_DIR, "packs/") loader = ContentPackLoader() self.assertRaises( ValueError, loader.get_content, - base_dirs=[packs_base_path], + base_dirs=[PACKS_BASE_PATH_1], content_type="stuff", ) def test_get_content_multiple_directories(self): - packs_base_path_1 = os.path.join(RESOURCES_DIR, "packs/") - packs_base_path_2 = os.path.join(RESOURCES_DIR, "packs2/") - base_dirs = [packs_base_path_1, packs_base_path_2] + base_dirs = [PACKS_BASE_PATH_1, PACKS_BASE_PATH_2] LOG.warning = Mock() @@ -81,14 +78,14 @@ def test_get_content_multiple_directories(self): # Assert that a warning is emitted when a duplicated pack is found expected_msg = ( 'Pack "pack1" already found in ' - '"%s/packs/", ignoring content from ' - '"%s/packs2/"' % (RESOURCES_DIR, RESOURCES_DIR) + f'"{PACKS_BASE_PATH_1}", ignoring content from ' + f'"{PACKS_BASE_PATH_2}"' ) LOG.warning.assert_called_once_with(expected_msg) def test_get_content_from_pack_success(self): loader = ContentPackLoader() - pack_path = os.path.join(RESOURCES_DIR, "packs/pack1") + pack_path = os.path.join(PACKS_BASE_PATH_1, "pack1") sensors = loader.get_content_from_pack( pack_dir=pack_path, content_type="sensors" @@ -97,7 +94,7 @@ def test_get_content_from_pack_success(self): def test_get_content_from_pack_directory_doesnt_exist(self): loader = ContentPackLoader() - pack_path = os.path.join(RESOURCES_DIR, "packs/pack100") + pack_path = os.path.join(PACKS_BASE_PATH_1, "pack100") message_regex = "Directory .*? doesn't exist" self.assertRaisesRegex( @@ -110,7 +107,7 @@ def test_get_content_from_pack_directory_doesnt_exist(self): def test_get_content_from_pack_no_sensors(self): loader = ContentPackLoader() - pack_path = os.path.join(RESOURCES_DIR, "packs/pack2") + pack_path = os.path.join(PACKS_BASE_PATH_1, "pack2") result = loader.get_content_from_pack( pack_dir=pack_path, content_type="sensors" @@ -119,7 +116,9 @@ def test_get_content_from_pack_no_sensors(self): def test_get_override_action_from_default(self): config.parse_args() - cfg.CONF.set_override(name="base_path", override=RESOURCES_DIR, group="system") + cfg.CONF.set_override( + name="base_path", override=PACKS_BASE_PATH_3, group="system" + ) loader = OverrideLoader() content = {"name": "action1", "enabled": True} self.assertTrue(loader.override("overpack1", "actions", content)) @@ -130,7 +129,9 @@ def test_get_override_action_from_default(self): def test_get_override_action_from_exception(self): config.parse_args() - cfg.CONF.set_override(name="base_path", override=RESOURCES_DIR, group="system") + cfg.CONF.set_override( + name="base_path", override=PACKS_BASE_PATH_3, group="system" + ) loader = OverrideLoader() content = {"name": "action2", "enabled": True} self.assertFalse(loader.override("overpack1", "actions", content)) @@ -141,7 +142,9 @@ def test_get_override_action_from_exception(self): def test_get_override_action_from_default_no_exceptions(self): config.parse_args() - cfg.CONF.set_override(name="base_path", override=RESOURCES_DIR, group="system") + cfg.CONF.set_override( + name="base_path", override=PACKS_BASE_PATH_3, group="system" + ) loader = OverrideLoader() content = {"name": "action1", "enabled": True} self.assertTrue(loader.override("overpack4", "actions", content)) @@ -152,7 +155,9 @@ def test_get_override_action_from_default_no_exceptions(self): def test_get_override_action_from_global_default_no_exceptions(self): config.parse_args() - cfg.CONF.set_override(name="base_path", override=RESOURCES_DIR, group="system") + cfg.CONF.set_override( + name="base_path", override=PACKS_BASE_PATH_3, group="system" + ) loader = OverrideLoader() content = {"class_name": "sensor1", "enabled": True} self.assertTrue(loader.override("overpack1", "sensors", content)) @@ -160,7 +165,9 @@ def test_get_override_action_from_global_default_no_exceptions(self): def test_get_override_action_from_global_overridden_by_pack(self): config.parse_args() - cfg.CONF.set_override(name="base_path", override=RESOURCES_DIR, group="system") + cfg.CONF.set_override( + name="base_path", override=PACKS_BASE_PATH_3, group="system" + ) loader = OverrideLoader() content = {"class_name": "sensor1", "enabled": True} self.assertFalse(loader.override("overpack2", "sensors", content)) @@ -168,7 +175,9 @@ def test_get_override_action_from_global_overridden_by_pack(self): def test_get_override_action_from_global_overridden_by_pack_exception(self): config.parse_args() - cfg.CONF.set_override(name="base_path", override=RESOURCES_DIR, group="system") + cfg.CONF.set_override( + name="base_path", override=PACKS_BASE_PATH_3, group="system" + ) loader = OverrideLoader() content = {"class_name": "sensor1", "enabled": True} self.assertFalse(loader.override("overpack3", "sensors", content)) @@ -176,7 +185,9 @@ def test_get_override_action_from_global_overridden_by_pack_exception(self): def test_get_override_invalid_type(self): config.parse_args() - cfg.CONF.set_override(name="base_path", override=RESOURCES_DIR, group="system") + cfg.CONF.set_override( + name="base_path", override=PACKS_BASE_PATH_3, group="system" + ) loader = OverrideLoader() content = {"name": "action2", "enabled": True} self.assertRaises( @@ -189,7 +200,9 @@ def test_get_override_invalid_type(self): def test_get_override_invalid_default_key(self): config.parse_args() - cfg.CONF.set_override(name="base_path", override=RESOURCES_DIR, group="system") + cfg.CONF.set_override( + name="base_path", override=PACKS_BASE_PATH_3, group="system" + ) loader = OverrideLoader() content = {"name": "action1", "enabled": True} self.assertRaises( @@ -202,7 +215,9 @@ def test_get_override_invalid_default_key(self): def test_get_override_invalid_exceptions_key(self): config.parse_args() - cfg.CONF.set_override(name="base_path", override=RESOURCES_DIR, group="system") + cfg.CONF.set_override( + name="base_path", override=PACKS_BASE_PATH_3, group="system" + ) loader = OverrideLoader() content = {"name": "action1", "enabled": True} loader.override("overpack1", "actions", content) diff --git a/st2common/tests/unit/test_logger.py b/st2common/tests/unit/test_logger.py index e2126208eb..bd43be9f96 100644 --- a/st2common/tests/unit/test_logger.py +++ b/st2common/tests/unit/test_logger.py @@ -35,9 +35,9 @@ from st2common.models.db.execution import ActionExecutionDB import st2tests.config as tests_config -CURRENT_DIR = os.path.dirname(os.path.realpath(__file__)) -RESOURCES_DIR = os.path.abspath(os.path.join(CURRENT_DIR, "../resources")) -CONFIG_FILE_PATH = os.path.join(RESOURCES_DIR, "logging.conf") +from tests.resources.fixture import FIXTURE_PATH + +CONFIG_FILE_PATH = os.path.join(FIXTURE_PATH, "logging.conf") MOCK_MASKED_ATTRIBUTES_BLACKLIST = [ "blacklisted_1", diff --git a/st2common/tests/unit/test_plugin_loader.py b/st2common/tests/unit/test_plugin_loader.py index e5a2822406..8e594ecb95 100644 --- a/st2common/tests/unit/test_plugin_loader.py +++ b/st2common/tests/unit/test_plugin_loader.py @@ -24,9 +24,7 @@ import st2common.util.loader as plugin_loader -PLUGIN_FOLDER = "loadableplugin" -SRC_RELATIVE = os.path.join("../resources", PLUGIN_FOLDER) -SRC_ROOT = os.path.join(os.path.abspath(os.path.dirname(__file__)), SRC_RELATIVE) +from tests.resources.loadableplugin.fixture import FIXTURE_PATH as SRC_ROOT class LoaderTest(unittest.TestCase): diff --git a/st2reactor/tests/resources/BUILD b/st2reactor/tests/resources/BUILD index 57341b1358..4cb4ff555e 100644 --- a/st2reactor/tests/resources/BUILD +++ b/st2reactor/tests/resources/BUILD @@ -1,3 +1,10 @@ -python_tests( - name="tests", +python_sources( + name="fixture_sensors", + # Override the default sources to include test_sensor*.py + # which are fixtures, not actual test files. + sources=["test_sensor*.py"], +) + +python_sources( + dependencies=[":fixture_sensors"], ) diff --git a/st2reactor/tests/resources/fixture.py b/st2reactor/tests/resources/fixture.py new file mode 100644 index 0000000000..f6d0d3e940 --- /dev/null +++ b/st2reactor/tests/resources/fixture.py @@ -0,0 +1,16 @@ +# Copyright 2024 The StackStorm Authors. +# +# 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 st2tests import fixturesloader + +FIXTURE_NAME, FIXTURE_PATH = fixturesloader.get_fixture_name_and_path(__file__) diff --git a/st2reactor/tests/unit/test_sensor_wrapper.py b/st2reactor/tests/unit/test_sensor_wrapper.py index 3a9d3b9ced..36b8c04f10 100644 --- a/st2reactor/tests/unit/test_sensor_wrapper.py +++ b/st2reactor/tests/unit/test_sensor_wrapper.py @@ -33,8 +33,7 @@ from st2reactor.container.sensor_wrapper import SensorWrapper from st2reactor.sensor.base import Sensor, PollingSensor -CURRENT_DIR = os.path.abspath(os.path.dirname(__file__)) -RESOURCES_DIR = os.path.abspath(os.path.join(CURRENT_DIR, "../resources")) +from tests.resources.fixture import FIXTURE_PATH as RESOURCES_DIR __all__ = ["SensorWrapperTestCase"]