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

mistral_v2/tests/unit/test_mistral_v2_callback.py (1 issue)

1
# -*- coding: UTF-8 -*-
2
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
3
# contributor license agreements.  See the NOTICE file distributed with
4
# this work for additional information regarding copyright ownership.
5
# The ASF licenses this file to You under the Apache License, Version 2.0
6
# (the "License"); you may not use this file except in compliance with
7
# the License.  You may obtain a copy of the License at
8
#
9
#     http://www.apache.org/licenses/LICENSE-2.0
10
#
11
# Unless required by applicable law or agreed to in writing, software
12
# distributed under the License is distributed on an "AS IS" BASIS,
13
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
# See the License for the specific language governing permissions and
15
# limitations under the License.
16
17
from __future__ import absolute_import
18
19
import six
20
import mock
21
import requests
22
from mock import call
23
24
from mistralclient.api.v2 import action_executions
25
from oslo_config import cfg
26
27
# XXX: actionsensor import depends on config being setup.
28
import st2tests.config as tests_config
29
from six.moves import range
0 ignored issues
show
Bug Best Practice introduced by
This seems to re-define the built-in range.

It is generally discouraged to redefine built-ins as this makes code very hard to read.

Loading history...
30
tests_config.parse_args()
31
32
from st2common.bootstrap import actionsregistrar
33
from st2common.bootstrap import runnersregistrar
34
from st2common.constants import action as action_constants
35
from st2common.models.db.liveaction import LiveActionDB
36
from st2common.persistence.liveaction import LiveAction
37
from st2common.runners import base as runners
38
from st2common.services import action as action_service
39
from st2common.transport.liveaction import LiveActionPublisher
40
from st2common.transport.publishers import CUDPublisher
41
from st2common.util import loader
42
from st2tests import DbTestCase
43
from st2tests import fixturesloader
44
from st2tests.mocks.liveaction import MockLiveActionPublisher
45
46
47
MISTRAL_RUNNER_NAME = 'mistral_v2'
48
TEST_PACK = 'mistral_tests'
49
TEST_PACK_PATH = fixturesloader.get_fixtures_packs_base_path() + '/' + TEST_PACK
50
51
PACKS = [
52
    TEST_PACK_PATH,
53
    fixturesloader.get_fixtures_packs_base_path() + '/core'
54
]
55
56
if six.PY2:
57
    NON_EMPTY_RESULT = 'non-empty'
58
else:
59
    NON_EMPTY_RESULT = u'non-empty'
60
61
62
@mock.patch.object(
63
    CUDPublisher,
64
    'publish_update',
65
    mock.MagicMock(return_value=None))
66
@mock.patch.object(
67
    CUDPublisher,
68
    'publish_create',
69
    mock.MagicMock(side_effect=MockLiveActionPublisher.publish_create))
70
@mock.patch.object(
71
    LiveActionPublisher,
72
    'publish_state',
73
    mock.MagicMock(side_effect=MockLiveActionPublisher.publish_state))
74
class MistralRunnerCallbackTest(DbTestCase):
75
76
    @classmethod
77
    def setUpClass(cls):
78
        super(MistralRunnerCallbackTest, cls).setUpClass()
79
80
        # Override the retry configuration here otherwise st2tests.config.parse_args
81
        # in DbTestCase.setUpClass will reset these overrides.
82
        cfg.CONF.set_override('retry_exp_msec', 100, group='mistral')
83
        cfg.CONF.set_override('retry_exp_max_msec', 200, group='mistral')
84
        cfg.CONF.set_override('retry_stop_max_msec', 200, group='mistral')
85
        cfg.CONF.set_override('api_url', 'http://0.0.0.0:9101', group='auth')
86
87
        # Register runners.
88
        runnersregistrar.register_runners()
89
90
        # Register test pack(s).
91
        actions_registrar = actionsregistrar.ActionsRegistrar(
92
            use_pack_cache=False,
93
            fail_on_failure=True
94
        )
95
96
        for pack in PACKS:
97
            actions_registrar.register_from_pack(pack)
98
99
        # Get an instance of the callback module and reference to mistral status map
100
        cls.callback_module = loader.register_callback_module(MISTRAL_RUNNER_NAME)
101
        cls.callback_class = cls.callback_module.get_instance()
102
        cls.status_map = cls.callback_module.STATUS_MAP
103
104
    @classmethod
105
    def get_runner_class(cls, package_name, module_name):
106
        return runners.get_runner(package_name, module_name).__class__
107
108
    def get_liveaction_instance(self, status=None, result=None):
109
        callback = {
110
            'source': MISTRAL_RUNNER_NAME,
111
            'url': 'http://127.0.0.1:8989/v2/action_executions/12345'
112
        }
113
114
        liveaction = LiveActionDB(
115
            action='core.local',
116
            parameters={'cmd': 'uname -a'},
117
            callback=callback,
118
            context=dict()
119
        )
120
121
        if status:
122
            liveaction.status = status
123
124
        if result:
125
            liveaction.result = result
126
127
        return liveaction
128
129
    def test_callback_handler_status_map(self):
130
        # Ensure all StackStorm status are mapped otherwise leads to zombie workflow.
131
        self.assertListEqual(sorted(self.status_map.keys()),
132
                             sorted(action_constants.LIVEACTION_STATUSES))
133
134
    @mock.patch.object(
135
        action_executions.ActionExecutionManager, 'update',
136
        mock.MagicMock(return_value=None))
137
    def test_callback_handler_with_result_as_text(self):
138
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
139
        result = '<html></html>'
140
        liveaction = self.get_liveaction_instance(status, result)
141
        self.callback_class.callback(liveaction)
142
143
        action_executions.ActionExecutionManager.update.assert_called_with(
144
            '12345',
145
            state='SUCCESS',
146
            output='<html></html>'
147
        )
148
149
    @mock.patch.object(
150
        action_executions.ActionExecutionManager, 'update',
151
        mock.MagicMock(return_value=None))
152
    def test_callback_handler_with_result_as_dict(self):
153
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
154
        result = {'a': 1}
155
        liveaction = self.get_liveaction_instance(status, result)
156
        self.callback_class.callback(liveaction)
157
158
        action_executions.ActionExecutionManager.update.assert_called_with(
159
            '12345',
160
            state='SUCCESS',
161
            output='{"a": 1}'
162
        )
163
164
    @mock.patch.object(
165
        action_executions.ActionExecutionManager, 'update',
166
        mock.MagicMock(return_value=None))
167
    def test_callback_handler_with_result_as_json_str(self):
168
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
169
        result = '{"a": 1}'
170
        liveaction = self.get_liveaction_instance(status, result)
171
        self.callback_class.callback(liveaction)
172
173
        action_executions.ActionExecutionManager.update.assert_called_with(
174
            '12345',
175
            state='SUCCESS',
176
            output='{"a": 1}'
177
        )
178
179
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
180
        result = "{'a': 1}"
181
        liveaction = self.get_liveaction_instance(status, result)
182
        self.callback_class.callback(liveaction)
183
184
        action_executions.ActionExecutionManager.update.assert_called_with(
185
            '12345',
186
            state='SUCCESS',
187
            output='{"a": 1}'
188
        )
189
190
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
191
        result = u"{'a': 1}"
192
        liveaction = self.get_liveaction_instance(status, result)
193
        self.callback_class.callback(liveaction)
194
195
        action_executions.ActionExecutionManager.update.assert_called_with(
196
            '12345',
197
            state='SUCCESS',
198
            output='{"a": 1}'
199
        )
200
201
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
202
        result = "{u'a': u'xyz'}"
203
        liveaction = self.get_liveaction_instance(status, result)
204
        self.callback_class.callback(liveaction)
205
206
        action_executions.ActionExecutionManager.update.assert_called_with(
207
            '12345',
208
            state='SUCCESS',
209
            output='{"a": "xyz"}'
210
        )
211
212
    @mock.patch.object(
213
        action_executions.ActionExecutionManager, 'update',
214
        mock.MagicMock(return_value=None))
215
    def test_callback_handler_with_result_as_list(self):
216
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
217
        result = ["a", "b", "c"]
218
        liveaction = self.get_liveaction_instance(status, result)
219
        self.callback_class.callback(liveaction)
220
221
        action_executions.ActionExecutionManager.update.assert_called_with(
222
            '12345',
223
            state='SUCCESS',
224
            output='["a", "b", "c"]'
225
        )
226
227
    @mock.patch.object(
228
        action_executions.ActionExecutionManager, 'update',
229
        mock.MagicMock(return_value=None))
230
    def test_callback_handler_with_result_as_list_str(self):
231
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
232
        result = '["a", "b", "c"]'
233
        liveaction = self.get_liveaction_instance(status, result)
234
        self.callback_class.callback(liveaction)
235
236
        action_executions.ActionExecutionManager.update.assert_called_with(
237
            '12345',
238
            state='SUCCESS',
239
            output='["a", "b", "c"]'
240
        )
241
242
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
243
        result = u'["a", "b", "c"]'
244
        liveaction = self.get_liveaction_instance(status, result)
245
        self.callback_class.callback(liveaction)
246
247
        action_executions.ActionExecutionManager.update.assert_called_with(
248
            '12345',
249
            state='SUCCESS',
250
            output='["a", "b", "c"]'
251
        )
252
253
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
254
        result = '[u"a", "b", "c"]'
255
        liveaction = self.get_liveaction_instance(status, result)
256
        self.callback_class.callback(liveaction)
257
258
        action_executions.ActionExecutionManager.update.assert_called_with(
259
            '12345',
260
            state='SUCCESS',
261
            output='["a", "b", "c"]'
262
        )
263
264
    @mock.patch.object(
265
        action_executions.ActionExecutionManager, 'update',
266
        mock.MagicMock(return_value=None))
267
    def test_callback_handler_with_result_unicode_str(self):
268
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
269
        result = '什麼'
270
        liveaction = self.get_liveaction_instance(status, result)
271
        self.callback_class.callback(liveaction)
272
273
        if six.PY2:
274
            expected_output = '\\u4ec0\\u9ebc'
275
        else:
276
            expected_output = '什麼'
277
278
        action_executions.ActionExecutionManager.update.assert_called_with(
279
            '12345',
280
            state='SUCCESS',
281
            output=expected_output
282
        )
283
284
    @mock.patch.object(
285
        action_executions.ActionExecutionManager, 'update',
286
        mock.MagicMock(return_value=None))
287
    def test_callback_handler_with_result_unicode_encoded_as_ascii_str(self):
288
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
289
        result = '\u4ec0\u9ebc'
290
        liveaction = self.get_liveaction_instance(status, result)
291
        self.callback_class.callback(liveaction)
292
293
        if six.PY2:
294
            expected_output = '\\\\u4ec0\\\\u9ebc'
295
        else:
296
            expected_output = '什麼'
297
298
        action_executions.ActionExecutionManager.update.assert_called_with(
299
            '12345',
300
            state='SUCCESS',
301
            output=expected_output
302
        )
303
304
    @mock.patch.object(
305
        action_executions.ActionExecutionManager, 'update',
306
        mock.MagicMock(return_value=None))
307
    def test_callback_handler_with_result_unicode_encoded_as_type(self):
308
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
309
        result = u'\u4ec0\u9ebc'
310
        liveaction = self.get_liveaction_instance(status, result)
311
        self.callback_class.callback(liveaction)
312
313
        if six.PY2:
314
            expected_output = '\\u4ec0\\u9ebc'
315
        else:
316
            expected_output = '什麼'
317
318
        action_executions.ActionExecutionManager.update.assert_called_with(
319
            '12345',
320
            state='SUCCESS',
321
            output=expected_output
322
        )
323
324
    @mock.patch.object(
325
        action_executions.ActionExecutionManager, 'update',
326
        mock.MagicMock(return_value=None))
327
    def test_callback_handler_with_result_as_list_with_unicode_str(self):
328
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
329
        result = ['\u4ec0\u9ebc']
330
        liveaction = self.get_liveaction_instance(status, result)
331
        self.callback_class.callback(liveaction)
332
333
        if six.PY2:
334
            expected_output = '["\\\\u4ec0\\\\u9ebc"]'
335
        else:
336
            expected_output = '["\\u4ec0\\u9ebc"]'
337
338
        action_executions.ActionExecutionManager.update.assert_called_with(
339
            '12345',
340
            state='SUCCESS',
341
            output=expected_output
342
        )
343
344
    @mock.patch.object(
345
        action_executions.ActionExecutionManager, 'update',
346
        mock.MagicMock(return_value=None))
347
    def test_callback_handler_with_result_as_list_with_unicode_type(self):
348
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
349
        result = [u'\u4ec0\u9ebc']
350
        liveaction = self.get_liveaction_instance(status, result)
351
        self.callback_class.callback(liveaction)
352
353
        if six.PY2:
354
            expected_output = '["\\\\u4ec0\\\\u9ebc"]'
355
        else:
356
            expected_output = '["\\u4ec0\\u9ebc"]'
357
358
        action_executions.ActionExecutionManager.update.assert_called_with(
359
            '12345',
360
            state='SUCCESS',
361
            output=expected_output
362
        )
363
364
    @mock.patch.object(
365
        action_executions.ActionExecutionManager, 'update',
366
        mock.MagicMock(return_value=None))
367
    def test_callback_handler_with_result_as_dict_with_unicode_str(self):
368
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
369
        result = {'a': '\u4ec0\u9ebc'}
370
        liveaction = self.get_liveaction_instance(status, result)
371
        self.callback_class.callback(liveaction)
372
373
        if six.PY2:
374
            expected_output = '{"a": "\\\\u4ec0\\\\u9ebc"}'
375
        else:
376
            expected_output = '{"a": "\\u4ec0\\u9ebc"}'
377
378
        action_executions.ActionExecutionManager.update.assert_called_with(
379
            '12345',
380
            state='SUCCESS',
381
            output=expected_output
382
        )
383
384
    @mock.patch.object(
385
        action_executions.ActionExecutionManager, 'update',
386
        mock.MagicMock(return_value=None))
387
    def test_callback_handler_with_result_as_dict_with_unicode_type(self):
388
        status = action_constants.LIVEACTION_STATUS_SUCCEEDED
389
        result = {'a': u'\u4ec0\u9ebc'}
390
        liveaction = self.get_liveaction_instance(status, result)
391
        self.callback_class.callback(liveaction)
392
393
        if six.PY2:
394
            expected_output = '{"a": "\\\\u4ec0\\\\u9ebc"}'
395
        else:
396
            expected_output = '{"a": "\\u4ec0\\u9ebc"}'
397
398
        action_executions.ActionExecutionManager.update.assert_called_with(
399
            '12345',
400
            state='SUCCESS',
401
            output=expected_output
402
        )
403
404
    @mock.patch.object(
405
        action_executions.ActionExecutionManager, 'update',
406
        mock.MagicMock(return_value=None))
407
    def test_callback_success_state(self):
408
        local_runner_cls = self.get_runner_class('local_runner', 'local_shell_command_runner')
409
        local_run_result = (action_constants.LIVEACTION_STATUS_SUCCEEDED, NON_EMPTY_RESULT, None)
410
        local_runner_cls.run = mock.Mock(return_value=local_run_result)
411
        expected_mistral_status = self.status_map[local_run_result[0]]
412
        liveaction = self.get_liveaction_instance()
413
        liveaction, execution = action_service.request(liveaction)
414
        liveaction = LiveAction.get_by_id(str(liveaction.id))
415
416
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_SUCCEEDED)
417
418
        action_executions.ActionExecutionManager.update.assert_called_with(
419
            '12345', state=expected_mistral_status, output=NON_EMPTY_RESULT)
420
421
    @mock.patch.object(
422
        action_executions.ActionExecutionManager, 'update',
423
        mock.MagicMock(return_value=None))
424
    def test_callback_incomplete_state(self):
425
        local_runner_cls = self.get_runner_class('local_runner', 'local_shell_command_runner')
426
        local_run_result = (action_constants.LIVEACTION_STATUS_RUNNING, NON_EMPTY_RESULT, None)
427
        local_runner_cls.run = mock.Mock(return_value=local_run_result)
428
        liveaction = self.get_liveaction_instance()
429
        liveaction, execution = action_service.request(liveaction)
430
        liveaction = LiveAction.get_by_id(str(liveaction.id))
431
432
        self.assertEqual(liveaction.status, local_run_result[0])
433
        self.assertFalse(action_executions.ActionExecutionManager.update.called)
434
435
    @mock.patch.object(
436
        action_executions.ActionExecutionManager, 'update',
437
        mock.MagicMock(return_value=None))
438
    def test_callback_canceling_state(self):
439
        local_runner_cls = self.get_runner_class('local_runner', 'local_shell_command_runner')
440
        local_run_result = (action_constants.LIVEACTION_STATUS_CANCELING, NON_EMPTY_RESULT, None)
441
        local_runner_cls.run = mock.Mock(return_value=local_run_result)
442
        local_cancel_result = (action_constants.LIVEACTION_STATUS_CANCELING, NON_EMPTY_RESULT, None)
443
        local_runner_cls.cancel = mock.Mock(return_value=local_cancel_result)
444
        liveaction = self.get_liveaction_instance()
445
        liveaction, execution = action_service.request(liveaction)
446
        liveaction = LiveAction.get_by_id(str(liveaction.id))
447
448
        self.assertEqual(liveaction.status, local_cancel_result[0])
449
450
        action_executions.ActionExecutionManager.update.assert_not_called()
451
452
    @mock.patch.object(
453
        action_executions.ActionExecutionManager, 'update',
454
        mock.MagicMock(return_value=None))
455
    def test_callback_canceled_state(self):
456
        local_runner_cls = self.get_runner_class('local_runner', 'local_shell_command_runner')
457
        local_run_result = (action_constants.LIVEACTION_STATUS_CANCELED, NON_EMPTY_RESULT, None)
458
        local_runner_cls.run = mock.Mock(return_value=local_run_result)
459
        expected_mistral_status = self.status_map[local_run_result[0]]
460
        liveaction = self.get_liveaction_instance()
461
        liveaction, execution = action_service.request(liveaction)
462
        liveaction = LiveAction.get_by_id(str(liveaction.id))
463
464
        self.assertEqual(liveaction.status, local_run_result[0])
465
466
        action_executions.ActionExecutionManager.update.assert_called_with(
467
            '12345', state=expected_mistral_status, output=NON_EMPTY_RESULT)
468
469
    @mock.patch.object(
470
        action_executions.ActionExecutionManager, 'update',
471
        mock.MagicMock(return_value=None))
472
    def test_callback_pausing_state(self):
473
        local_runner_cls = self.get_runner_class('local_runner', 'local_shell_command_runner')
474
        local_run_result = (action_constants.LIVEACTION_STATUS_PAUSING, NON_EMPTY_RESULT, None)
475
        local_runner_cls.run = mock.Mock(return_value=local_run_result)
476
        local_pause_result = (action_constants.LIVEACTION_STATUS_PAUSING, NON_EMPTY_RESULT, None)
477
        local_runner_cls.pause = mock.Mock(return_value=local_pause_result)
478
        liveaction = self.get_liveaction_instance()
479
        liveaction, execution = action_service.request(liveaction)
480
        liveaction = LiveAction.get_by_id(str(liveaction.id))
481
482
        self.assertEqual(liveaction.status, local_pause_result[0])
483
484
        action_executions.ActionExecutionManager.update.assert_not_called()
485
486
    @mock.patch.object(
487
        action_executions.ActionExecutionManager, 'update',
488
        mock.MagicMock(return_value=None))
489
    def test_callback_paused_state(self):
490
        local_runner_cls = self.get_runner_class('local_runner', 'local_shell_command_runner')
491
        local_run_result = (action_constants.LIVEACTION_STATUS_PAUSED, NON_EMPTY_RESULT, None)
492
        local_runner_cls.run = mock.Mock(return_value=local_run_result)
493
        expected_mistral_status = self.status_map[local_run_result[0]]
494
        liveaction = self.get_liveaction_instance()
495
        liveaction, execution = action_service.request(liveaction)
496
        liveaction = LiveAction.get_by_id(str(liveaction.id))
497
498
        self.assertEqual(liveaction.status, local_run_result[0])
499
500
        action_executions.ActionExecutionManager.update.assert_called_with(
501
            '12345', state=expected_mistral_status, output=NON_EMPTY_RESULT)
502
503
    @mock.patch.object(
504
        action_executions.ActionExecutionManager, 'update',
505
        mock.MagicMock(return_value=None))
506
    def test_callback_resuming_state(self):
507
        local_runner_cls = self.get_runner_class('local_runner', 'local_shell_command_runner')
508
        local_run_result = (action_constants.LIVEACTION_STATUS_RESUMING, NON_EMPTY_RESULT, None)
509
        local_runner_cls.run = mock.Mock(return_value=local_run_result)
510
        local_resume_result = (action_constants.LIVEACTION_STATUS_RUNNING, NON_EMPTY_RESULT, None)
511
        local_runner_cls.resume = mock.Mock(return_value=local_resume_result)
512
        liveaction = self.get_liveaction_instance()
513
        liveaction, execution = action_service.request(liveaction)
514
        liveaction = LiveAction.get_by_id(str(liveaction.id))
515
516
        self.assertEqual(liveaction.status, local_resume_result[0])
517
        self.assertFalse(action_executions.ActionExecutionManager.update.called)
518
519
    @mock.patch.object(
520
        action_executions.ActionExecutionManager, 'update',
521
        mock.MagicMock(side_effect=[
522
            requests.exceptions.ConnectionError(),
523
            None]))
524
    def test_callback_retry(self):
525
        local_runner_cls = self.get_runner_class('local_runner', 'local_shell_command_runner')
526
        local_run_result = (action_constants.LIVEACTION_STATUS_SUCCEEDED, NON_EMPTY_RESULT, None)
527
        local_runner_cls.run = mock.Mock(return_value=local_run_result)
528
        liveaction = self.get_liveaction_instance()
529
        liveaction, execution = action_service.request(liveaction)
530
        liveaction = LiveAction.get_by_id(str(liveaction.id))
531
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_SUCCEEDED)
532
533
        calls = [call('12345', state='SUCCESS', output=NON_EMPTY_RESULT) for i in range(0, 2)]
534
        action_executions.ActionExecutionManager.update.assert_has_calls(calls)
535
536
    @mock.patch.object(
537
        action_executions.ActionExecutionManager, 'update',
538
        mock.MagicMock(side_effect=[
539
            requests.exceptions.ConnectionError(),
540
            requests.exceptions.ConnectionError(),
541
            requests.exceptions.ConnectionError(),
542
            requests.exceptions.ConnectionError(),
543
            None]))
544
    def test_callback_retry_exhausted(self):
545
        local_runner_cls = self.get_runner_class('local_runner', 'local_shell_command_runner')
546
        local_run_result = (action_constants.LIVEACTION_STATUS_SUCCEEDED, NON_EMPTY_RESULT, None)
547
        local_runner_cls.run = mock.Mock(return_value=local_run_result)
548
        liveaction = self.get_liveaction_instance()
549
        liveaction, execution = action_service.request(liveaction)
550
        liveaction = LiveAction.get_by_id(str(liveaction.id))
551
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_SUCCEEDED)
552
553
        # This test initially setup mock for action_executions.ActionExecutionManager.update
554
        # to fail the first 4 times and return success on the 5th times. The max attempts
555
        # is set to 3. We expect only 3 calls to pass thru the update method.
556
        calls = [call('12345', state='SUCCESS', output=NON_EMPTY_RESULT) for i in range(0, 2)]
557
        action_executions.ActionExecutionManager.update.assert_has_calls(calls)
558