Passed
Pull Request — master (#3645)
by W
05:13
created

TestActionChainRunner.test_runner_creation()   A

Complexity

Conditions 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
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
        chain_runner.container_service = RunnerContainerService()
504
        chain_runner.pre_run()
505
        chain_runner.run({})
506
        self.assertEqual(request.call_count, 0, 'No call expected.')
507
508
    @mock.patch.object(action_db_util, 'get_action_by_ref',
509
                       mock.MagicMock(return_value=ACTION_1))
510
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
511
    def test_chain_runner_failure_during_param_rendering_single_task(self, request):
512
        # Parameter rendering should result in a top level error which aborts
513
        # the whole chain
514
        chain_runner = acr.get_runner()
515
        chain_runner.entry_point = CHAIN_FIRST_TASK_RENDER_FAIL_PATH
516
        chain_runner.action = ACTION_1
517
        chain_runner.container_service = RunnerContainerService()
518
        chain_runner.pre_run()
519
        status, result, _ = chain_runner.run({})
520
521
        # No tasks ran because rendering of parameters for the first task failed
522
        self.assertEqual(status, LIVEACTION_STATUS_FAILED)
523
        self.assertEqual(result['tasks'], [])
524
        self.assertTrue('error' in result)
525
        self.assertTrue('traceback' in result)
526
        self.assertTrue('Failed to run task "c1". Parameter rendering failed' in result['error'])
527
        self.assertTrue('Traceback' in result['traceback'])
528
529
    @mock.patch.object(action_db_util, 'get_action_by_ref',
530
                       mock.MagicMock(return_value=ACTION_1))
531
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
532
    def test_chain_runner_failure_during_param_rendering_multiple_tasks(self, request):
533
        # Parameter rendering should result in a top level error which aborts
534
        # the whole chain
535
        chain_runner = acr.get_runner()
536
        chain_runner.entry_point = CHAIN_SECOND_TASK_RENDER_FAIL_PATH
537
        chain_runner.action = ACTION_1
538
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
539
        chain_runner.liveaction = LiveActionDB(action=action_ref)
540
        chain_runner.container_service = RunnerContainerService()
541
        chain_runner.pre_run()
542
        status, result, _ = chain_runner.run({})
543
544
        # Verify that only first task has ran
545
        self.assertEqual(status, LIVEACTION_STATUS_FAILED)
546
        self.assertEqual(len(result['tasks']), 1)
547
        self.assertEqual(result['tasks'][0]['name'], 'c1')
548
549
        expected_error = ('Failed rendering value for action parameter "p1" in '
550
                          'task "c2" (template string={{s1}}):')
551
552
        self.assertTrue('error' in result)
553
        self.assertTrue('traceback' in result)
554
        self.assertTrue('Failed to run task "c2". Parameter rendering failed' in result['error'])
555
        self.assertTrue(expected_error in result['error'])
556
        self.assertTrue('Traceback' in result['traceback'])
557
558
    @mock.patch.object(action_db_util, 'get_action_by_ref',
559
                       mock.MagicMock(return_value=ACTION_2))
560
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
561
    def test_chain_runner_typed_params(self, request):
562
        chain_runner = acr.get_runner()
563
        chain_runner.entry_point = CHAIN_TYPED_PARAMS
564
        chain_runner.action = ACTION_2
565
        action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack)
566
        chain_runner.liveaction = LiveActionDB(action=action_ref)
567
        chain_runner.container_service = RunnerContainerService()
568
        chain_runner.pre_run()
569
        chain_runner.run({'s1': 1, 's2': 'two', 's3': 3.14})
570
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
571
        expected_value = {'booltype': True,
572
                          'inttype': 1,
573
                          'numbertype': 3.14,
574
                          'strtype': 'two',
575
                          'arrtype': ['1', 'two'],
576
                          'objtype': {'s2': 'two',
577
                                      'k1': '1'}}
578
        mock_args, _ = request.call_args
579
        self.assertEqual(mock_args[0].parameters, expected_value)
580
581
    @mock.patch.object(action_db_util, 'get_action_by_ref',
582
                       mock.MagicMock(return_value=ACTION_2))
583
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
584
    def test_chain_runner_typed_system_params(self, request):
585
        action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack)
586
        kvps = []
587
        try:
588
            kvps.append(KeyValuePair.add_or_update(KeyValuePairDB(name='a', value='1')))
589
            kvps.append(KeyValuePair.add_or_update(KeyValuePairDB(name='a.b.c', value='two')))
590
            chain_runner = acr.get_runner()
591
            chain_runner.entry_point = CHAIN_SYSTEM_PARAMS
592
            chain_runner.action = ACTION_2
593
            chain_runner.liveaction = LiveActionDB(action=action_ref)
594
            chain_runner.container_service = RunnerContainerService()
595
            chain_runner.pre_run()
596
            chain_runner.run({})
597
            self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
598
            expected_value = {'inttype': 1,
599
                              'strtype': 'two'}
600
            mock_args, _ = request.call_args
601
            self.assertEqual(mock_args[0].parameters, expected_value)
602
        finally:
603
            for kvp in kvps:
604
                KeyValuePair.delete(kvp)
605
606
    @mock.patch.object(action_db_util, 'get_action_by_ref',
607
                       mock.MagicMock(return_value=ACTION_2))
608
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
609
    def test_chain_runner_vars_system_params(self, request):
610
        action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack)
611
        kvps = []
612
        try:
613
            kvps.append(KeyValuePair.add_or_update(KeyValuePairDB(name='a', value='two')))
614
            chain_runner = acr.get_runner()
615
            chain_runner.entry_point = CHAIN_WITH_SYSTEM_VARS
616
            chain_runner.action = ACTION_2
617
            chain_runner.liveaction = LiveActionDB(action=action_ref)
618
            chain_runner.container_service = RunnerContainerService()
619
            chain_runner.pre_run()
620
            chain_runner.run({})
621
            self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
622
            expected_value = {'inttype': 1,
623
                              'strtype': 'two',
624
                              'booltype': True}
625
            mock_args, _ = request.call_args
626
            self.assertEqual(mock_args[0].parameters, expected_value)
627
        finally:
628
            for kvp in kvps:
629
                KeyValuePair.delete(kvp)
630
631
    @mock.patch.object(action_db_util, 'get_action_by_ref',
632
                       mock.MagicMock(return_value=ACTION_2))
633
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
634
    def test_chain_runner_vars_action_params(self, request):
635
        chain_runner = acr.get_runner()
636
        chain_runner.entry_point = CHAIN_WITH_ACTIONPARAM_VARS
637
        chain_runner.action = ACTION_2
638
        action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack)
639
        chain_runner.liveaction = LiveActionDB(action=action_ref)
640
        chain_runner.container_service = RunnerContainerService()
641
        chain_runner.pre_run()
642
        chain_runner.run({'input_a': 'two'})
643
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
644
        expected_value = {'inttype': 1,
645
                          'strtype': 'two',
646
                          'booltype': True}
647
        mock_args, _ = request.call_args
648
        self.assertEqual(mock_args[0].parameters, expected_value)
649
650
    @mock.patch.object(action_db_util, 'get_action_by_ref',
651
                       mock.MagicMock(return_value=ACTION_2))
652
    @mock.patch.object(action_service, 'request',
653
                       return_value=(DummyActionExecution(result={'raw_out': 'published'}), None))
654
    def test_chain_runner_publish(self, request):
655
        chain_runner = acr.get_runner()
656
        chain_runner.entry_point = CHAIN_WITH_PUBLISH
657
        chain_runner.action = ACTION_2
658
        action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack)
659
        chain_runner.liveaction = LiveActionDB(action=action_ref)
660
        chain_runner.container_service = RunnerContainerService()
661
        chain_runner.runner_parameters = {'display_published': True}
662
        chain_runner.pre_run()
663
664
        action_parameters = {'action_param_1': 'test value 1'}
665
        _, result, _ = chain_runner.run(action_parameters=action_parameters)
666
667
        # We also assert that the action parameters are available in the
668
        # "publish" scope
669
        self.assertNotEqual(chain_runner.chain_holder.actionchain, None)
670
        expected_value = {'inttype': 1,
671
                          'strtype': 'published',
672
                          'booltype': True,
673
                          'published_action_param': action_parameters['action_param_1']}
674
        mock_args, _ = request.call_args
675
        self.assertEqual(mock_args[0].parameters, expected_value)
676
        # Assert that the variables are correctly published
677
        self.assertEqual(result['published'],
678
                         {'published_action_param': u'test value 1', 'o1': u'published'})
679
680
    @mock.patch.object(action_db_util, 'get_action_by_ref',
681
                       mock.MagicMock(return_value=ACTION_1))
682
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
683
    def test_chain_runner_publish_param_rendering_failure(self, request):
684
        # Parameter rendering should result in a top level error which aborts
685
        # the whole chain
686
        chain_runner = acr.get_runner()
687
        chain_runner.entry_point = CHAIN_WITH_PUBLISH_PARAM_RENDERING_FAILURE
688
        chain_runner.action = ACTION_1
689
        action_ref = ResourceReference.to_string_reference(name=ACTION_1.name, pack=ACTION_1.pack)
690
        chain_runner.liveaction = LiveActionDB(action=action_ref)
691
        chain_runner.container_service = RunnerContainerService()
692
        chain_runner.pre_run()
693
694
        try:
695
            chain_runner.run({})
696
        except ParameterRenderingFailedException as e:
697
            # TODO: Should we treat this as task error? Right now it bubbles all
698
            # the way up and it's not really consistent with action param
699
            # rendering failure
700
            expected_error = ('Failed rendering value for publish parameter "p1" in '
701
                              'task "c2" (template string={{ not_defined }}):')
702
            self.assertTrue(expected_error in str(e))
703
            pass
0 ignored issues
show
Unused Code introduced by
Unnecessary pass statement
Loading history...
704
        else:
705
            self.fail('Exception was not thrown')
706
707
    @mock.patch.object(action_db_util, 'get_action_by_ref',
708
                       mock.MagicMock(return_value=ACTION_2))
709
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
710
    def test_chain_task_passes_invalid_parameter_type_to_action(self, mock_request):
711
        chain_runner = acr.get_runner()
712
        chain_runner.entry_point = CHAIN_ACTION_INVALID_PARAMETER_TYPE
713
        chain_runner.action = ACTION_2
714
        chain_runner.container_service = RunnerContainerService()
715
        chain_runner.pre_run()
716
717
        action_parameters = {}
718
        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...
719
                        '"arrtype" of type "array"')
720
        self.assertRaisesRegexp(ValueError, expected_msg, chain_runner.run,
721
                                action_parameters=action_parameters)
722
723
    @mock.patch.object(action_db_util, 'get_action_by_ref',
724
                       mock.MagicMock(return_value=None))
725
    @mock.patch.object(action_service, 'request',
726
                       return_value=(DummyActionExecution(result={'raw_out': 'published'}), None))
727
    def test_action_chain_runner_referenced_action_doesnt_exist(self, mock_request):
728
        # Action referenced by a task doesn't exist, should result in a top level error
729
        chain_runner = acr.get_runner()
730
        chain_runner.entry_point = CHAIN_WITH_INVALID_ACTION
731
        chain_runner.action = ACTION_2
732
        chain_runner.container_service = RunnerContainerService()
733
        chain_runner.pre_run()
734
735
        action_parameters = {}
736
        status, output, _ = chain_runner.run(action_parameters=action_parameters)
737
738
        expected_error = ('Failed to run task "c1". Action with reference "wolfpack.a2" '
739
                          'doesn\'t exist.')
740
        self.assertEqual(status, LIVEACTION_STATUS_FAILED)
741
        self.assertTrue(expected_error in output['error'])
742
        self.assertTrue('Traceback' in output['traceback'], output['traceback'])
743
744
    def test_exception_is_thrown_if_both_params_and_parameters_attributes_are_provided(self):
745
        chain_runner = acr.get_runner()
746
        chain_runner.entry_point = CHAIN_ACTION_PARAMS_AND_PARAMETERS_ATTRIBUTE
747
        chain_runner.action = ACTION_2
748
        chain_runner.container_service = RunnerContainerService()
749
750
        expected_msg = ('Either "params" or "parameters" attribute needs to be provided, but '
751
                       'not both')
752
        self.assertRaisesRegexp(runnerexceptions.ActionRunnerPreRunError, expected_msg,
753
                                chain_runner.pre_run)
754
755
    @mock.patch.object(action_db_util, 'get_action_by_ref',
756
                       mock.MagicMock(return_value=ACTION_2))
757
    @mock.patch.object(action_service, 'request', return_value=(DummyActionExecution(), None))
758
    def test_params_and_parameters_attributes_both_work(self, _):
759
        action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack)
760
761
        # "params" attribute used
762
        chain_runner = acr.get_runner()
763
        chain_runner.entry_point = CHAIN_ACTION_PARAMS_ATTRIBUTE
764
        chain_runner.action = ACTION_2
765
        chain_runner.liveaction = LiveActionDB(action=action_ref)
766
        chain_runner.container_service = RunnerContainerService()
767
        chain_runner.pre_run()
768
769
        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...
770
771
        def mock_build_liveaction_object(action_node, resolved_params, parent_context):
772
            # Verify parameters are correctly passed to the action
773
            self.assertEqual(resolved_params, {'pparams': 'v1'})
774
            original_build_liveaction_object(action_node=action_node,
775
                                             resolved_params=resolved_params,
776
                                             parent_context=parent_context)
777
778
        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...
779
780
        action_parameters = {}
781
        status, output, _ = chain_runner.run(action_parameters=action_parameters)
782
        self.assertEqual(status, LIVEACTION_STATUS_SUCCEEDED)
783
784
        # "parameters" attribute used
785
        chain_runner = acr.get_runner()
786
        chain_runner.entry_point = CHAIN_ACTION_PARAMETERS_ATTRIBUTE
787
        chain_runner.action = ACTION_2
788
        chain_runner.liveaction = LiveActionDB(action=action_ref)
789
        chain_runner.container_service = RunnerContainerService()
790
        chain_runner.pre_run()
791
792
        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 771.
Loading history...
793
            # Verify parameters are correctly passed to the action
794
            self.assertEqual(resolved_params, {'pparameters': 'v1'})
795
            original_build_liveaction_object(action_node=action_node,
796
                                             resolved_params=resolved_params,
797
                                             parent_context=parent_context)
798
799
        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...
800
801
        action_parameters = {}
802
        status, output, _ = chain_runner.run(action_parameters=action_parameters)
803
        self.assertEqual(status, LIVEACTION_STATUS_SUCCEEDED)
804
805
    @mock.patch.object(action_db_util, 'get_action_by_ref',
806
                       mock.MagicMock(return_value=ACTION_2))
807
    @mock.patch.object(action_service, 'request',
808
                       return_value=(DummyActionExecution(result={'raw_out': 'published'}), None))
809
    def test_display_published_is_true_by_default(self, _):
810
        action_ref = ResourceReference.to_string_reference(name=ACTION_2.name, pack=ACTION_2.pack)
811
812
        expected_published_values = {
813
            't1_publish_param_1': 'foo1',
814
            't1_publish_param_2': 'foo2',
815
            't1_publish_param_3': 'foo3',
816
            't2_publish_param_1': 'foo4',
817
            't2_publish_param_2': 'foo5',
818
            't2_publish_param_3': 'foo6',
819
            'publish_last_wins': 'bar_last',
820
        }
821
822
        # 1. display_published is True by default
823
        chain_runner = acr.get_runner()
824
        chain_runner.entry_point = CHAIN_WITH_PUBLISH_2
825
        chain_runner.action = ACTION_2
826
        chain_runner.liveaction = LiveActionDB(action=action_ref)
827
        chain_runner.container_service = RunnerContainerService()
828
        chain_runner.runner_parameters = {}
829
        chain_runner.pre_run()
830
831
        action_parameters = {}
832
        _, result, _ = chain_runner.run(action_parameters=action_parameters)
833
834
        # Assert that the variables are correctly published
835
        self.assertEqual(result['published'], expected_published_values)
836
837
        # 2. display_published is True by default so end result should be the same
838
        chain_runner = acr.get_runner()
839
        chain_runner.entry_point = CHAIN_WITH_PUBLISH_2
840
        chain_runner.action = ACTION_2
841
        chain_runner.liveaction = LiveActionDB(action=action_ref)
842
        chain_runner.container_service = RunnerContainerService()
843
        chain_runner.runner_parameters = {'display_published': True}
844
        chain_runner.pre_run()
845
846
        action_parameters = {}
847
        _, result, _ = chain_runner.run(action_parameters=action_parameters)
848
849
        # Assert that the variables are correctly published
850
        self.assertEqual(result['published'], expected_published_values)
851
852
        # 3. display_published is disabled
853
        chain_runner = acr.get_runner()
854
        chain_runner.entry_point = CHAIN_WITH_PUBLISH_2
855
        chain_runner.action = ACTION_2
856
        chain_runner.liveaction = LiveActionDB(action=action_ref)
857
        chain_runner.container_service = RunnerContainerService()
858
        chain_runner.runner_parameters = {'display_published': False}
859
        chain_runner.pre_run()
860
861
        action_parameters = {}
862
        _, result, _ = chain_runner.run(action_parameters=action_parameters)
863
864
        self.assertTrue('published' not in result)
865
        self.assertEqual(result.get('published', {}), {})
866
867
    @classmethod
868
    def tearDownClass(cls):
869
        FixturesLoader().delete_models_from_db(MODELS)
870