Test Failed
Push — master ( e380d0...f5671d )
by W
02:58
created

action_chain_runner/tests/unit/test_actionchain.py (7 issues)

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