Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pants: Use python imports to identify fixtures #6240

Merged
merged 13 commits into from
Sep 16, 2024
2 changes: 1 addition & 1 deletion CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Added
* Continue introducing `pants <https://www.pantsbuild.org/docs>`_ 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
Expand Down
42 changes: 24 additions & 18 deletions contrib/runners/python_runner/tests/unit/test_pythonrunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -229,32 +235,30 @@ 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)
self.assertEqual(runner._config["private_key_path"], None)

# 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")
Expand Down Expand Up @@ -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"])

Expand All @@ -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"])
Expand Down Expand Up @@ -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 = (
Expand All @@ -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 = (
Expand All @@ -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" '
Expand Down Expand Up @@ -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."
)
Expand All @@ -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."
Expand All @@ -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."
)
Expand All @@ -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"]
)
Expand Down Expand Up @@ -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
5 changes: 4 additions & 1 deletion st2api/tests/unit/controllers/v1/test_packs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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"],
},
Expand Down
37 changes: 23 additions & 14 deletions st2api/tests/unit/controllers/v1/test_packs_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand All @@ -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]
Expand All @@ -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)

Expand All @@ -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)

Expand All @@ -84,58 +91,60 @@ 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)
self.assertIn(b"name : dummy_pack_1", resp.body)

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)
Loading
Loading