Skip to content

Commit 33efbef

Browse files
authored
Merge branch 'main' into fix/scenario-plugins-and-utils
2 parents 5571b43 + 71bd34b commit 33efbef

File tree

2 files changed

+97
-9
lines changed

2 files changed

+97
-9
lines changed

krkn/scenario_plugins/abstract_scenario_plugin.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
import os
23
import time
34
from abc import ABC, abstractmethod
45
from krkn_lib.models.telemetry import ScenarioTelemetry
@@ -86,6 +87,16 @@ def run_scenarios(
8687
scenario_telemetry.scenario = scenario_config
8788
scenario_telemetry.scenario_type = self.get_scenario_types()[0]
8889
scenario_telemetry.start_timestamp = time.time()
90+
if not os.path.exists(scenario_config):
91+
logging.error(
92+
f"scenario file not found: '{scenario_config}' -- "
93+
f"check that the path is correct relative to the working directory: {os.getcwd()}"
94+
)
95+
failed_scenarios.append(scenario_config)
96+
scenario_telemetry.exit_status = 1
97+
scenario_telemetry.end_timestamp = time.time()
98+
scenario_telemetries.append(scenario_telemetry)
99+
continue
89100
parsed_scenario_config = telemetry.set_parameters_base64(
90101
scenario_telemetry, scenario_config
91102
)

tests/test_abstract_scenario_plugin_cerberus.py

Lines changed: 86 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,10 @@ def setUp(self):
6666
@patch('krkn.scenario_plugins.abstract_scenario_plugin.cleanup_rollback_version_files')
6767
@patch('krkn.scenario_plugins.abstract_scenario_plugin.utils.collect_and_put_ocp_logs')
6868
@patch('krkn.scenario_plugins.abstract_scenario_plugin.signal_handler.signal_context')
69+
@patch('krkn.scenario_plugins.abstract_scenario_plugin.os.path.exists', return_value=True)
6970
@patch('time.sleep')
7071
def test_cerberus_publish_called_after_successful_scenario(
71-
self, mock_sleep, mock_signal_ctx, mock_collect_logs, mock_cleanup, mock_cerberus_publish
72+
self, mock_sleep, mock_exists, mock_signal_ctx, mock_collect_logs, mock_cleanup, mock_cerberus_publish
7273
):
7374
"""Test that cerberus.publish_kraken_status is called after a successful scenario"""
7475
mock_signal_ctx.return_value.__enter__ = Mock()
@@ -97,9 +98,10 @@ def test_cerberus_publish_called_after_successful_scenario(
9798
@patch('krkn.scenario_plugins.abstract_scenario_plugin.execute_rollback_version_files')
9899
@patch('krkn.scenario_plugins.abstract_scenario_plugin.utils.collect_and_put_ocp_logs')
99100
@patch('krkn.scenario_plugins.abstract_scenario_plugin.signal_handler.signal_context')
101+
@patch('krkn.scenario_plugins.abstract_scenario_plugin.os.path.exists', return_value=True)
100102
@patch('time.sleep')
101103
def test_cerberus_publish_called_after_failed_scenario(
102-
self, mock_sleep, mock_signal_ctx, mock_collect_logs, mock_rollback, mock_cerberus_publish
104+
self, mock_sleep, mock_exists, mock_signal_ctx, mock_collect_logs, mock_rollback, mock_cerberus_publish
103105
):
104106
"""Test that cerberus.publish_kraken_status is called even after a failed scenario"""
105107
mock_signal_ctx.return_value.__enter__ = Mock()
@@ -122,9 +124,10 @@ def test_cerberus_publish_called_after_failed_scenario(
122124
@patch('krkn.scenario_plugins.abstract_scenario_plugin.cleanup_rollback_version_files')
123125
@patch('krkn.scenario_plugins.abstract_scenario_plugin.utils.collect_and_put_ocp_logs')
124126
@patch('krkn.scenario_plugins.abstract_scenario_plugin.signal_handler.signal_context')
127+
@patch('krkn.scenario_plugins.abstract_scenario_plugin.os.path.exists', return_value=True)
125128
@patch('time.sleep')
126129
def test_cerberus_publish_called_for_multiple_scenarios(
127-
self, mock_sleep, mock_signal_ctx, mock_collect_logs, mock_cleanup, mock_cerberus_publish
130+
self, mock_sleep, mock_exists, mock_signal_ctx, mock_collect_logs, mock_cleanup, mock_cerberus_publish
128131
):
129132
"""Test that cerberus.publish_kraken_status is called for each scenario"""
130133
mock_signal_ctx.return_value.__enter__ = Mock()
@@ -148,10 +151,11 @@ def test_cerberus_publish_called_for_multiple_scenarios(
148151
@patch('krkn.scenario_plugins.abstract_scenario_plugin.execute_rollback_version_files')
149152
@patch('krkn.scenario_plugins.abstract_scenario_plugin.utils.collect_and_put_ocp_logs')
150153
@patch('krkn.scenario_plugins.abstract_scenario_plugin.signal_handler.signal_context')
154+
@patch('krkn.scenario_plugins.abstract_scenario_plugin.os.path.exists', return_value=True)
151155
@patch('time.sleep')
152156
@patch('time.time')
153157
def test_cerberus_publish_timing(
154-
self, mock_time, mock_sleep, mock_signal_ctx, mock_collect_logs,
158+
self, mock_time, mock_sleep, mock_exists, mock_signal_ctx, mock_collect_logs,
155159
mock_rollback, mock_cleanup, mock_cerberus_publish
156160
):
157161
"""Test that cerberus.publish_kraken_status receives correct timestamps"""
@@ -181,9 +185,10 @@ def test_cerberus_publish_timing(
181185
@patch('krkn.scenario_plugins.abstract_scenario_plugin.cleanup_rollback_version_files')
182186
@patch('krkn.scenario_plugins.abstract_scenario_plugin.utils.collect_and_put_ocp_logs')
183187
@patch('krkn.scenario_plugins.abstract_scenario_plugin.signal_handler.signal_context')
188+
@patch('krkn.scenario_plugins.abstract_scenario_plugin.os.path.exists', return_value=True)
184189
@patch('time.sleep')
185190
def test_cerberus_publish_exception_does_not_break_flow(
186-
self, mock_sleep, mock_signal_ctx, mock_collect_logs, mock_cleanup, mock_cerberus_publish
191+
self, mock_sleep, mock_exists, mock_signal_ctx, mock_collect_logs, mock_cleanup, mock_cerberus_publish
187192
):
188193
"""Test that exceptions in cerberus.publish_kraken_status don't break scenario execution"""
189194
mock_signal_ctx.return_value.__enter__ = Mock()
@@ -210,9 +215,10 @@ def test_cerberus_publish_exception_does_not_break_flow(
210215
@patch('krkn.scenario_plugins.abstract_scenario_plugin.execute_rollback_version_files')
211216
@patch('krkn.scenario_plugins.abstract_scenario_plugin.utils.collect_and_put_ocp_logs')
212217
@patch('krkn.scenario_plugins.abstract_scenario_plugin.signal_handler.signal_context')
218+
@patch('krkn.scenario_plugins.abstract_scenario_plugin.os.path.exists', return_value=True)
213219
@patch('time.sleep')
214220
def test_cerberus_publish_called_for_mixed_success_and_failure(
215-
self, mock_sleep, mock_signal_ctx, mock_collect_logs, mock_rollback,
221+
self, mock_sleep, mock_exists, mock_signal_ctx, mock_collect_logs, mock_rollback,
216222
mock_cleanup, mock_cerberus_publish
217223
):
218224
"""Test cerberus publish is called for both successful and failed scenarios"""
@@ -250,9 +256,10 @@ def get_scenario_types(self):
250256
@patch('krkn.scenario_plugins.abstract_scenario_plugin.cerberus.publish_kraken_status')
251257
@patch('krkn.scenario_plugins.abstract_scenario_plugin.utils.collect_and_put_ocp_logs')
252258
@patch('krkn.scenario_plugins.abstract_scenario_plugin.signal_handler.signal_context')
259+
@patch('krkn.scenario_plugins.abstract_scenario_plugin.os.path.exists', return_value=True)
253260
@patch('time.sleep')
254261
def test_cerberus_not_called_for_deprecated_post_scenarios(
255-
self, mock_sleep, mock_signal_ctx, mock_collect_logs, mock_cerberus_publish
262+
self, mock_sleep, mock_exists, mock_signal_ctx, mock_collect_logs, mock_cerberus_publish
256263
):
257264
"""Test that cerberus is not called for deprecated post scenarios (list format)"""
258265
mock_signal_ctx.return_value.__enter__ = Mock()
@@ -277,9 +284,10 @@ def test_cerberus_not_called_for_deprecated_post_scenarios(
277284
@patch('krkn.scenario_plugins.abstract_scenario_plugin.utils.collect_and_put_ocp_logs')
278285
@patch('krkn.scenario_plugins.abstract_scenario_plugin.utils.populate_cluster_events')
279286
@patch('krkn.scenario_plugins.abstract_scenario_plugin.signal_handler.signal_context')
287+
@patch('krkn.scenario_plugins.abstract_scenario_plugin.os.path.exists', return_value=True)
280288
@patch('time.sleep')
281289
def test_cerberus_called_with_events_backup_enabled(
282-
self, mock_sleep, mock_signal_ctx, mock_populate_events,
290+
self, mock_sleep, mock_exists, mock_signal_ctx, mock_populate_events,
283291
mock_collect_logs, mock_cleanup, mock_cerberus_publish
284292
):
285293
"""Test that cerberus is called even when events_backup is enabled"""
@@ -308,9 +316,10 @@ def test_cerberus_called_with_events_backup_enabled(
308316
@patch('krkn.scenario_plugins.abstract_scenario_plugin.execute_rollback_version_files')
309317
@patch('krkn.scenario_plugins.abstract_scenario_plugin.utils.collect_and_put_ocp_logs')
310318
@patch('krkn.scenario_plugins.abstract_scenario_plugin.signal_handler.signal_context')
319+
@patch('krkn.scenario_plugins.abstract_scenario_plugin.os.path.exists', return_value=True)
311320
@patch('time.sleep')
312321
def test_cerberus_called_after_exception_in_run(
313-
self, mock_sleep, mock_signal_ctx, mock_collect_logs,
322+
self, mock_sleep, mock_exists, mock_signal_ctx, mock_collect_logs,
314323
mock_rollback, mock_cerberus_publish
315324
):
316325
"""Test that cerberus is called even if run() raises an uncaught exception"""
@@ -345,5 +354,73 @@ def get_scenario_types(self):
345354
self.assertEqual(telemetries[0].exit_status, 1)
346355

347356

357+
@patch('krkn.scenario_plugins.abstract_scenario_plugin.cerberus.publish_kraken_status')
358+
@patch('krkn.scenario_plugins.abstract_scenario_plugin.os.path.exists', return_value=False)
359+
@patch('time.sleep')
360+
def test_missing_scenario_file_logs_error_and_marks_failed(
361+
self, mock_sleep, mock_exists, mock_cerberus_publish
362+
):
363+
"""Test that a missing scenario file logs a clear error and is marked as failed without crashing"""
364+
scenarios_list = ["scenarios/openshift/cnv.yml"]
365+
366+
with self.assertLogs('root', level='ERROR') as log_ctx:
367+
failed_scenarios, telemetries = self.plugin.run_scenarios(
368+
"test-uuid",
369+
scenarios_list,
370+
self.krkn_config,
371+
self.mock_telemetry,
372+
)
373+
374+
# scenario is marked failed and returned in failed list
375+
self.assertEqual(len(failed_scenarios), 1)
376+
self.assertEqual(failed_scenarios[0], "scenarios/openshift/cnv.yml")
377+
378+
# telemetry recorded with exit_status=1
379+
self.assertEqual(len(telemetries), 1)
380+
self.assertEqual(telemetries[0].exit_status, 1)
381+
382+
# error message contains the missing path
383+
self.assertTrue(
384+
any("scenarios/openshift/cnv.yml" in msg for msg in log_ctx.output),
385+
f"Expected file path in error log, got: {log_ctx.output}",
386+
)
387+
388+
# set_parameters_base64 and cerberus should not be called
389+
self.mock_telemetry.set_parameters_base64.assert_not_called()
390+
mock_cerberus_publish.assert_not_called()
391+
392+
@patch('krkn.scenario_plugins.abstract_scenario_plugin.cerberus.publish_kraken_status')
393+
@patch('krkn.scenario_plugins.abstract_scenario_plugin.cleanup_rollback_version_files')
394+
@patch('krkn.scenario_plugins.abstract_scenario_plugin.utils.collect_and_put_ocp_logs')
395+
@patch('krkn.scenario_plugins.abstract_scenario_plugin.signal_handler.signal_context')
396+
@patch('krkn.scenario_plugins.abstract_scenario_plugin.os.path.exists')
397+
@patch('time.sleep')
398+
def test_missing_scenario_file_skipped_others_continue(
399+
self, mock_sleep, mock_exists, mock_signal_ctx, mock_collect_logs,
400+
mock_cleanup, mock_cerberus_publish
401+
):
402+
"""Test that a missing file is skipped and remaining scenarios still run"""
403+
mock_signal_ctx.return_value.__enter__ = Mock()
404+
mock_signal_ctx.return_value.__exit__ = Mock(return_value=False)
405+
# first file missing, second exists
406+
mock_exists.side_effect = [False, True]
407+
408+
scenarios_list = ["missing.yml", "scenario2.yaml"]
409+
410+
with self.assertLogs('root', level='ERROR'):
411+
failed_scenarios, telemetries = self.plugin.run_scenarios(
412+
"test-uuid",
413+
scenarios_list,
414+
self.krkn_config,
415+
self.mock_telemetry,
416+
)
417+
418+
self.assertIn("missing.yml", failed_scenarios)
419+
self.assertNotIn("scenario2.yaml", failed_scenarios)
420+
self.assertEqual(len(telemetries), 2)
421+
# cerberus called only for the scenario that ran
422+
self.assertEqual(mock_cerberus_publish.call_count, 1)
423+
424+
348425
if __name__ == '__main__':
349426
unittest.main()

0 commit comments

Comments
 (0)