Passed
Pull Request — master (#3640)
by Lakshmi
06:19
created

test_chain_runner_action_exception()   B

Complexity

Conditions 3

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
c 0
b 0
f 0
dl 0
loc 24
rs 8.9713
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
import mock
17
import action_chain_runner as acr
18
from st2actions.container.service import RunnerContainerService
19
from st2common.constants.action import LIVEACTION_STATUS_RUNNING
20
from st2common.constants.action import LIVEACTION_STATUS_SUCCEEDED
21
from st2common.constants.action import LIVEACTION_STATUS_CANCELED
22
from st2common.constants.action import LIVEACTION_STATUS_TIMED_OUT
23
from st2common.constants.action import LIVEACTION_STATUS_FAILED
24
from st2common.exceptions import actionrunner as runnerexceptions
25
from st2common.models.api.notification import NotificationsHelper
26
from st2common.models.db.liveaction import LiveActionDB
27
from st2common.models.db.keyvalue import KeyValuePairDB
28
from st2common.models.system.common import ResourceReference
29
from st2common.persistence.keyvalue import KeyValuePair
30
from st2common.persistence.runner import RunnerType
31
from st2common.services import action as action_service
32
from st2common.util import action_db as action_db_util
33
from st2common.exceptions.action import ParameterRenderingFailedException
34
from st2tests import DbTestCase
35
from st2tests.fixturesloader import FixturesLoader
36
37
38
class DummyActionExecution(object):
39
    def __init__(self, status=LIVEACTION_STATUS_SUCCEEDED, result=''):
40
        self.id = None
41
        self.status = status
42
        self.result = result
43
44
45
FIXTURES_PACK = 'generic'
46
47
TEST_MODELS = {
48
    'actions': ['a1.yaml', 'a2.yaml', 'action_4_action_context_param.yaml'],
49
    'runners': ['testrunner1.yaml']
50
}
51
52
MODELS = FixturesLoader().load_models(fixtures_pack=FIXTURES_PACK,
53
                                      fixtures_dict=TEST_MODELS)
54
ACTION_1 = MODELS['actions']['a1.yaml']
55
ACTION_2 = MODELS['actions']['a2.yaml']
56
ACTION_3 = MODELS['actions']['action_4_action_context_param.yaml']
57
RUNNER = MODELS['runners']['testrunner1.yaml']
58
59
CHAIN_1_PATH = FixturesLoader().get_fixture_file_path_abs(
60
    FIXTURES_PACK, 'actionchains', 'chain1.yaml')
61
CHAIN_2_PATH = FixturesLoader().get_fixture_file_path_abs(
62
    FIXTURES_PACK, 'actionchains', 'chain2.yaml')
63
CHAIN_ACTION_CALL_NO_PARAMS_PATH = FixturesLoader().get_fixture_file_path_abs(
64
    FIXTURES_PACK, 'actionchains', 'chain_action_call_no_params.yaml')
65
CHAIN_NO_DEFAULT = FixturesLoader().get_fixture_file_path_abs(
66
    FIXTURES_PACK, 'actionchains', 'no_default_chain.yaml')
67
CHAIN_NO_DEFAULT_2 = FixturesLoader().get_fixture_file_path_abs(
68
    FIXTURES_PACK, 'actionchains', 'no_default_chain_2.yaml')
69
CHAIN_BAD_DEFAULT = FixturesLoader().get_fixture_file_path_abs(
70
    FIXTURES_PACK, 'actionchains', 'bad_default_chain.yaml')
71
CHAIN_BROKEN_ON_SUCCESS_PATH_STATIC_TASK_NAME = FixturesLoader().get_fixture_file_path_abs(
72
    FIXTURES_PACK, 'actionchains', 'chain_broken_on_success_path_static_task_name.yaml')
73
CHAIN_BROKEN_ON_FAILURE_PATH_STATIC_TASK_NAME = FixturesLoader().get_fixture_file_path_abs(
74
    FIXTURES_PACK, 'actionchains', 'chain_broken_on_failure_path_static_task_name.yaml')
75
CHAIN_FIRST_TASK_RENDER_FAIL_PATH = FixturesLoader().get_fixture_file_path_abs(
76
    FIXTURES_PACK, 'actionchains', 'chain_first_task_parameter_render_fail.yaml')
77
CHAIN_SECOND_TASK_RENDER_FAIL_PATH = FixturesLoader().get_fixture_file_path_abs(
78
    FIXTURES_PACK, 'actionchains', 'chain_second_task_parameter_render_fail.yaml')
79
CHAIN_LIST_TEMP_PATH = FixturesLoader().get_fixture_file_path_abs(
80
    FIXTURES_PACK, 'actionchains', 'chain_list_template.yaml')
81
CHAIN_DICT_TEMP_PATH = FixturesLoader().get_fixture_file_path_abs(
82
    FIXTURES_PACK, 'actionchains', 'chain_dict_template.yaml')
83
CHAIN_DEP_INPUT = FixturesLoader().get_fixture_file_path_abs(
84
    FIXTURES_PACK, 'actionchains', 'chain_dependent_input.yaml')
85
CHAIN_DEP_RESULTS_INPUT = FixturesLoader().get_fixture_file_path_abs(
86
    FIXTURES_PACK, 'actionchains', 'chain_dep_result_input.yaml')
87
MALFORMED_CHAIN_PATH = FixturesLoader().get_fixture_file_path_abs(
88
    FIXTURES_PACK, 'actionchains', 'malformedchain.yaml')
89
CHAIN_TYPED_PARAMS = FixturesLoader().get_fixture_file_path_abs(
90
    FIXTURES_PACK, 'actionchains', 'chain_typed_params.yaml')
91
CHAIN_SYSTEM_PARAMS = FixturesLoader().get_fixture_file_path_abs(
92
    FIXTURES_PACK, 'actionchains', 'chain_typed_system_params.yaml')
93
CHAIN_WITH_ACTIONPARAM_VARS = FixturesLoader().get_fixture_file_path_abs(
94
    FIXTURES_PACK, 'actionchains', 'chain_with_actionparam_vars.yaml')
95
CHAIN_WITH_SYSTEM_VARS = FixturesLoader().get_fixture_file_path_abs(
96
    FIXTURES_PACK, 'actionchains', 'chain_with_system_vars.yaml')
97
CHAIN_WITH_PUBLISH = FixturesLoader().get_fixture_file_path_abs(
98
    FIXTURES_PACK, 'actionchains', 'chain_with_publish.yaml')
99
CHAIN_WITH_PUBLISH_2 = FixturesLoader().get_fixture_file_path_abs(
100
    FIXTURES_PACK, 'actionchains', 'chain_with_publish_2.yaml')
101
CHAIN_WITH_PUBLISH_PARAM_RENDERING_FAILURE = FixturesLoader().get_fixture_file_path_abs(
102
    FIXTURES_PACK, 'actionchains', 'chain_publish_params_rendering_failure.yaml')
103
CHAIN_WITH_INVALID_ACTION = FixturesLoader().get_fixture_file_path_abs(
104
    FIXTURES_PACK, 'actionchains', 'chain_with_invalid_action.yaml')
105
CHAIN_ACTION_PARAMS_AND_PARAMETERS_ATTRIBUTE = FixturesLoader().get_fixture_file_path_abs(
106
    FIXTURES_PACK, 'actionchains', 'chain_action_params_and_parameters.yaml')
107
CHAIN_ACTION_PARAMS_ATTRIBUTE = FixturesLoader().get_fixture_file_path_abs(
108
    FIXTURES_PACK, 'actionchains', 'chain_action_params_attribute.yaml')
109
CHAIN_ACTION_PARAMETERS_ATTRIBUTE = FixturesLoader().get_fixture_file_path_abs(
110
    FIXTURES_PACK, 'actionchains', 'chain_action_parameters_attribute.yaml')
111
CHAIN_ACTION_INVALID_PARAMETER_TYPE = FixturesLoader().get_fixture_file_path_abs(
112
    FIXTURES_PACK, 'actionchains', 'chain_invalid_parameter_type_passed_to_action.yaml')
113
114
CHAIN_NOTIFY_API = {'notify': {'on-complete': {'message': 'foo happened.'}}}
115
CHAIN_NOTIFY_DB = NotificationsHelper.to_model(CHAIN_NOTIFY_API)
116
117
118
@mock.patch.object(
119
    action_db_util,
120
    'get_runnertype_by_name',
121
    mock.MagicMock(return_value=RUNNER))
122
@mock.patch.object(
123
    action_service,
124
    'is_action_canceled_or_canceling',
125
    mock.MagicMock(return_value=False))
126
@mock.patch.object(
127
    action_service,
128
    'is_action_paused_or_pausing',
129
    mock.MagicMock(return_value=False))
130
class TestActionChainRunner(DbTestCase):
131
132
    def test_runner_creation(self):
133
        runner = acr.get_runner()
134
        self.assertTrue(runner)
135
        self.assertTrue(runner.runner_id)
136
137
    def test_malformed_chain(self):
138
        try:
139
            chain_runner = acr.get_runner()
140
            chain_runner.entry_point = MALFORMED_CHAIN_PATH
141
            chain_runner.action = ACTION_1
142
            chain_runner.container_service = RunnerContainerService()
143
            chain_runner.pre_run()
144
            self.assertTrue(False, 'Expected pre_run to fail.')
145
        except runnerexceptions.ActionRunnerPreRunError:
146
            self.assertTrue(True)
147
148
    @mock.patch.object(action_db_util, 'get_action_by_ref',
149
                       mock.MagicMock(return_value=ACTION_1))
150
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
151
    def test_chain_runner_success_path(self, request):
152
        chain_runner = acr.get_runner()
153
        chain_runner.entry_point = CHAIN_1_PATH
154
        chain_runner.action = ACTION_1
155
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
156
        chain_runner.liveaction = LiveActionDB(action=action_ref)
157
        chain_runner.liveaction.notify = CHAIN_NOTIFY_DB
158
        chain_runner.container_service = RunnerContainerService()
159
        chain_runner.pre_run()
160
        chain_runner.run({})
161
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
162
        # based on the chain the callcount is known to be 3. Not great but works.
163
        self.assertEqual(request.call_count, 3)
164
165
    @mock.patch.object(action_db_util, 'get_action_by_ref',
166
                       mock.MagicMock(return_value=ACTION_1))
167
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
168
    def test_chain_runner_chain_second_task_times_out(self, request):
169
        # Second task in the chain times out so the action chain status should be timeout
170
        chain_runner = acr.get_runner()
171
        chain_runner.entry_point = CHAIN_2_PATH
172
        chain_runner.action = ACTION_1
173
174
        original_run_action = chain_runner._run_action
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _run_action was declared protected and should not be accessed from this context.

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:

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...
175
176
        def mock_run_action(*args, **kwargs):
177
            original_live_action = args[0]
178
            liveaction = original_run_action(*args, **kwargs)
179
            if original_live_action.action == 'wolfpack.a2':
180
                # Mock a timeout for second task
181
                liveaction.status = LIVEACTION_STATUS_TIMED_OUT
182
            return liveaction
183
184
        chain_runner._run_action = mock_run_action
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _run_action was declared protected and should not be accessed from this context.

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:

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...
185
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
186
        chain_runner.liveaction = LiveActionDB(action=action_ref)
187
        chain_runner.container_service = RunnerContainerService()
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
Coding Style Best Practice introduced by
It seems like _run_action was declared protected and should not be accessed from this context.

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:

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
Coding Style Best Practice introduced by
It seems like _run_action was declared protected and should not be accessed from this context.

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:

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.container_service = RunnerContainerService()
222
        chain_runner.pre_run()
223
        status, _, _ = chain_runner.run({})
224
225
        self.assertEqual(status, LIVEACTION_STATUS_CANCELED)
226
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
227
        # Chain count should be 2 since the last task doesn't get called since the second one was
228
        # canceled
229
        self.assertEqual(request.call_count, 2)
230
231
    @mock.patch.object(action_db_util, 'get_action_by_ref',
232
                       mock.MagicMock(return_value=ACTION_1))
233
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
234
    def test_chain_runner_success_task_action_call_with_no_params(self, request):
235
        # Make sure that the runner doesn't explode if task definition contains
236
        # no "params" section
237
        chain_runner = acr.get_runner()
238
        chain_runner.entry_point = CHAIN_ACTION_CALL_NO_PARAMS_PATH
239
        chain_runner.action = ACTION_1
240
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
241
        chain_runner.liveaction = LiveActionDB(action=action_ref)
242
        chain_runner.liveaction.notify = CHAIN_NOTIFY_DB
243
        chain_runner.container_service = RunnerContainerService()
244
        chain_runner.pre_run()
245
        chain_runner.run({})
246
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
247
        # based on the chain the callcount is known to be 3. Not great but works.
248
        self.assertEqual(request.call_count, 3)
249
250
    @mock.patch.object(action_db_util, 'get_action_by_ref',
251
                       mock.MagicMock(return_value=ACTION_1))
252
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
253
    def test_chain_runner_no_default(self, request):
254
        chain_runner = acr.get_runner()
255
        chain_runner.entry_point = CHAIN_NO_DEFAULT
256
        chain_runner.action = ACTION_1
257
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
258
        chain_runner.liveaction = LiveActionDB(action=action_ref)
259
        chain_runner.container_service = RunnerContainerService()
260
        chain_runner.pre_run()
261
        chain_runner.run({})
262
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
263
        # In case of this chain default_node is the first_node.
264
        default_node = chain_runner.chain_holder.actionchain.default
265
        first_node = chain_runner.chain_holder.actionchain.chain[0]
266
        self.assertEqual(default_node, first_node.name)
267
        # based on the chain the callcount is known to be 3. Not great but works.
268
        self.assertEqual(request.call_count, 3)
269
270
    @mock.patch.object(action_db_util, 'get_action_by_ref',
271
                       mock.MagicMock(return_value=ACTION_1))
272
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
273
    def test_chain_runner_no_default_multiple_options(self, request):
274
        # subtle difference is that when there are multiple possible default nodes
275
        # the order per chain definition may not be preseved. This is really a
276
        # poorly formatted chain but we still the best attempt to work.
277
        chain_runner = acr.get_runner()
278
        chain_runner.entry_point = CHAIN_NO_DEFAULT_2
279
        chain_runner.action = ACTION_1
280
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
281
        chain_runner.liveaction = LiveActionDB(action=action_ref)
282
        chain_runner.container_service = RunnerContainerService()
283
        chain_runner.pre_run()
284
        chain_runner.run({})
285
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
286
        # In case of this chain default_node is the first_node.
287
        default_node = chain_runner.chain_holder.actionchain.default
288
        first_node = chain_runner.chain_holder.actionchain.chain[0]
289
        self.assertEqual(default_node, first_node.name)
290
        # based on the chain the callcount is known to be 2.
291
        self.assertEqual(request.call_count, 2)
292
293
    @mock.patch.object(action_db_util, 'get_action_by_ref',
294
                       mock.MagicMock(return_value=ACTION_1))
295
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
296
    def test_chain_runner_bad_default(self, request):
297
        chain_runner = acr.get_runner()
298
        chain_runner.entry_point = CHAIN_BAD_DEFAULT
299
        chain_runner.action = ACTION_1
300
        chain_runner.container_service = RunnerContainerService()
301
        expected_msg = 'Unable to find node with name "bad_default" referenced in "default".'
302
        self.assertRaisesRegexp(runnerexceptions.ActionRunnerPreRunError,
303
                                expected_msg, chain_runner.pre_run)
304
305
    @mock.patch('eventlet.sleep', mock.MagicMock())
306
    @mock.patch.object(action_db_util, 'get_liveaction_by_id', mock.MagicMock(
307
        return_value=DummyActionExecution()))
308
    @mock.patch.object(action_db_util, 'get_action_by_ref',
309
                       mock.MagicMock(return_value=ACTION_1))
310
    @mock.patch.object(action_service, 'request',
311
                       return_value=(DummyActionExecution(status=LIVEACTION_STATUS_RUNNING), None))
312
    def test_chain_runner_success_path_with_wait(self, request):
313
        chain_runner = acr.get_runner()
314
        chain_runner.entry_point = CHAIN_1_PATH
315
        chain_runner.action = ACTION_1
316
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
317
        chain_runner.liveaction = LiveActionDB(action=action_ref)
318
        chain_runner.container_service = RunnerContainerService()
319
        chain_runner.pre_run()
320
        chain_runner.run({})
321
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
322
        # based on the chain the callcount is known to be 3. Not great but works.
323
        self.assertEqual(request.call_count, 3)
324
325
    @mock.patch.object(action_db_util, 'get_action_by_ref',
326
                       mock.MagicMock(return_value=ACTION_1))
327
    @mock.patch.object(action_service, 'request',
328
                       return_value=(DummyActionExecution(status=LIVEACTION_STATUS_FAILED), None))
329
    def test_chain_runner_failure_path(self, request):
330
        chain_runner = acr.get_runner()
331
        chain_runner.entry_point = CHAIN_1_PATH
332
        chain_runner.action = ACTION_1
333
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
334
        chain_runner.liveaction = LiveActionDB(action=action_ref)
335
        chain_runner.container_service = RunnerContainerService()
336
        chain_runner.pre_run()
337
        status, _, _ = chain_runner.run({})
338
        self.assertEqual(status, LIVEACTION_STATUS_FAILED)
339
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
340
        # based on the chain the callcount is known to be 2. Not great but works.
341
        self.assertEqual(request.call_count, 2)
342
343
    @mock.patch.object(action_db_util, 'get_action_by_ref',
344
                       mock.MagicMock(return_value=ACTION_1))
345
    @mock.patch.object(action_service, 'request',
346
                       return_value=(DummyActionExecution(), None))
347
    def test_chain_runner_broken_on_success_path_static_task_name(self, request):
348
        chain_runner = acr.get_runner()
349
        chain_runner.entry_point = CHAIN_BROKEN_ON_SUCCESS_PATH_STATIC_TASK_NAME
350
        chain_runner.action = ACTION_1
351
        chain_runner.container_service = RunnerContainerService()
352
353
        expected_msg = ('Unable to find node with name "c5" referenced in "on-success" '
354
                        'in task "c2"')
355
        self.assertRaisesRegexp(runnerexceptions.ActionRunnerPreRunError,
356
                                expected_msg, chain_runner.pre_run)
357
358
    @mock.patch.object(action_db_util, 'get_action_by_ref',
359
                       mock.MagicMock(return_value=ACTION_1))
360
    @mock.patch.object(action_service, 'request',
361
                       return_value=(DummyActionExecution(), None))
362
    def test_chain_runner_broken_on_failure_path_static_task_name(self, request):
363
        chain_runner = acr.get_runner()
364
        chain_runner.entry_point = CHAIN_BROKEN_ON_FAILURE_PATH_STATIC_TASK_NAME
365
        chain_runner.action = ACTION_1
366
        chain_runner.container_service = RunnerContainerService()
367
368
        expected_msg = ('Unable to find node with name "c6" referenced in "on-failure" '
369
                        'in task "c2"')
370
        self.assertRaisesRegexp(runnerexceptions.ActionRunnerPreRunError,
371
                                expected_msg, chain_runner.pre_run)
372
373
    @mock.patch.object(action_db_util, 'get_action_by_ref',
374
                       mock.MagicMock(return_value=ACTION_1))
375
    @mock.patch.object(action_service, 'request', side_effect=RuntimeError('Test Failure.'))
376
    def test_chain_runner_action_exception(self, request):
377
        chain_runner = acr.get_runner()
378
        chain_runner.entry_point = CHAIN_1_PATH
379
        chain_runner.action = ACTION_1
380
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
381
        chain_runner.liveaction = LiveActionDB(action=action_ref)
382
        chain_runner.container_service = RunnerContainerService()
383
        chain_runner.pre_run()
384
        status, results, _ = chain_runner.run({})
385
        self.assertEqual(status, LIVEACTION_STATUS_FAILED)
386
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
387
388
        # based on the chain the callcount is known to be 2. Not great but works.
389
        self.assertEqual(request.call_count, 2)
390
391
        error_count = 0
392
        for task_result in results['tasks']:
393
            if task_result['result'].get('error', None):
394
                error_count += 1
395
396
        self.assertEqual(error_count, 2)
397
398
    @mock.patch.object(action_db_util, 'get_action_by_ref',
399
                       mock.MagicMock(return_value=ACTION_1))
400
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
401
    def test_chain_runner_str_param_temp(self, request):
402
        chain_runner = acr.get_runner()
403
        chain_runner.entry_point = CHAIN_FIRST_TASK_RENDER_FAIL_PATH
404
        chain_runner.action = ACTION_1
405
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
406
        chain_runner.liveaction = LiveActionDB(action=action_ref)
407
        chain_runner.container_service = RunnerContainerService()
408
        chain_runner.pre_run()
409
        chain_runner.run({'s1': 1, 's2': 2, 's3': 3, 's4': 4})
410
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
411
        mock_args, _ = request.call_args
412
        self.assertEqual(mock_args[0].parameters, {"p1": "1"})
413
414
    @mock.patch.object(action_db_util, 'get_action_by_ref',
415
                       mock.MagicMock(return_value=ACTION_1))
416
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
417
    def test_chain_runner_list_param_temp(self, request):
418
        chain_runner = acr.get_runner()
419
        chain_runner.entry_point = CHAIN_LIST_TEMP_PATH
420
        chain_runner.action = ACTION_1
421
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
422
        chain_runner.liveaction = LiveActionDB(action=action_ref)
423
        chain_runner.container_service = RunnerContainerService()
424
        chain_runner.pre_run()
425
        chain_runner.run({'s1': 1, 's2': 2, 's3': 3, 's4': 4})
426
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
427
        mock_args, _ = request.call_args
428
        self.assertEqual(mock_args[0].parameters, {"p1": "[2, 3, 4]"})
429
430
    @mock.patch.object(action_db_util, 'get_action_by_ref',
431
                       mock.MagicMock(return_value=ACTION_1))
432
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
433
    def test_chain_runner_dict_param_temp(self, request):
434
        chain_runner = acr.get_runner()
435
        chain_runner.entry_point = CHAIN_DICT_TEMP_PATH
436
        chain_runner.action = ACTION_1
437
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
438
        chain_runner.liveaction = LiveActionDB(action=action_ref)
439
        chain_runner.container_service = RunnerContainerService()
440
        chain_runner.pre_run()
441
        chain_runner.run({'s1': 1, 's2': 2, 's3': 3, 's4': 4})
442
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
443
        expected_value = {"p1": {"p1.3": "[3, 4]", "p1.2": "2", "p1.1": "1"}}
444
        mock_args, _ = request.call_args
445
        self.assertEqual(mock_args[0].parameters, expected_value)
446
447
    @mock.patch.object(action_db_util, 'get_action_by_ref',
448
                       mock.MagicMock(return_value=ACTION_1))
449
    @mock.patch.object(action_service, 'request',
450
                       return_value=(DummyActionExecution(result={'o1': '1'}), None))
451
    def test_chain_runner_dependent_param_temp(self, request):
452
        chain_runner = acr.get_runner()
453
        chain_runner.entry_point = CHAIN_DEP_INPUT
454
        chain_runner.action = ACTION_1
455
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
456
        chain_runner.liveaction = LiveActionDB(action=action_ref)
457
        chain_runner.container_service = RunnerContainerService()
458
        chain_runner.pre_run()
459
        chain_runner.run({'s1': 1, 's2': 2, 's3': 3, 's4': 4})
460
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
461
        expected_values = [{u'p1': u'1'},
462
                           {u'p1': u'1'},
463
                           {u'p2': u'1', u'p3': u'1', u'p1': u'1'}]
464
        # Each of the call_args must be one of
465
        for call_args in request.call_args_list:
466
            self.assertTrue(call_args[0][0].parameters in expected_values)
467
            expected_values.remove(call_args[0][0].parameters)
468
        self.assertEqual(len(expected_values), 0, 'Not all expected values received.')
469
470
    @mock.patch.object(action_db_util, 'get_action_by_ref',
471
                       mock.MagicMock(return_value=ACTION_1))
472
    @mock.patch.object(action_service, 'request',
473
                       return_value=(DummyActionExecution(result={'o1': '1'}), None))
474
    def test_chain_runner_dependent_results_param(self, request):
475
        chain_runner = acr.get_runner()
476
        chain_runner.entry_point = CHAIN_DEP_RESULTS_INPUT
477
        chain_runner.action = ACTION_1
478
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
479
        chain_runner.liveaction = LiveActionDB(action=action_ref)
480
        chain_runner.container_service = RunnerContainerService()
481
        chain_runner.pre_run()
482
        chain_runner.run({'s1': 1})
483
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
484
        expected_values = [{u'p1': u'1'},
485
                           {u'p1': u'1'},
486
                           {u'out': u"{'c2': {'o1': '1'}, 'c1': {'o1': '1'}}"}]
487
        # Each of the call_args must be one of
488
        self.assertEqual(request.call_count, 3)
489
        for call_args in request.call_args_list:
490
            self.assertTrue(call_args[0][0].parameters in expected_values)
491
            expected_values.remove(call_args[0][0].parameters)
492
        self.assertEqual(len(expected_values), 0, 'Not all expected values received.')
493
494
    @mock.patch.object(action_db_util, 'get_action_by_ref',
495
                       mock.MagicMock(return_value=ACTION_1))
496
    @mock.patch.object(RunnerType, 'get_by_name',
497
                       mock.MagicMock(return_value=RUNNER))
498
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
499
    def test_chain_runner_missing_param_temp(self, request):
500
        chain_runner = acr.get_runner()
501
        chain_runner.entry_point = CHAIN_FIRST_TASK_RENDER_FAIL_PATH
502
        chain_runner.action = ACTION_1
503
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
504
        chain_runner.liveaction = LiveActionDB(action=action_ref)
505
        chain_runner.container_service = RunnerContainerService()
506
        chain_runner.pre_run()
507
        chain_runner.run({})
508
        self.assertEqual(request.call_count, 0, 'No call expected.')
509
510
    @mock.patch.object(action_db_util, 'get_action_by_ref',
511
                       mock.MagicMock(return_value=ACTION_1))
512
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
513
    def test_chain_runner_failure_during_param_rendering_single_task(self, request):
514
        # Parameter rendering should result in a top level error which aborts
515
        # the whole chain
516
        chain_runner = acr.get_runner()
517
        chain_runner.entry_point = CHAIN_FIRST_TASK_RENDER_FAIL_PATH
518
        chain_runner.action = ACTION_1
519
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
520
        chain_runner.liveaction = LiveActionDB(action=action_ref)
521
        chain_runner.container_service = RunnerContainerService()
522
        chain_runner.pre_run()
523
        status, result, _ = chain_runner.run({})
524
525
        # No tasks ran because rendering of parameters for the first task failed
526
        self.assertEqual(status, LIVEACTION_STATUS_FAILED)
527
        self.assertEqual(result['tasks'], [])
528
        self.assertTrue('error' in result)
529
        self.assertTrue('traceback' in result)
530
        self.assertTrue('Failed to run task "c1". Parameter rendering failed' in result['error'])
531
        self.assertTrue('Traceback' in result['traceback'])
532
533
    @mock.patch.object(action_db_util, 'get_action_by_ref',
534
                       mock.MagicMock(return_value=ACTION_1))
535
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
536
    def test_chain_runner_failure_during_param_rendering_multiple_tasks(self, request):
537
        # Parameter rendering should result in a top level error which aborts
538
        # the whole chain
539
        chain_runner = acr.get_runner()
540
        chain_runner.entry_point = CHAIN_SECOND_TASK_RENDER_FAIL_PATH
541
        chain_runner.action = ACTION_1
542
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
543
        chain_runner.liveaction = LiveActionDB(action=action_ref)
544
        chain_runner.container_service = RunnerContainerService()
545
        chain_runner.pre_run()
546
        status, result, _ = chain_runner.run({})
547
548
        # Verify that only first task has ran
549
        self.assertEqual(status, LIVEACTION_STATUS_FAILED)
550
        self.assertEqual(len(result['tasks']), 1)
551
        self.assertEqual(result['tasks'][0]['name'], 'c1')
552
553
        expected_error = ('Failed rendering value for action parameter "p1" in '
554
                          'task "c2" (template string={{s1}}):')
555
556
        self.assertTrue('error' in result)
557
        self.assertTrue('traceback' in result)
558
        self.assertTrue('Failed to run task "c2". Parameter rendering failed' in result['error'])
559
        self.assertTrue(expected_error in result['error'])
560
        self.assertTrue('Traceback' in result['traceback'])
561
562
    @mock.patch.object(action_db_util, 'get_action_by_ref',
563
                       mock.MagicMock(return_value=ACTION_2))
564
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
565
    def test_chain_runner_typed_params(self, request):
566
        chain_runner = acr.get_runner()
567
        chain_runner.entry_point = CHAIN_TYPED_PARAMS
568
        chain_runner.action = ACTION_2
569
        action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack)
570
        chain_runner.liveaction = LiveActionDB(action=action_ref)
571
        chain_runner.container_service = RunnerContainerService()
572
        chain_runner.pre_run()
573
        chain_runner.run({'s1': 1, 's2': 'two', 's3': 3.14})
574
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
575
        expected_value = {'booltype': True,
576
                          'inttype': 1,
577
                          'numbertype': 3.14,
578
                          'strtype': 'two',
579
                          'arrtype': ['1', 'two'],
580
                          'objtype': {'s2': 'two',
581
                                      'k1': '1'}}
582
        mock_args, _ = request.call_args
583
        self.assertEqual(mock_args[0].parameters, expected_value)
584
585
    @mock.patch.object(action_db_util, 'get_action_by_ref',
586
                       mock.MagicMock(return_value=ACTION_2))
587
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
588
    def test_chain_runner_typed_system_params(self, request):
589
        action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack)
590
        kvps = []
591
        try:
592
            kvps.append(KeyValuePair.add_or_update(KeyValuePairDB(name='a', value='1')))
593
            kvps.append(KeyValuePair.add_or_update(KeyValuePairDB(name='a.b.c', value='two')))
594
            chain_runner = acr.get_runner()
595
            chain_runner.entry_point = CHAIN_SYSTEM_PARAMS
596
            chain_runner.action = ACTION_2
597
            chain_runner.liveaction = LiveActionDB(action=action_ref)
598
            chain_runner.container_service = RunnerContainerService()
599
            chain_runner.pre_run()
600
            chain_runner.run({})
601
            self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
602
            expected_value = {'inttype': 1,
603
                              'strtype': 'two'}
604
            mock_args, _ = request.call_args
605
            self.assertEqual(mock_args[0].parameters, expected_value)
606
        finally:
607
            for kvp in kvps:
608
                KeyValuePair.delete(kvp)
609
610
    @mock.patch.object(action_db_util, 'get_action_by_ref',
611
                       mock.MagicMock(return_value=ACTION_2))
612
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
613
    def test_chain_runner_vars_system_params(self, request):
614
        action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack)
615
        kvps = []
616
        try:
617
            kvps.append(KeyValuePair.add_or_update(KeyValuePairDB(name='a', value='two')))
618
            chain_runner = acr.get_runner()
619
            chain_runner.entry_point = CHAIN_WITH_SYSTEM_VARS
620
            chain_runner.action = ACTION_2
621
            chain_runner.liveaction = LiveActionDB(action=action_ref)
622
            chain_runner.container_service = RunnerContainerService()
623
            chain_runner.pre_run()
624
            chain_runner.run({})
625
            self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
626
            expected_value = {'inttype': 1,
627
                              'strtype': 'two',
628
                              'booltype': True}
629
            mock_args, _ = request.call_args
630
            self.assertEqual(mock_args[0].parameters, expected_value)
631
        finally:
632
            for kvp in kvps:
633
                KeyValuePair.delete(kvp)
634
635
    @mock.patch.object(action_db_util, 'get_action_by_ref',
636
                       mock.MagicMock(return_value=ACTION_2))
637
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
638
    def test_chain_runner_vars_action_params(self, request):
639
        chain_runner = acr.get_runner()
640
        chain_runner.entry_point = CHAIN_WITH_ACTIONPARAM_VARS
641
        chain_runner.action = ACTION_2
642
        action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack)
643
        chain_runner.liveaction = LiveActionDB(action=action_ref)
644
        chain_runner.container_service = RunnerContainerService()
645
        chain_runner.pre_run()
646
        chain_runner.run({'input_a': 'two'})
647
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
648
        expected_value = {'inttype': 1,
649
                          'strtype': 'two',
650
                          'booltype': True}
651
        mock_args, _ = request.call_args
652
        self.assertEqual(mock_args[0].parameters, expected_value)
653
654
    @mock.patch.object(action_db_util, 'get_action_by_ref',
655
                       mock.MagicMock(return_value=ACTION_2))
656
    @mock.patch.object(action_service, 'request',
657
                       return_value=(DummyActionExecution(result={'raw_out': 'published'}), None))
658
    def test_chain_runner_publish(self, request):
659
        chain_runner = acr.get_runner()
660
        chain_runner.entry_point = CHAIN_WITH_PUBLISH
661
        chain_runner.action = ACTION_2
662
        action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack)
663
        chain_runner.liveaction = LiveActionDB(action=action_ref)
664
        chain_runner.container_service = RunnerContainerService()
665
        chain_runner.runner_parameters = {'display_published': True}
666
        chain_runner.pre_run()
667
668
        action_parameters = {'action_param_1': 'test value 1'}
669
        _, result, _ = chain_runner.run(action_parameters=action_parameters)
670
671
        # We also assert that the action parameters are available in the
672
        # "publish" scope
673
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
674
        expected_value = {'inttype': 1,
675
                          'strtype': 'published',
676
                          'booltype': True,
677
                          'published_action_param': action_parameters['action_param_1']}
678
        mock_args, _ = request.call_args
679
        self.assertEqual(mock_args[0].parameters, expected_value)
680
        # Assert that the variables are correctly published
681
        self.assertEqual(result['published'],
682
                         {'published_action_param': u'test value 1', 'o1': u'published'})
683
684
    @mock.patch.object(action_db_util, 'get_action_by_ref',
685
                       mock.MagicMock(return_value=ACTION_1))
686
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
687
    def test_chain_runner_publish_param_rendering_failure(self, request):
688
        # Parameter rendering should result in a top level error which aborts
689
        # the whole chain
690
        chain_runner = acr.get_runner()
691
        chain_runner.entry_point = CHAIN_WITH_PUBLISH_PARAM_RENDERING_FAILURE
692
        chain_runner.action = ACTION_1
693
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
694
        chain_runner.liveaction = LiveActionDB(action=action_ref)
695
        chain_runner.container_service = RunnerContainerService()
696
        chain_runner.pre_run()
697
698
        try:
699
            chain_runner.run({})
700
        except ParameterRenderingFailedException as e:
701
            # TODO: Should we treat this as task error? Right now it bubbles all
702
            # the way up and it's not really consistent with action param
703
            # rendering failure
704
            expected_error = ('Failed rendering value for publish parameter "p1" in '
705
                              'task "c2" (template string={{ not_defined }}):')
706
            self.assertTrue(expected_error in str(e))
707
            pass
0 ignored issues
show
Unused Code introduced by
Unnecessary pass statement
Loading history...
708
        else:
709
            self.fail('Exception was not thrown')
710
711
    @mock.patch.object(action_db_util, 'get_action_by_ref',
712
                       mock.MagicMock(return_value=ACTION_2))
713
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
714
    def test_chain_task_passes_invalid_parameter_type_to_action(self, mock_request):
715
        chain_runner = acr.get_runner()
716
        chain_runner.entry_point = CHAIN_ACTION_INVALID_PARAMETER_TYPE
717
        chain_runner.action = ACTION_2
718
        chain_runner.container_service = RunnerContainerService()
719
        chain_runner.pre_run()
720
721
        action_parameters = {}
722
        expected_msg = ('Failed to cast value "stringnotanarray" \(type: str\) for parameter '
0 ignored issues
show
Bug introduced by
A suspicious escape sequence \( was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
Bug introduced by
A suspicious escape sequence \) was found. Did you maybe forget to add an r prefix?

Escape sequences in Python are generally interpreted according to rules similar to standard C. Only if strings are prefixed with r or R are they interpreted as regular expressions.

The escape sequence that was used indicates that you might have intended to write a regular expression.

Learn more about the available escape sequences. in the Python documentation.

Loading history...
723
                        '"arrtype" of type "array"')
724
        self.assertRaisesRegexp(ValueError, expected_msg, chain_runner.run,
725
                                action_parameters=action_parameters)
726
727
    @mock.patch.object(action_db_util, 'get_action_by_ref',
728
                       mock.MagicMock(return_value=None))
729
    @mock.patch.object(action_service, 'request',
730
                       return_value=(DummyActionExecution(result={'raw_out': 'published'}), None))
731
    def test_action_chain_runner_referenced_action_doesnt_exist(self, mock_request):
732
        # Action referenced by a task doesn't exist, should result in a top level error
733
        chain_runner = acr.get_runner()
734
        chain_runner.entry_point = CHAIN_WITH_INVALID_ACTION
735
        chain_runner.action = ACTION_2
736
        action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack)
737
        chain_runner.liveaction = LiveActionDB(action=action_ref)
738
        chain_runner.container_service = RunnerContainerService()
739
        chain_runner.pre_run()
740
741
        action_parameters = {}
742
        status, output, _ = chain_runner.run(action_parameters=action_parameters)
743
744
        expected_error = ('Failed to run task "c1". Action with reference "wolfpack.a2" '
745
                          'doesn\'t exist.')
746
        self.assertEqual(status, LIVEACTION_STATUS_FAILED)
747
        self.assertTrue(expected_error in output['error'])
748
        self.assertTrue('Traceback' in output['traceback'], output['traceback'])
749
750
    def test_exception_is_thrown_if_both_params_and_parameters_attributes_are_provided(self):
751
        chain_runner = acr.get_runner()
752
        chain_runner.entry_point = CHAIN_ACTION_PARAMS_AND_PARAMETERS_ATTRIBUTE
753
        chain_runner.action = ACTION_2
754
        chain_runner.container_service = RunnerContainerService()
755
756
        expected_msg = ('Either "params" or "parameters" attribute needs to be provided, but '
757
                       'not both')
758
        self.assertRaisesRegexp(runnerexceptions.ActionRunnerPreRunError, expected_msg,
759
                                chain_runner.pre_run)
760
761
    @mock.patch.object(action_db_util, 'get_action_by_ref',
762
                       mock.MagicMock(return_value=ACTION_2))
763
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
764
    def test_params_and_parameters_attributes_both_work(self, _):
765
        action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack)
766
767
        # "params" attribute used
768
        chain_runner = acr.get_runner()
769
        chain_runner.entry_point = CHAIN_ACTION_PARAMS_ATTRIBUTE
770
        chain_runner.action = ACTION_2
771
        chain_runner.liveaction = LiveActionDB(action=action_ref)
772
        chain_runner.container_service = RunnerContainerService()
773
        chain_runner.pre_run()
774
775
        original_build_liveaction_object = chain_runner._build_liveaction_object
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _build_liveaction_object was declared protected and should not be accessed from this context.

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:

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...
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, {'pparams': '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
Coding Style Best Practice introduced by
It seems like _build_liveaction_object was declared protected and should not be accessed from this context.

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:

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
        # "parameters" attribute used
791
        chain_runner = acr.get_runner()
792
        chain_runner.entry_point = CHAIN_ACTION_PARAMETERS_ATTRIBUTE
793
        chain_runner.action = ACTION_2
794
        chain_runner.liveaction = LiveActionDB(action=action_ref)
795
        chain_runner.container_service = RunnerContainerService()
796
        chain_runner.pre_run()
797
798
        def mock_build_liveaction_object(action_node, resolved_params, parent_context):
0 ignored issues
show
Bug introduced by
This function was already defined on line 777.
Loading history...
799
            # Verify parameters are correctly passed to the action
800
            self.assertEqual(resolved_params, {'pparameters': 'v1'})
801
            original_build_liveaction_object(action_node=action_node,
802
                                             resolved_params=resolved_params,
803
                                             parent_context=parent_context)
804
805
        chain_runner._build_liveaction_object = mock_build_liveaction_object
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like _build_liveaction_object was declared protected and should not be accessed from this context.

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:

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...
806
807
        action_parameters = {}
808
        status, output, _ = chain_runner.run(action_parameters=action_parameters)
809
        self.assertEqual(status, LIVEACTION_STATUS_SUCCEEDED)
810
811
    @mock.patch.object(action_db_util, 'get_action_by_ref',
812
                       mock.MagicMock(return_value=ACTION_2))
813
    @mock.patch.object(action_service, 'request',
814
                       return_value=(DummyActionExecution(result={'raw_out': 'published'}), None))
815
    def test_display_published_is_true_by_default(self, _):
816
        action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack)
817
818
        expected_published_values = {
819
            't1_publish_param_1': 'foo1',
820
            't1_publish_param_2': 'foo2',
821
            't1_publish_param_3': 'foo3',
822
            't2_publish_param_1': 'foo4',
823
            't2_publish_param_2': 'foo5',
824
            't2_publish_param_3': 'foo6',
825
            'publish_last_wins': 'bar_last',
826
        }
827
828
        # 1. display_published is True by default
829
        chain_runner = acr.get_runner()
830
        chain_runner.entry_point = CHAIN_WITH_PUBLISH_2
831
        chain_runner.action = ACTION_2
832
        chain_runner.liveaction = LiveActionDB(action=action_ref)
833
        chain_runner.container_service = RunnerContainerService()
834
        chain_runner.runner_parameters = {}
835
        chain_runner.pre_run()
836
837
        action_parameters = {}
838
        _, result, _ = chain_runner.run(action_parameters=action_parameters)
839
840
        # Assert that the variables are correctly published
841
        self.assertEqual(result['published'], expected_published_values)
842
843
        # 2. display_published is True by default so end result should be the same
844
        chain_runner = acr.get_runner()
845
        chain_runner.entry_point = CHAIN_WITH_PUBLISH_2
846
        chain_runner.action = ACTION_2
847
        chain_runner.liveaction = LiveActionDB(action=action_ref)
848
        chain_runner.container_service = RunnerContainerService()
849
        chain_runner.runner_parameters = {'display_published': True}
850
        chain_runner.pre_run()
851
852
        action_parameters = {}
853
        _, result, _ = chain_runner.run(action_parameters=action_parameters)
854
855
        # Assert that the variables are correctly published
856
        self.assertEqual(result['published'], expected_published_values)
857
858
        # 3. display_published is disabled
859
        chain_runner = acr.get_runner()
860
        chain_runner.entry_point = CHAIN_WITH_PUBLISH_2
861
        chain_runner.action = ACTION_2
862
        chain_runner.liveaction = LiveActionDB(action=action_ref)
863
        chain_runner.container_service = RunnerContainerService()
864
        chain_runner.runner_parameters = {'display_published': False}
865
        chain_runner.pre_run()
866
867
        action_parameters = {}
868
        _, result, _ = chain_runner.run(action_parameters=action_parameters)
869
870
        self.assertTrue('published' not in result)
871
        self.assertEqual(result.get('published', {}), {})
872
873
    @classmethod
874
    def tearDownClass(cls):
875
        FixturesLoader().delete_models_from_db(MODELS)
876