1 | # Licensed to the StackStorm, Inc ('StackStorm') under one or more |
||
2 | # contributor license agreements. See the NOTICE file distributed with |
||
3 | # this work for additional information regarding copyright ownership. |
||
4 | # The ASF licenses this file to You under the Apache License, Version 2.0 |
||
5 | # (the "License"); you may not use this file except in compliance with |
||
6 | # the License. You may obtain a copy of the License at |
||
7 | # |
||
8 | # http://www.apache.org/licenses/LICENSE-2.0 |
||
9 | # |
||
10 | # Unless required by applicable law or agreed to in writing, software |
||
11 | # distributed under the License is distributed on an "AS IS" BASIS, |
||
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||
13 | # See the License for the specific language governing permissions and |
||
14 | # limitations under the License. |
||
15 | |||
16 | from __future__ import absolute_import |
||
17 | |||
18 | import six |
||
19 | import mock |
||
20 | |||
21 | from action_chain_runner import action_chain_runner as acr |
||
22 | from st2common.constants.action import LIVEACTION_STATUS_RUNNING |
||
23 | from st2common.constants.action import LIVEACTION_STATUS_SUCCEEDED |
||
24 | from st2common.constants.action import LIVEACTION_STATUS_CANCELED |
||
25 | from st2common.constants.action import LIVEACTION_STATUS_TIMED_OUT |
||
26 | from st2common.constants.action import LIVEACTION_STATUS_FAILED |
||
27 | from st2common.exceptions import actionrunner as runnerexceptions |
||
28 | from st2common.models.api.notification import NotificationsHelper |
||
29 | from st2common.models.db.liveaction import LiveActionDB |
||
30 | from st2common.models.db.keyvalue import KeyValuePairDB |
||
31 | from st2common.models.system.common import ResourceReference |
||
32 | from st2common.persistence.keyvalue import KeyValuePair |
||
33 | from st2common.persistence.runner import RunnerType |
||
34 | from st2common.services import action as action_service |
||
35 | from st2common.util import action_db as action_db_util |
||
36 | from st2common.exceptions.action import ParameterRenderingFailedException |
||
37 | from st2tests import DbTestCase |
||
38 | from st2tests.fixturesloader import FixturesLoader |
||
39 | |||
40 | |||
41 | class DummyActionExecution(object): |
||
42 | def __init__(self, status=LIVEACTION_STATUS_SUCCEEDED, result=''): |
||
43 | self.id = None |
||
44 | self.status = status |
||
45 | self.result = result |
||
46 | |||
47 | |||
48 | FIXTURES_PACK = 'generic' |
||
49 | |||
50 | TEST_MODELS = { |
||
51 | 'actions': ['a1.yaml', 'a2.yaml', 'action_4_action_context_param.yaml'], |
||
52 | 'runners': ['testrunner1.yaml'] |
||
53 | } |
||
54 | |||
55 | MODELS = FixturesLoader().load_models(fixtures_pack=FIXTURES_PACK, |
||
56 | fixtures_dict=TEST_MODELS) |
||
57 | ACTION_1 = MODELS['actions']['a1.yaml'] |
||
58 | ACTION_2 = MODELS['actions']['a2.yaml'] |
||
59 | ACTION_3 = MODELS['actions']['action_4_action_context_param.yaml'] |
||
60 | RUNNER = MODELS['runners']['testrunner1.yaml'] |
||
61 | |||
62 | CHAIN_1_PATH = FixturesLoader().get_fixture_file_path_abs( |
||
63 | FIXTURES_PACK, 'actionchains', 'chain1.yaml') |
||
64 | CHAIN_2_PATH = FixturesLoader().get_fixture_file_path_abs( |
||
65 | FIXTURES_PACK, 'actionchains', 'chain2.yaml') |
||
66 | CHAIN_ACTION_CALL_NO_PARAMS_PATH = FixturesLoader().get_fixture_file_path_abs( |
||
67 | FIXTURES_PACK, 'actionchains', 'chain_action_call_no_params.yaml') |
||
68 | CHAIN_NO_DEFAULT = FixturesLoader().get_fixture_file_path_abs( |
||
69 | FIXTURES_PACK, 'actionchains', 'no_default_chain.yaml') |
||
70 | CHAIN_NO_DEFAULT_2 = FixturesLoader().get_fixture_file_path_abs( |
||
71 | FIXTURES_PACK, 'actionchains', 'no_default_chain_2.yaml') |
||
72 | CHAIN_BAD_DEFAULT = FixturesLoader().get_fixture_file_path_abs( |
||
73 | FIXTURES_PACK, 'actionchains', 'bad_default_chain.yaml') |
||
74 | CHAIN_BROKEN_ON_SUCCESS_PATH_STATIC_TASK_NAME = FixturesLoader().get_fixture_file_path_abs( |
||
75 | FIXTURES_PACK, 'actionchains', 'chain_broken_on_success_path_static_task_name.yaml') |
||
76 | CHAIN_BROKEN_ON_FAILURE_PATH_STATIC_TASK_NAME = FixturesLoader().get_fixture_file_path_abs( |
||
77 | FIXTURES_PACK, 'actionchains', 'chain_broken_on_failure_path_static_task_name.yaml') |
||
78 | CHAIN_FIRST_TASK_RENDER_FAIL_PATH = FixturesLoader().get_fixture_file_path_abs( |
||
79 | FIXTURES_PACK, 'actionchains', 'chain_first_task_parameter_render_fail.yaml') |
||
80 | CHAIN_SECOND_TASK_RENDER_FAIL_PATH = FixturesLoader().get_fixture_file_path_abs( |
||
81 | FIXTURES_PACK, 'actionchains', 'chain_second_task_parameter_render_fail.yaml') |
||
82 | CHAIN_LIST_TEMP_PATH = FixturesLoader().get_fixture_file_path_abs( |
||
83 | FIXTURES_PACK, 'actionchains', 'chain_list_template.yaml') |
||
84 | CHAIN_DICT_TEMP_PATH = FixturesLoader().get_fixture_file_path_abs( |
||
85 | FIXTURES_PACK, 'actionchains', 'chain_dict_template.yaml') |
||
86 | CHAIN_DEP_INPUT = FixturesLoader().get_fixture_file_path_abs( |
||
87 | FIXTURES_PACK, 'actionchains', 'chain_dependent_input.yaml') |
||
88 | CHAIN_DEP_RESULTS_INPUT = FixturesLoader().get_fixture_file_path_abs( |
||
89 | FIXTURES_PACK, 'actionchains', 'chain_dep_result_input.yaml') |
||
90 | MALFORMED_CHAIN_PATH = FixturesLoader().get_fixture_file_path_abs( |
||
91 | FIXTURES_PACK, 'actionchains', 'malformedchain.yaml') |
||
92 | CHAIN_TYPED_PARAMS = FixturesLoader().get_fixture_file_path_abs( |
||
93 | FIXTURES_PACK, 'actionchains', 'chain_typed_params.yaml') |
||
94 | CHAIN_SYSTEM_PARAMS = FixturesLoader().get_fixture_file_path_abs( |
||
95 | FIXTURES_PACK, 'actionchains', 'chain_typed_system_params.yaml') |
||
96 | CHAIN_WITH_ACTIONPARAM_VARS = FixturesLoader().get_fixture_file_path_abs( |
||
97 | FIXTURES_PACK, 'actionchains', 'chain_with_actionparam_vars.yaml') |
||
98 | CHAIN_WITH_SYSTEM_VARS = FixturesLoader().get_fixture_file_path_abs( |
||
99 | FIXTURES_PACK, 'actionchains', 'chain_with_system_vars.yaml') |
||
100 | CHAIN_WITH_PUBLISH = FixturesLoader().get_fixture_file_path_abs( |
||
101 | FIXTURES_PACK, 'actionchains', 'chain_with_publish.yaml') |
||
102 | CHAIN_WITH_PUBLISH_2 = FixturesLoader().get_fixture_file_path_abs( |
||
103 | FIXTURES_PACK, 'actionchains', 'chain_with_publish_2.yaml') |
||
104 | CHAIN_WITH_PUBLISH_PARAM_RENDERING_FAILURE = FixturesLoader().get_fixture_file_path_abs( |
||
105 | FIXTURES_PACK, 'actionchains', 'chain_publish_params_rendering_failure.yaml') |
||
106 | CHAIN_WITH_INVALID_ACTION = FixturesLoader().get_fixture_file_path_abs( |
||
107 | FIXTURES_PACK, 'actionchains', 'chain_with_invalid_action.yaml') |
||
108 | CHAIN_ACTION_PARAMS_AND_PARAMETERS_ATTRIBUTE = FixturesLoader().get_fixture_file_path_abs( |
||
109 | FIXTURES_PACK, 'actionchains', 'chain_action_params_and_parameters.yaml') |
||
110 | CHAIN_ACTION_PARAMS_ATTRIBUTE = FixturesLoader().get_fixture_file_path_abs( |
||
111 | FIXTURES_PACK, 'actionchains', 'chain_action_params_attribute.yaml') |
||
112 | CHAIN_ACTION_PARAMETERS_ATTRIBUTE = FixturesLoader().get_fixture_file_path_abs( |
||
113 | FIXTURES_PACK, 'actionchains', 'chain_action_parameters_attribute.yaml') |
||
114 | CHAIN_ACTION_INVALID_PARAMETER_TYPE = FixturesLoader().get_fixture_file_path_abs( |
||
115 | FIXTURES_PACK, 'actionchains', 'chain_invalid_parameter_type_passed_to_action.yaml') |
||
116 | |||
117 | CHAIN_NOTIFY_API = {'notify': {'on-complete': {'message': 'foo happened.'}}} |
||
118 | CHAIN_NOTIFY_DB = NotificationsHelper.to_model(CHAIN_NOTIFY_API) |
||
119 | |||
120 | |||
121 | @mock.patch.object( |
||
122 | action_db_util, |
||
123 | 'get_runnertype_by_name', |
||
124 | mock.MagicMock(return_value=RUNNER)) |
||
125 | @mock.patch.object( |
||
126 | action_service, |
||
127 | 'is_action_canceled_or_canceling', |
||
128 | mock.MagicMock(return_value=False)) |
||
129 | @mock.patch.object( |
||
130 | action_service, |
||
131 | 'is_action_paused_or_pausing', |
||
132 | mock.MagicMock(return_value=False)) |
||
133 | class TestActionChainRunner(DbTestCase): |
||
134 | |||
135 | def test_runner_creation(self): |
||
136 | runner = acr.get_runner() |
||
137 | self.assertTrue(runner) |
||
138 | self.assertTrue(runner.runner_id) |
||
139 | |||
140 | def test_malformed_chain(self): |
||
141 | try: |
||
142 | chain_runner = acr.get_runner() |
||
143 | chain_runner.entry_point = MALFORMED_CHAIN_PATH |
||
144 | chain_runner.action = ACTION_1 |
||
145 | chain_runner.pre_run() |
||
146 | self.assertTrue(False, 'Expected pre_run to fail.') |
||
147 | except runnerexceptions.ActionRunnerPreRunError: |
||
148 | self.assertTrue(True) |
||
149 | |||
150 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
151 | mock.MagicMock(return_value=ACTION_1)) |
||
152 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
153 | def test_chain_runner_success_path(self, request): |
||
154 | chain_runner = acr.get_runner() |
||
155 | chain_runner.entry_point = CHAIN_1_PATH |
||
156 | chain_runner.action = ACTION_1 |
||
157 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
158 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
159 | chain_runner.liveaction.notify = CHAIN_NOTIFY_DB |
||
160 | chain_runner.pre_run() |
||
161 | chain_runner.run({}) |
||
162 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
163 | # based on the chain the callcount is known to be 3. Not great but works. |
||
164 | self.assertEqual(request.call_count, 3) |
||
165 | |||
166 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
167 | mock.MagicMock(return_value=ACTION_1)) |
||
168 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
169 | def test_chain_runner_chain_second_task_times_out(self, request): |
||
170 | # Second task in the chain times out so the action chain status should be timeout |
||
171 | chain_runner = acr.get_runner() |
||
172 | chain_runner.entry_point = CHAIN_2_PATH |
||
173 | chain_runner.action = ACTION_1 |
||
174 | |||
175 | original_run_action = chain_runner._run_action |
||
0 ignored issues
–
show
|
|||
176 | |||
177 | def mock_run_action(*args, **kwargs): |
||
178 | original_live_action = args[0] |
||
179 | liveaction = original_run_action(*args, **kwargs) |
||
180 | if original_live_action.action == 'wolfpack.a2': |
||
181 | # Mock a timeout for second task |
||
182 | liveaction.status = LIVEACTION_STATUS_TIMED_OUT |
||
183 | return liveaction |
||
184 | |||
185 | chain_runner._run_action = mock_run_action |
||
0 ignored issues
–
show
It seems like
_run_action was declared protected and should not be accessed from this context.
Prefixing a member variable class MyParent:
def __init__(self):
self._x = 1;
self.y = 2;
class MyChild(MyParent):
def some_method(self):
return self._x # Ok, since accessed from a child class
class AnotherClass:
def some_method(self, instance_of_my_child):
return instance_of_my_child._x # Would be flagged as AnotherClass is not
# a child class of MyParent
Loading history...
|
|||
186 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
187 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
188 | chain_runner.pre_run() |
||
189 | status, _, _ = chain_runner.run({}) |
||
190 | |||
191 | self.assertEqual(status, LIVEACTION_STATUS_TIMED_OUT) |
||
192 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
193 | # based on the chain the callcount is known to be 3. Not great but works. |
||
194 | self.assertEqual(request.call_count, 3) |
||
195 | |||
196 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
197 | mock.MagicMock(return_value=ACTION_1)) |
||
198 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
199 | def test_chain_runner_task_is_canceled_while_running(self, request): |
||
200 | # Second task in the action is CANCELED, make sure runner doesn't get stuck in an infinite |
||
201 | # loop |
||
202 | chain_runner = acr.get_runner() |
||
203 | chain_runner.entry_point = CHAIN_2_PATH |
||
204 | chain_runner.action = ACTION_1 |
||
205 | |||
206 | original_run_action = chain_runner._run_action |
||
0 ignored issues
–
show
It seems like
_run_action was declared protected and should not be accessed from this context.
Prefixing a member variable class MyParent:
def __init__(self):
self._x = 1;
self.y = 2;
class MyChild(MyParent):
def some_method(self):
return self._x # Ok, since accessed from a child class
class AnotherClass:
def some_method(self, instance_of_my_child):
return instance_of_my_child._x # Would be flagged as AnotherClass is not
# a child class of MyParent
Loading history...
|
|||
207 | |||
208 | def mock_run_action(*args, **kwargs): |
||
209 | original_live_action = args[0] |
||
210 | if original_live_action.action == 'wolfpack.a2': |
||
211 | status = LIVEACTION_STATUS_CANCELED |
||
212 | else: |
||
213 | status = LIVEACTION_STATUS_SUCCEEDED |
||
214 | request.return_value = (DummyActionExecution(status=status), None) |
||
215 | liveaction = original_run_action(*args, **kwargs) |
||
216 | return liveaction |
||
217 | |||
218 | chain_runner._run_action = mock_run_action |
||
0 ignored issues
–
show
It seems like
_run_action was declared protected and should not be accessed from this context.
Prefixing a member variable class MyParent:
def __init__(self):
self._x = 1;
self.y = 2;
class MyChild(MyParent):
def some_method(self):
return self._x # Ok, since accessed from a child class
class AnotherClass:
def some_method(self, instance_of_my_child):
return instance_of_my_child._x # Would be flagged as AnotherClass is not
# a child class of MyParent
Loading history...
|
|||
219 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
220 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
221 | chain_runner.pre_run() |
||
222 | status, _, _ = chain_runner.run({}) |
||
223 | |||
224 | self.assertEqual(status, LIVEACTION_STATUS_CANCELED) |
||
225 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
226 | # Chain count should be 2 since the last task doesn't get called since the second one was |
||
227 | # canceled |
||
228 | self.assertEqual(request.call_count, 2) |
||
229 | |||
230 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
231 | mock.MagicMock(return_value=ACTION_1)) |
||
232 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
233 | def test_chain_runner_success_task_action_call_with_no_params(self, request): |
||
234 | # Make sure that the runner doesn't explode if task definition contains |
||
235 | # no "params" section |
||
236 | chain_runner = acr.get_runner() |
||
237 | chain_runner.entry_point = CHAIN_ACTION_CALL_NO_PARAMS_PATH |
||
238 | chain_runner.action = ACTION_1 |
||
239 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
240 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
241 | chain_runner.liveaction.notify = CHAIN_NOTIFY_DB |
||
242 | chain_runner.pre_run() |
||
243 | chain_runner.run({}) |
||
244 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
245 | # based on the chain the callcount is known to be 3. Not great but works. |
||
246 | self.assertEqual(request.call_count, 3) |
||
247 | |||
248 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
249 | mock.MagicMock(return_value=ACTION_1)) |
||
250 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
251 | def test_chain_runner_no_default(self, request): |
||
252 | chain_runner = acr.get_runner() |
||
253 | chain_runner.entry_point = CHAIN_NO_DEFAULT |
||
254 | chain_runner.action = ACTION_1 |
||
255 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
256 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
257 | chain_runner.pre_run() |
||
258 | chain_runner.run({}) |
||
259 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
260 | # In case of this chain default_node is the first_node. |
||
261 | default_node = chain_runner.chain_holder.actionchain.default |
||
262 | first_node = chain_runner.chain_holder.actionchain.chain[0] |
||
263 | self.assertEqual(default_node, first_node.name) |
||
264 | # based on the chain the callcount is known to be 3. Not great but works. |
||
265 | self.assertEqual(request.call_count, 3) |
||
266 | |||
267 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
268 | mock.MagicMock(return_value=ACTION_1)) |
||
269 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
270 | def test_chain_runner_no_default_multiple_options(self, request): |
||
271 | # subtle difference is that when there are multiple possible default nodes |
||
272 | # the order per chain definition may not be preseved. This is really a |
||
273 | # poorly formatted chain but we still the best attempt to work. |
||
274 | chain_runner = acr.get_runner() |
||
275 | chain_runner.entry_point = CHAIN_NO_DEFAULT_2 |
||
276 | chain_runner.action = ACTION_1 |
||
277 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
278 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
279 | chain_runner.pre_run() |
||
280 | chain_runner.run({}) |
||
281 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
282 | # In case of this chain default_node is the first_node. |
||
283 | default_node = chain_runner.chain_holder.actionchain.default |
||
284 | first_node = chain_runner.chain_holder.actionchain.chain[0] |
||
285 | self.assertEqual(default_node, first_node.name) |
||
286 | # based on the chain the callcount is known to be 2. |
||
287 | self.assertEqual(request.call_count, 2) |
||
288 | |||
289 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
290 | mock.MagicMock(return_value=ACTION_1)) |
||
291 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
292 | def test_chain_runner_bad_default(self, request): |
||
293 | chain_runner = acr.get_runner() |
||
294 | chain_runner.entry_point = CHAIN_BAD_DEFAULT |
||
295 | chain_runner.action = ACTION_1 |
||
296 | expected_msg = 'Unable to find node with name "bad_default" referenced in "default".' |
||
297 | self.assertRaisesRegexp(runnerexceptions.ActionRunnerPreRunError, |
||
298 | expected_msg, chain_runner.pre_run) |
||
299 | |||
300 | @mock.patch('eventlet.sleep', mock.MagicMock()) |
||
301 | @mock.patch.object(action_db_util, 'get_liveaction_by_id', mock.MagicMock( |
||
302 | return_value=DummyActionExecution())) |
||
303 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
304 | mock.MagicMock(return_value=ACTION_1)) |
||
305 | @mock.patch.object(action_service, 'request', |
||
306 | return_value=(DummyActionExecution(status=LIVEACTION_STATUS_RUNNING), None)) |
||
307 | def test_chain_runner_success_path_with_wait(self, request): |
||
308 | chain_runner = acr.get_runner() |
||
309 | chain_runner.entry_point = CHAIN_1_PATH |
||
310 | chain_runner.action = ACTION_1 |
||
311 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
312 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
313 | chain_runner.pre_run() |
||
314 | chain_runner.run({}) |
||
315 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
316 | # based on the chain the callcount is known to be 3. Not great but works. |
||
317 | self.assertEqual(request.call_count, 3) |
||
318 | |||
319 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
320 | mock.MagicMock(return_value=ACTION_1)) |
||
321 | @mock.patch.object(action_service, 'request', |
||
322 | return_value=(DummyActionExecution(status=LIVEACTION_STATUS_FAILED), None)) |
||
323 | def test_chain_runner_failure_path(self, request): |
||
324 | chain_runner = acr.get_runner() |
||
325 | chain_runner.entry_point = CHAIN_1_PATH |
||
326 | chain_runner.action = ACTION_1 |
||
327 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
328 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
329 | chain_runner.pre_run() |
||
330 | status, _, _ = chain_runner.run({}) |
||
331 | self.assertEqual(status, LIVEACTION_STATUS_FAILED) |
||
332 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
333 | # based on the chain the callcount is known to be 2. Not great but works. |
||
334 | self.assertEqual(request.call_count, 2) |
||
335 | |||
336 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
337 | mock.MagicMock(return_value=ACTION_1)) |
||
338 | @mock.patch.object(action_service, 'request', |
||
339 | return_value=(DummyActionExecution(), None)) |
||
340 | def test_chain_runner_broken_on_success_path_static_task_name(self, request): |
||
341 | chain_runner = acr.get_runner() |
||
342 | chain_runner.entry_point = CHAIN_BROKEN_ON_SUCCESS_PATH_STATIC_TASK_NAME |
||
343 | chain_runner.action = ACTION_1 |
||
344 | |||
345 | expected_msg = ('Unable to find node with name "c5" referenced in "on-success" ' |
||
346 | 'in task "c2"') |
||
347 | self.assertRaisesRegexp(runnerexceptions.ActionRunnerPreRunError, |
||
348 | expected_msg, chain_runner.pre_run) |
||
349 | |||
350 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
351 | mock.MagicMock(return_value=ACTION_1)) |
||
352 | @mock.patch.object(action_service, 'request', |
||
353 | return_value=(DummyActionExecution(), None)) |
||
354 | def test_chain_runner_broken_on_failure_path_static_task_name(self, request): |
||
355 | chain_runner = acr.get_runner() |
||
356 | chain_runner.entry_point = CHAIN_BROKEN_ON_FAILURE_PATH_STATIC_TASK_NAME |
||
357 | chain_runner.action = ACTION_1 |
||
358 | |||
359 | expected_msg = ('Unable to find node with name "c6" referenced in "on-failure" ' |
||
360 | 'in task "c2"') |
||
361 | self.assertRaisesRegexp(runnerexceptions.ActionRunnerPreRunError, |
||
362 | expected_msg, chain_runner.pre_run) |
||
363 | |||
364 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
365 | mock.MagicMock(return_value=ACTION_1)) |
||
366 | @mock.patch.object(action_service, 'request', side_effect=RuntimeError('Test Failure.')) |
||
367 | def test_chain_runner_action_exception(self, request): |
||
368 | chain_runner = acr.get_runner() |
||
369 | chain_runner.entry_point = CHAIN_1_PATH |
||
370 | chain_runner.action = ACTION_1 |
||
371 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
372 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
373 | chain_runner.pre_run() |
||
374 | status, results, _ = chain_runner.run({}) |
||
375 | self.assertEqual(status, LIVEACTION_STATUS_FAILED) |
||
376 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
377 | |||
378 | # based on the chain the callcount is known to be 2. Not great but works. |
||
379 | self.assertEqual(request.call_count, 2) |
||
380 | |||
381 | error_count = 0 |
||
382 | for task_result in results['tasks']: |
||
383 | if task_result['result'].get('error', None): |
||
384 | error_count += 1 |
||
385 | |||
386 | self.assertEqual(error_count, 2) |
||
387 | |||
388 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
389 | mock.MagicMock(return_value=ACTION_1)) |
||
390 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
391 | def test_chain_runner_str_param_temp(self, request): |
||
392 | chain_runner = acr.get_runner() |
||
393 | chain_runner.entry_point = CHAIN_FIRST_TASK_RENDER_FAIL_PATH |
||
394 | chain_runner.action = ACTION_1 |
||
395 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
396 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
397 | chain_runner.pre_run() |
||
398 | chain_runner.run({'s1': 1, 's2': 2, 's3': 3, 's4': 4}) |
||
399 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
400 | mock_args, _ = request.call_args |
||
401 | self.assertEqual(mock_args[0].parameters, {"p1": "1"}) |
||
402 | |||
403 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
404 | mock.MagicMock(return_value=ACTION_1)) |
||
405 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
406 | def test_chain_runner_list_param_temp(self, request): |
||
407 | chain_runner = acr.get_runner() |
||
408 | chain_runner.entry_point = CHAIN_LIST_TEMP_PATH |
||
409 | chain_runner.action = ACTION_1 |
||
410 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
411 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
412 | chain_runner.pre_run() |
||
413 | chain_runner.run({'s1': 1, 's2': 2, 's3': 3, 's4': 4}) |
||
414 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
415 | mock_args, _ = request.call_args |
||
416 | self.assertEqual(mock_args[0].parameters, {"p1": "[2, 3, 4]"}) |
||
417 | |||
418 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
419 | mock.MagicMock(return_value=ACTION_1)) |
||
420 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
421 | def test_chain_runner_dict_param_temp(self, request): |
||
422 | chain_runner = acr.get_runner() |
||
423 | chain_runner.entry_point = CHAIN_DICT_TEMP_PATH |
||
424 | chain_runner.action = ACTION_1 |
||
425 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
426 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
427 | chain_runner.pre_run() |
||
428 | chain_runner.run({'s1': 1, 's2': 2, 's3': 3, 's4': 4}) |
||
429 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
430 | expected_value = {"p1": {"p1.3": "[3, 4]", "p1.2": "2", "p1.1": "1"}} |
||
431 | mock_args, _ = request.call_args |
||
432 | self.assertEqual(mock_args[0].parameters, expected_value) |
||
433 | |||
434 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
435 | mock.MagicMock(return_value=ACTION_1)) |
||
436 | @mock.patch.object(action_service, 'request', |
||
437 | return_value=(DummyActionExecution(result={'o1': '1'}), None)) |
||
438 | def test_chain_runner_dependent_param_temp(self, request): |
||
439 | chain_runner = acr.get_runner() |
||
440 | chain_runner.entry_point = CHAIN_DEP_INPUT |
||
441 | chain_runner.action = ACTION_1 |
||
442 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
443 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
444 | chain_runner.pre_run() |
||
445 | chain_runner.run({'s1': 1, 's2': 2, 's3': 3, 's4': 4}) |
||
446 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
447 | expected_values = [{u'p1': u'1'}, |
||
448 | {u'p1': u'1'}, |
||
449 | {u'p2': u'1', u'p3': u'1', u'p1': u'1'}] |
||
450 | # Each of the call_args must be one of |
||
451 | for call_args in request.call_args_list: |
||
452 | self.assertTrue(call_args[0][0].parameters in expected_values) |
||
453 | expected_values.remove(call_args[0][0].parameters) |
||
454 | self.assertEqual(len(expected_values), 0, 'Not all expected values received.') |
||
455 | |||
456 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
457 | mock.MagicMock(return_value=ACTION_1)) |
||
458 | @mock.patch.object(action_service, 'request', |
||
459 | return_value=(DummyActionExecution(result={'o1': '1'}), None)) |
||
460 | def test_chain_runner_dependent_results_param(self, request): |
||
461 | chain_runner = acr.get_runner() |
||
462 | chain_runner.entry_point = CHAIN_DEP_RESULTS_INPUT |
||
463 | chain_runner.action = ACTION_1 |
||
464 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
465 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
466 | chain_runner.pre_run() |
||
467 | chain_runner.run({'s1': 1}) |
||
468 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
469 | |||
470 | if six.PY2: |
||
471 | expected_values = [{u'p1': u'1'}, |
||
472 | {u'p1': u'1'}, |
||
473 | {u'out': u"{'c2': {'o1': '1'}, 'c1': {'o1': '1'}}"}] |
||
474 | else: |
||
475 | expected_values = [{'p1': '1'}, |
||
476 | {'p1': '1'}, |
||
477 | {'out': "{'c1': {'o1': '1'}, 'c2': {'o1': '1'}}"}] |
||
478 | |||
479 | # Each of the call_args must be one of |
||
480 | self.assertEqual(request.call_count, 3) |
||
481 | for call_args in request.call_args_list: |
||
482 | self.assertTrue(call_args[0][0].parameters in expected_values) |
||
483 | expected_values.remove(call_args[0][0].parameters) |
||
484 | |||
485 | self.assertEqual(len(expected_values), 0, 'Not all expected values received.') |
||
486 | |||
487 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
488 | mock.MagicMock(return_value=ACTION_1)) |
||
489 | @mock.patch.object(RunnerType, 'get_by_name', |
||
490 | mock.MagicMock(return_value=RUNNER)) |
||
491 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
492 | def test_chain_runner_missing_param_temp(self, request): |
||
493 | chain_runner = acr.get_runner() |
||
494 | chain_runner.entry_point = CHAIN_FIRST_TASK_RENDER_FAIL_PATH |
||
495 | chain_runner.action = ACTION_1 |
||
496 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
497 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
498 | chain_runner.pre_run() |
||
499 | chain_runner.run({}) |
||
500 | self.assertEqual(request.call_count, 0, 'No call expected.') |
||
501 | |||
502 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
503 | mock.MagicMock(return_value=ACTION_1)) |
||
504 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
505 | def test_chain_runner_failure_during_param_rendering_single_task(self, request): |
||
506 | # Parameter rendering should result in a top level error which aborts |
||
507 | # the whole chain |
||
508 | chain_runner = acr.get_runner() |
||
509 | chain_runner.entry_point = CHAIN_FIRST_TASK_RENDER_FAIL_PATH |
||
510 | chain_runner.action = ACTION_1 |
||
511 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
512 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
513 | chain_runner.pre_run() |
||
514 | status, result, _ = chain_runner.run({}) |
||
515 | |||
516 | # No tasks ran because rendering of parameters for the first task failed |
||
517 | self.assertEqual(status, LIVEACTION_STATUS_FAILED) |
||
518 | self.assertEqual(result['tasks'], []) |
||
519 | self.assertTrue('error' in result) |
||
520 | self.assertTrue('traceback' in result) |
||
521 | self.assertTrue('Failed to run task "c1". Parameter rendering failed' in result['error']) |
||
522 | self.assertTrue('Traceback' in result['traceback']) |
||
523 | |||
524 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
525 | mock.MagicMock(return_value=ACTION_1)) |
||
526 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
527 | def test_chain_runner_failure_during_param_rendering_multiple_tasks(self, request): |
||
528 | # Parameter rendering should result in a top level error which aborts |
||
529 | # the whole chain |
||
530 | chain_runner = acr.get_runner() |
||
531 | chain_runner.entry_point = CHAIN_SECOND_TASK_RENDER_FAIL_PATH |
||
532 | chain_runner.action = ACTION_1 |
||
533 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
534 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
535 | chain_runner.pre_run() |
||
536 | status, result, _ = chain_runner.run({}) |
||
537 | |||
538 | # Verify that only first task has ran |
||
539 | self.assertEqual(status, LIVEACTION_STATUS_FAILED) |
||
540 | self.assertEqual(len(result['tasks']), 1) |
||
541 | self.assertEqual(result['tasks'][0]['name'], 'c1') |
||
542 | |||
543 | expected_error = ('Failed rendering value for action parameter "p1" in ' |
||
544 | 'task "c2" (template string={{s1}}):') |
||
545 | |||
546 | self.assertTrue('error' in result) |
||
547 | self.assertTrue('traceback' in result) |
||
548 | self.assertTrue('Failed to run task "c2". Parameter rendering failed' in result['error']) |
||
549 | self.assertTrue(expected_error in result['error']) |
||
550 | self.assertTrue('Traceback' in result['traceback']) |
||
551 | |||
552 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
553 | mock.MagicMock(return_value=ACTION_2)) |
||
554 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
555 | def test_chain_runner_typed_params(self, request): |
||
556 | chain_runner = acr.get_runner() |
||
557 | chain_runner.entry_point = CHAIN_TYPED_PARAMS |
||
558 | chain_runner.action = ACTION_2 |
||
559 | action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack) |
||
560 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
561 | chain_runner.pre_run() |
||
562 | chain_runner.run({'s1': 1, 's2': 'two', 's3': 3.14}) |
||
563 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
564 | expected_value = {'booltype': True, |
||
565 | 'inttype': 1, |
||
566 | 'numbertype': 3.14, |
||
567 | 'strtype': 'two', |
||
568 | 'arrtype': ['1', 'two'], |
||
569 | 'objtype': {'s2': 'two', |
||
570 | 'k1': '1'}} |
||
571 | mock_args, _ = request.call_args |
||
572 | self.assertEqual(mock_args[0].parameters, expected_value) |
||
573 | |||
574 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
575 | mock.MagicMock(return_value=ACTION_2)) |
||
576 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
577 | def test_chain_runner_typed_system_params(self, request): |
||
578 | action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack) |
||
579 | kvps = [] |
||
580 | try: |
||
581 | kvps.append(KeyValuePair.add_or_update(KeyValuePairDB(name='a', value='1'))) |
||
582 | kvps.append(KeyValuePair.add_or_update(KeyValuePairDB(name='a.b.c', value='two'))) |
||
583 | chain_runner = acr.get_runner() |
||
584 | chain_runner.entry_point = CHAIN_SYSTEM_PARAMS |
||
585 | chain_runner.action = ACTION_2 |
||
586 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
587 | chain_runner.pre_run() |
||
588 | chain_runner.run({}) |
||
589 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
590 | expected_value = {'inttype': 1, |
||
591 | 'strtype': 'two'} |
||
592 | mock_args, _ = request.call_args |
||
593 | self.assertEqual(mock_args[0].parameters, expected_value) |
||
594 | finally: |
||
595 | for kvp in kvps: |
||
596 | KeyValuePair.delete(kvp) |
||
597 | |||
598 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
599 | mock.MagicMock(return_value=ACTION_2)) |
||
600 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
601 | def test_chain_runner_vars_system_params(self, request): |
||
602 | action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack) |
||
603 | kvps = [] |
||
604 | try: |
||
605 | kvps.append(KeyValuePair.add_or_update(KeyValuePairDB(name='a', value='two'))) |
||
606 | chain_runner = acr.get_runner() |
||
607 | chain_runner.entry_point = CHAIN_WITH_SYSTEM_VARS |
||
608 | chain_runner.action = ACTION_2 |
||
609 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
610 | chain_runner.pre_run() |
||
611 | chain_runner.run({}) |
||
612 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
613 | expected_value = {'inttype': 1, |
||
614 | 'strtype': 'two', |
||
615 | 'booltype': True} |
||
616 | mock_args, _ = request.call_args |
||
617 | self.assertEqual(mock_args[0].parameters, expected_value) |
||
618 | finally: |
||
619 | for kvp in kvps: |
||
620 | KeyValuePair.delete(kvp) |
||
621 | |||
622 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
623 | mock.MagicMock(return_value=ACTION_2)) |
||
624 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
625 | def test_chain_runner_vars_action_params(self, request): |
||
626 | chain_runner = acr.get_runner() |
||
627 | chain_runner.entry_point = CHAIN_WITH_ACTIONPARAM_VARS |
||
628 | chain_runner.action = ACTION_2 |
||
629 | action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack) |
||
630 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
631 | chain_runner.pre_run() |
||
632 | chain_runner.run({'input_a': 'two'}) |
||
633 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
634 | expected_value = {'inttype': 1, |
||
635 | 'strtype': 'two', |
||
636 | 'booltype': True} |
||
637 | mock_args, _ = request.call_args |
||
638 | self.assertEqual(mock_args[0].parameters, expected_value) |
||
639 | |||
640 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
641 | mock.MagicMock(return_value=ACTION_2)) |
||
642 | @mock.patch.object(action_service, 'request', |
||
643 | return_value=(DummyActionExecution(result={'raw_out': 'published'}), None)) |
||
644 | def test_chain_runner_publish(self, request): |
||
645 | chain_runner = acr.get_runner() |
||
646 | chain_runner.entry_point = CHAIN_WITH_PUBLISH |
||
647 | chain_runner.action = ACTION_2 |
||
648 | action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack) |
||
649 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
650 | chain_runner.runner_parameters = {'display_published': True} |
||
651 | chain_runner.pre_run() |
||
652 | |||
653 | action_parameters = {'action_param_1': 'test value 1'} |
||
654 | _, result, _ = chain_runner.run(action_parameters=action_parameters) |
||
655 | |||
656 | # We also assert that the action parameters are available in the |
||
657 | # "publish" scope |
||
658 | self.assertNotEqual(chain_runner.chain_holder.actionchain, None) |
||
659 | expected_value = {'inttype': 1, |
||
660 | 'strtype': 'published', |
||
661 | 'booltype': True, |
||
662 | 'published_action_param': action_parameters['action_param_1']} |
||
663 | mock_args, _ = request.call_args |
||
664 | self.assertEqual(mock_args[0].parameters, expected_value) |
||
665 | # Assert that the variables are correctly published |
||
666 | self.assertEqual(result['published'], |
||
667 | {'published_action_param': u'test value 1', 'o1': u'published'}) |
||
668 | |||
669 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
670 | mock.MagicMock(return_value=ACTION_1)) |
||
671 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
672 | def test_chain_runner_publish_param_rendering_failure(self, request): |
||
673 | # Parameter rendering should result in a top level error which aborts |
||
674 | # the whole chain |
||
675 | chain_runner = acr.get_runner() |
||
676 | chain_runner.entry_point = CHAIN_WITH_PUBLISH_PARAM_RENDERING_FAILURE |
||
677 | chain_runner.action = ACTION_1 |
||
678 | action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack) |
||
679 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
680 | chain_runner.pre_run() |
||
681 | |||
682 | try: |
||
683 | chain_runner.run({}) |
||
684 | except ParameterRenderingFailedException as e: |
||
685 | # TODO: Should we treat this as task error? Right now it bubbles all |
||
686 | # the way up and it's not really consistent with action param |
||
687 | # rendering failure |
||
688 | expected_error = ('Failed rendering value for publish parameter "p1" in ' |
||
689 | 'task "c2" (template string={{ not_defined }}):') |
||
690 | self.assertTrue(expected_error in str(e)) |
||
691 | pass |
||
692 | else: |
||
693 | self.fail('Exception was not thrown') |
||
694 | |||
695 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
696 | mock.MagicMock(return_value=ACTION_2)) |
||
697 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
698 | def test_chain_task_passes_invalid_parameter_type_to_action(self, mock_request): |
||
699 | chain_runner = acr.get_runner() |
||
700 | chain_runner.entry_point = CHAIN_ACTION_INVALID_PARAMETER_TYPE |
||
701 | chain_runner.action = ACTION_2 |
||
702 | chain_runner.pre_run() |
||
703 | |||
704 | action_parameters = {} |
||
705 | expected_msg = ('Failed to cast value "stringnotanarray" \(type: str\) for parameter ' |
||
706 | '"arrtype" of type "array"') |
||
707 | self.assertRaisesRegexp(ValueError, expected_msg, chain_runner.run, |
||
708 | action_parameters=action_parameters) |
||
709 | |||
710 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
711 | mock.MagicMock(return_value=None)) |
||
712 | @mock.patch.object(action_service, 'request', |
||
713 | return_value=(DummyActionExecution(result={'raw_out': 'published'}), None)) |
||
714 | def test_action_chain_runner_referenced_action_doesnt_exist(self, mock_request): |
||
715 | # Action referenced by a task doesn't exist, should result in a top level error |
||
716 | chain_runner = acr.get_runner() |
||
717 | chain_runner.entry_point = CHAIN_WITH_INVALID_ACTION |
||
718 | chain_runner.action = ACTION_2 |
||
719 | action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack) |
||
720 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
721 | chain_runner.pre_run() |
||
722 | |||
723 | action_parameters = {} |
||
724 | status, output, _ = chain_runner.run(action_parameters=action_parameters) |
||
725 | |||
726 | expected_error = ('Failed to run task "c1". Action with reference "wolfpack.a2" ' |
||
727 | 'doesn\'t exist.') |
||
728 | self.assertEqual(status, LIVEACTION_STATUS_FAILED) |
||
729 | self.assertTrue(expected_error in output['error']) |
||
730 | self.assertTrue('Traceback' in output['traceback'], output['traceback']) |
||
731 | |||
732 | def test_exception_is_thrown_if_both_params_and_parameters_attributes_are_provided(self): |
||
733 | chain_runner = acr.get_runner() |
||
734 | chain_runner.entry_point = CHAIN_ACTION_PARAMS_AND_PARAMETERS_ATTRIBUTE |
||
735 | chain_runner.action = ACTION_2 |
||
736 | |||
737 | expected_msg = ('Either "params" or "parameters" attribute needs to be provided, but ' |
||
738 | 'not both') |
||
739 | self.assertRaisesRegexp(runnerexceptions.ActionRunnerPreRunError, expected_msg, |
||
740 | chain_runner.pre_run) |
||
741 | |||
742 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
743 | mock.MagicMock(return_value=ACTION_2)) |
||
744 | @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None)) |
||
745 | def test_params_and_parameters_attributes_both_work(self, _): |
||
746 | action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack) |
||
747 | |||
748 | # "params" attribute used |
||
749 | chain_runner = acr.get_runner() |
||
750 | chain_runner.entry_point = CHAIN_ACTION_PARAMS_ATTRIBUTE |
||
751 | chain_runner.action = ACTION_2 |
||
752 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
753 | chain_runner.pre_run() |
||
754 | |||
755 | original_build_liveaction_object = chain_runner._build_liveaction_object |
||
0 ignored issues
–
show
It seems like
_build_liveaction_object was declared protected and should not be accessed from this context.
Prefixing a member variable class MyParent:
def __init__(self):
self._x = 1;
self.y = 2;
class MyChild(MyParent):
def some_method(self):
return self._x # Ok, since accessed from a child class
class AnotherClass:
def some_method(self, instance_of_my_child):
return instance_of_my_child._x # Would be flagged as AnotherClass is not
# a child class of MyParent
Loading history...
|
|||
756 | |||
757 | def mock_build_liveaction_object(action_node, resolved_params, parent_context): |
||
758 | # Verify parameters are correctly passed to the action |
||
759 | self.assertEqual(resolved_params, {'pparams': 'v1'}) |
||
760 | original_build_liveaction_object(action_node=action_node, |
||
761 | resolved_params=resolved_params, |
||
762 | parent_context=parent_context) |
||
763 | |||
764 | chain_runner._build_liveaction_object = mock_build_liveaction_object |
||
0 ignored issues
–
show
It seems like
_build_liveaction_object was declared protected and should not be accessed from this context.
Prefixing a member variable class MyParent:
def __init__(self):
self._x = 1;
self.y = 2;
class MyChild(MyParent):
def some_method(self):
return self._x # Ok, since accessed from a child class
class AnotherClass:
def some_method(self, instance_of_my_child):
return instance_of_my_child._x # Would be flagged as AnotherClass is not
# a child class of MyParent
Loading history...
|
|||
765 | |||
766 | action_parameters = {} |
||
767 | status, output, _ = chain_runner.run(action_parameters=action_parameters) |
||
768 | self.assertEqual(status, LIVEACTION_STATUS_SUCCEEDED) |
||
769 | |||
770 | # "parameters" attribute used |
||
771 | chain_runner = acr.get_runner() |
||
772 | chain_runner.entry_point = CHAIN_ACTION_PARAMETERS_ATTRIBUTE |
||
773 | chain_runner.action = ACTION_2 |
||
774 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
775 | chain_runner.pre_run() |
||
776 | |||
777 | def mock_build_liveaction_object(action_node, resolved_params, parent_context): |
||
778 | # Verify parameters are correctly passed to the action |
||
779 | self.assertEqual(resolved_params, {'pparameters': 'v1'}) |
||
780 | original_build_liveaction_object(action_node=action_node, |
||
781 | resolved_params=resolved_params, |
||
782 | parent_context=parent_context) |
||
783 | |||
784 | chain_runner._build_liveaction_object = mock_build_liveaction_object |
||
0 ignored issues
–
show
It seems like
_build_liveaction_object was declared protected and should not be accessed from this context.
Prefixing a member variable class MyParent:
def __init__(self):
self._x = 1;
self.y = 2;
class MyChild(MyParent):
def some_method(self):
return self._x # Ok, since accessed from a child class
class AnotherClass:
def some_method(self, instance_of_my_child):
return instance_of_my_child._x # Would be flagged as AnotherClass is not
# a child class of MyParent
Loading history...
|
|||
785 | |||
786 | action_parameters = {} |
||
787 | status, output, _ = chain_runner.run(action_parameters=action_parameters) |
||
788 | self.assertEqual(status, LIVEACTION_STATUS_SUCCEEDED) |
||
789 | |||
790 | @mock.patch.object(action_db_util, 'get_action_by_ref', |
||
791 | mock.MagicMock(return_value=ACTION_2)) |
||
792 | @mock.patch.object(action_service, 'request', |
||
793 | return_value=(DummyActionExecution(result={'raw_out': 'published'}), None)) |
||
794 | def test_display_published_is_true_by_default(self, _): |
||
795 | action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack) |
||
796 | |||
797 | expected_published_values = { |
||
798 | 't1_publish_param_1': 'foo1', |
||
799 | 't1_publish_param_2': 'foo2', |
||
800 | 't1_publish_param_3': 'foo3', |
||
801 | 't2_publish_param_1': 'foo4', |
||
802 | 't2_publish_param_2': 'foo5', |
||
803 | 't2_publish_param_3': 'foo6', |
||
804 | 'publish_last_wins': 'bar_last', |
||
805 | } |
||
806 | |||
807 | # 1. display_published is True by default |
||
808 | chain_runner = acr.get_runner() |
||
809 | chain_runner.entry_point = CHAIN_WITH_PUBLISH_2 |
||
810 | chain_runner.action = ACTION_2 |
||
811 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
812 | chain_runner.runner_parameters = {} |
||
813 | chain_runner.pre_run() |
||
814 | |||
815 | action_parameters = {} |
||
816 | _, result, _ = chain_runner.run(action_parameters=action_parameters) |
||
817 | |||
818 | # Assert that the variables are correctly published |
||
819 | self.assertEqual(result['published'], expected_published_values) |
||
820 | |||
821 | # 2. display_published is True by default so end result should be the same |
||
822 | chain_runner = acr.get_runner() |
||
823 | chain_runner.entry_point = CHAIN_WITH_PUBLISH_2 |
||
824 | chain_runner.action = ACTION_2 |
||
825 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
826 | chain_runner.runner_parameters = {'display_published': True} |
||
827 | chain_runner.pre_run() |
||
828 | |||
829 | action_parameters = {} |
||
830 | _, result, _ = chain_runner.run(action_parameters=action_parameters) |
||
831 | |||
832 | # Assert that the variables are correctly published |
||
833 | self.assertEqual(result['published'], expected_published_values) |
||
834 | |||
835 | # 3. display_published is disabled |
||
836 | chain_runner = acr.get_runner() |
||
837 | chain_runner.entry_point = CHAIN_WITH_PUBLISH_2 |
||
838 | chain_runner.action = ACTION_2 |
||
839 | chain_runner.liveaction = LiveActionDB(action=action_ref) |
||
840 | chain_runner.runner_parameters = {'display_published': False} |
||
841 | chain_runner.pre_run() |
||
842 | |||
843 | action_parameters = {} |
||
844 | _, result, _ = chain_runner.run(action_parameters=action_parameters) |
||
845 | |||
846 | self.assertTrue('published' not in result) |
||
847 | self.assertEqual(result.get('published', {}), {}) |
||
848 | |||
849 | @classmethod |
||
850 | def tearDownClass(cls): |
||
851 | FixturesLoader().delete_models_from_db(MODELS) |
||
852 |
Prefixing a member variable
_
is usually regarded as the equivalent of declaring it with protected visibility that exists in other languages. Consequentially, such a member should only be accessed from the same class or a child class: