Test Failed
Push — master ( f5671d...de3728 )
by W
01:28
created

orquesta_runner/tests/unit/test_error_handling.py (1 issue)

Labels
Severity
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 mock
19
import six
20
21
from orquesta import states as wf_states
22
23
import st2tests
24
25
# XXX: actionsensor import depends on config being setup.
26
import st2tests.config as tests_config
27
tests_config.parse_args()
28
29
from tests.unit import base
30
31
from st2common.bootstrap import actionsregistrar
32
from st2common.bootstrap import runnersregistrar
33
from st2common.constants import action as ac_const
34
from st2common.models.db import liveaction as lv_db_models
35
from st2common.persistence import execution as ex_db_access
36
from st2common.persistence import liveaction as lv_db_access
37
from st2common.persistence import workflow as wf_db_access
38
from st2common.runners import base as runners
39
from st2common.services import action as ac_svc
40
from st2common.services import workflows as wf_svc
41
from st2common.transport import liveaction as lv_ac_xport
42
from st2common.transport import workflow as wf_ex_xport
43
from st2common.transport import publishers
44
from st2tests.mocks import liveaction as mock_lv_ac_xport
45
from st2tests.mocks import workflow as mock_wf_ex_xport
46
47
48
TEST_PACK = 'orquesta_tests'
49
TEST_PACK_PATH = st2tests.fixturesloader.get_fixtures_packs_base_path() + '/' + TEST_PACK
50
51
PACKS = [
52
    TEST_PACK_PATH,
53
    st2tests.fixturesloader.get_fixtures_packs_base_path() + '/core'
54
]
55
56
57
@mock.patch.object(
58
    publishers.CUDPublisher,
59
    'publish_update',
60
    mock.MagicMock(return_value=None))
61
@mock.patch.object(
62
    lv_ac_xport.LiveActionPublisher,
63
    'publish_create',
64
    mock.MagicMock(side_effect=mock_lv_ac_xport.MockLiveActionPublisher.publish_create))
65
@mock.patch.object(
66
    lv_ac_xport.LiveActionPublisher,
67
    'publish_state',
68
    mock.MagicMock(side_effect=mock_lv_ac_xport.MockLiveActionPublisher.publish_state))
69
@mock.patch.object(
70
    wf_ex_xport.WorkflowExecutionPublisher,
71
    'publish_create',
72
    mock.MagicMock(side_effect=mock_wf_ex_xport.MockWorkflowExecutionPublisher.publish_create))
73
@mock.patch.object(
74
    wf_ex_xport.WorkflowExecutionPublisher,
75
    'publish_state',
76
    mock.MagicMock(side_effect=mock_wf_ex_xport.MockWorkflowExecutionPublisher.publish_state))
77
class OrquestaErrorHandlingTest(st2tests.DbTestCase):
78
79
    @classmethod
80
    def setUpClass(cls):
81
        super(OrquestaErrorHandlingTest, cls).setUpClass()
82
83
        # Register runners.
84
        runnersregistrar.register_runners()
85
86
        # Register test pack(s).
87
        actions_registrar = actionsregistrar.ActionsRegistrar(
88
            use_pack_cache=False,
89
            fail_on_failure=True
90
        )
91
92
        for pack in PACKS:
93
            actions_registrar.register_from_pack(pack)
94
95
    @classmethod
96
    def get_runner_class(cls, runner_name):
97
        return runners.get_runner(runner_name, runner_name).__class__
98
99
    def sort_wf_runtime_errors(self, errors):
100
        return sorted(errors, key=lambda x: x.get('task_id', None))
101
102
    def test_fail_inspection(self):
103
        expected_errors = [
104
            {
105
                'type': 'content',
106
                'message': 'The action "std.noop" is not registered in the database.',
107
                'schema_path': 'properties.tasks.patternProperties.^\w+$.properties.action',
0 ignored issues
show
A suspicious escape sequence \w 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...
108
                'spec_path': 'tasks.task3.action'
109
            },
110
            {
111
                'type': 'context',
112
                'language': 'yaql',
113
                'expression': '<% ctx().foobar %>',
114
                'message': 'Variable "foobar" is referenced before assignment.',
115
                'schema_path': 'properties.tasks.patternProperties.^\w+$.properties.input',
116
                'spec_path': 'tasks.task1.input',
117
            },
118
            {
119
                'type': 'expression',
120
                'language': 'yaql',
121
                'expression': '<% <% succeeded() %>',
122
                'message': (
123
                    'Parse error: unexpected \'<\' at '
124
                    'position 0 of expression \'<% succeeded()\''
125
                ),
126
                'schema_path': (
127
                    'properties.tasks.patternProperties.^\w+$.'
128
                    'properties.next.items.properties.when'
129
                ),
130
                'spec_path': 'tasks.task2.next[0].when'
131
            },
132
            {
133
                'type': 'syntax',
134
                'message': '[{\'cmd\': \'echo <% ctx().macro %>\'}] is not of type \'object\'',
135
                'schema_path': 'properties.tasks.patternProperties.^\w+$.properties.input.type',
136
                'spec_path': 'tasks.task2.input'
137
            }
138
        ]
139
140
        wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-inspection.yaml')
141
        lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'])
142
        lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db)
143
        lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id))
144
145
        self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED)
146
        self.assertIn('errors', lv_ac_db.result)
147
        self.assertListEqual(lv_ac_db.result['errors'], expected_errors)
148
149
    def test_fail_input_rendering(self):
150
        expected_errors = [
151
            {
152
                'message': 'Unknown function "#property#value"'
153
            }
154
        ]
155
156
        expected_result = {'output': None, 'errors': expected_errors}
157
158
        wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-input-rendering.yaml')
159
160
        lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'])
161
        lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db)
162
163
        # Assert action execution for task is not started and workflow failed.
164
        wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0]
165
        tk_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))
166
        self.assertEqual(len(tk_ex_dbs), 0)
167
        self.assertEqual(wf_ex_db.status, wf_states.FAILED)
168
        self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors)
169
170
        lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id))
171
        self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED)
172
        self.assertDictEqual(lv_ac_db.result, expected_result)
173
174
        ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id))
175
        self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED)
176
        self.assertDictEqual(ac_ex_db.result, expected_result)
177
178
    def test_fail_vars_rendering(self):
179
        expected_errors = [
180
            {
181
                'message': 'Unknown function "#property#value"'
182
            }
183
        ]
184
185
        expected_result = {'output': None, 'errors': expected_errors}
186
187
        wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-vars-rendering.yaml')
188
189
        lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'])
190
        lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db)
191
192
        # Assert action execution for task is not started and workflow failed.
193
        wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0]
194
        tk_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))
195
        self.assertEqual(len(tk_ex_dbs), 0)
196
        self.assertEqual(wf_ex_db.status, wf_states.FAILED)
197
        self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors)
198
199
        lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id))
200
        self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED)
201
        self.assertDictEqual(lv_ac_db.result, expected_result)
202
203
        ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id))
204
        self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED)
205
        self.assertDictEqual(ac_ex_db.result, expected_result)
206
207
    def test_fail_start_task_action(self):
208
        expected_errors = [
209
            {
210
                'message': 'Unknown function "#property#value"',
211
                'task_id': 'task1'
212
            }
213
        ]
214
215
        expected_result = {'output': None, 'errors': expected_errors}
216
217
        wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-start-task-action.yaml')
218
219
        lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'])
220
        lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db)
221
222
        # Assert action execution for task is not started and workflow failed.
223
        wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0]
224
        tk_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))
225
        self.assertEqual(len(tk_ex_dbs), 0)
226
        self.assertEqual(wf_ex_db.status, wf_states.FAILED)
227
        self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors)
228
229
        lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id))
230
        self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED)
231
        self.assertDictEqual(lv_ac_db.result, expected_result)
232
233
        ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id))
234
        self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED)
235
        self.assertDictEqual(ac_ex_db.result, expected_result)
236
237
    def test_fail_start_task_input_expr_eval(self):
238
        expected_errors = [
239
            {
240
                'message': 'Unknown function "#property#value"',
241
                'task_id': 'task1'
242
            }
243
        ]
244
245
        expected_result = {'output': None, 'errors': expected_errors}
246
247
        wf_file = 'fail-start-task-input-expr-eval.yaml'
248
        wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, wf_file)
249
250
        lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'])
251
        lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db)
252
253
        # Assert action execution for task is not started and workflow failed.
254
        wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0]
255
        tk_ex_dbs = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))
256
        self.assertEqual(len(tk_ex_dbs), 0)
257
        self.assertEqual(wf_ex_db.status, wf_states.FAILED)
258
        self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors)
259
260
        lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id))
261
        self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED)
262
        self.assertDictEqual(lv_ac_db.result, expected_result)
263
264
        ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id))
265
        self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED)
266
        self.assertDictEqual(ac_ex_db.result, expected_result)
267
268
    def test_fail_start_task_input_value_type(self):
269
        if six.PY3:
270
            msg = 'Value "{\'x\': \'foobar\'}" must either be a string or None. Got "dict".'
271
        else:
272
            msg = 'Value "{u\'x\': u\'foobar\'}" must either be a string or None. Got "dict".'
273
274
        expected_errors = [
275
            {
276
                'message': msg,
277
                'task_id': 'task1'
278
            }
279
        ]
280
281
        expected_result = {'output': None, 'errors': expected_errors}
282
283
        wf_file = 'fail-start-task-input-value-type.yaml'
284
        wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, wf_file)
285
        wf_input = {'var1': {'x': 'foobar'}}
286
        lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input)
287
        lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db)
288
289
        # Assert workflow and task executions failed.
290
        wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0]
291
        self.assertEqual(wf_ex_db.status, wf_states.FAILED)
292
        self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors)
293
294
        tk_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))[0]
295
        self.assertEqual(tk_ex_db.status, wf_states.FAILED)
296
        self.assertDictEqual(tk_ex_db.result, {'errors': expected_errors})
297
298
        lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id))
299
        self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED)
300
        self.assertDictEqual(lv_ac_db.result, expected_result)
301
302
        ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id))
303
        self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED)
304
        self.assertDictEqual(ac_ex_db.result, expected_result)
305
306
    def test_fail_next_task_action(self):
307
        expected_errors = [
308
            {
309
                'message': 'Unknown function "#property#value"',
310
                'task_id': 'task2'
311
            }
312
        ]
313
314
        expected_result = {'output': None, 'errors': expected_errors}
315
316
        wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-task-action.yaml')
317
318
        lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'])
319
        lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db)
320
321
        # Assert task1 is already completed.
322
        wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0]
323
        tk_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))[0]
324
        tk_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_db.id))[0]
325
        tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk_ac_ex_db.liveaction['id'])
326
        self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED)
327
328
        # Manually handle action execution completion for task1 which has an error in publish.
329
        wf_svc.handle_action_execution_completion(tk_ac_ex_db)
330
331
        # Assert task1 succeeded but workflow failed.
332
        tk_ex_db = wf_db_access.TaskExecution.get_by_id(tk_ex_db.id)
333
        self.assertEqual(tk_ex_db.status, wf_states.SUCCEEDED)
334
        wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id)
335
        self.assertEqual(wf_ex_db.status, wf_states.FAILED)
336
        self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors)
337
338
        lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id))
339
        self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED)
340
        self.assertDictEqual(lv_ac_db.result, expected_result)
341
342
        ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id))
343
        self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED)
344
        self.assertDictEqual(ac_ex_db.result, expected_result)
345
346
    def test_fail_next_task_input_expr_eval(self):
347
        expected_errors = [
348
            {
349
                'message': 'Unknown function "#property#value"',
350
                'task_id': 'task2'
351
            }
352
        ]
353
354
        expected_result = {'output': None, 'errors': expected_errors}
355
356
        wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-task-input-expr-eval.yaml')
357
358
        lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'])
359
        lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db)
360
361
        # Assert task1 is already completed.
362
        wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0]
363
        tk_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))[0]
364
        tk_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_db.id))[0]
365
        tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk_ac_ex_db.liveaction['id'])
366
        self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED)
367
368
        # Manually handle action execution completion for task1 which has an error in publish.
369
        wf_svc.handle_action_execution_completion(tk_ac_ex_db)
370
371
        # Assert task1 succeeded but workflow failed.
372
        tk_ex_db = wf_db_access.TaskExecution.get_by_id(tk_ex_db.id)
373
        self.assertEqual(tk_ex_db.status, wf_states.SUCCEEDED)
374
        wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id)
375
        self.assertEqual(wf_ex_db.status, wf_states.FAILED)
376
        self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors)
377
378
        lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id))
379
        self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED)
380
        self.assertDictEqual(lv_ac_db.result, expected_result)
381
382
        ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id))
383
        self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED)
384
        self.assertDictEqual(ac_ex_db.result, expected_result)
385
386
    def test_fail_next_task_input_value_type(self):
387
        if six.PY3:
388
            msg = 'Value "{\'x\': \'foobar\'}" must either be a string or None. Got "dict".'
389
        else:
390
            msg = 'Value "{u\'x\': u\'foobar\'}" must either be a string or None. Got "dict".'
391
392
        expected_errors = [
393
            {
394
                'message': msg,
395
                'task_id': 'task2'
396
            }
397
        ]
398
399
        expected_result = {'output': None, 'errors': expected_errors}
400
401
        wf_file = 'fail-task-input-value-type.yaml'
402
        wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, wf_file)
403
        wf_input = {'var1': {'x': 'foobar'}}
404
        lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'], parameters=wf_input)
405
        lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db)
406
407
        # Assert task1 is already completed and workflow execution is still running.
408
        wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0]
409
        tk1_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))[0]
410
        tk1_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk1_ex_db.id))[0]
411
        tk1_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk1_ac_ex_db.liveaction['id'])
412
        self.assertEqual(tk1_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED)
413
        self.assertEqual(wf_ex_db.status, wf_states.RUNNING)
414
415
        # Manually handle action execution completion for task1 which has an error in publish.
416
        wf_svc.handle_action_execution_completion(tk1_ac_ex_db)
417
418
        # Assert workflow execution and task2 execution failed.
419
        wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(str(wf_ex_db.id))
420
        self.assertEqual(wf_ex_db.status, wf_states.FAILED)
421
        self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors)
422
423
        tk2_ex_db = wf_db_access.TaskExecution.query(task_id='task2')[0]
424
        self.assertEqual(tk2_ex_db.status, wf_states.FAILED)
425
        self.assertDictEqual(tk2_ex_db.result, {'errors': expected_errors})
426
427
        lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id))
428
        self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED)
429
        self.assertDictEqual(lv_ac_db.result, expected_result)
430
431
        ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id))
432
        self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED)
433
        self.assertDictEqual(ac_ex_db.result, expected_result)
434
435
    def test_fail_task_transition(self):
436
        expected_errors = [
437
            {
438
                'message': (
439
                    "Unable to resolve key 'foobar' in expression "
440
                    "'<% succeeded() and result().foobar %>' from context."
441
                ),
442
                'task_transition_id': 'task2__0',
443
                'task_id': 'task1'
444
            }
445
        ]
446
447
        expected_result = {'output': None, 'errors': expected_errors}
448
449
        wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-task-transition.yaml')
450
        lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'])
451
        lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db)
452
453
        # Assert task1 is already completed.
454
        wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0]
455
        tk_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))[0]
456
        tk_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_db.id))[0]
457
        tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk_ac_ex_db.liveaction['id'])
458
        self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED)
459
460
        # Manually handle action execution completion for task1 which has an error in publish.
461
        wf_svc.handle_action_execution_completion(tk_ac_ex_db)
462
463
        # Assert task1 succeeded but workflow failed.
464
        tk_ex_db = wf_db_access.TaskExecution.get_by_id(tk_ex_db.id)
465
        self.assertEqual(tk_ex_db.status, wf_states.SUCCEEDED)
466
        wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id)
467
        self.assertEqual(wf_ex_db.status, wf_states.FAILED)
468
        self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors)
469
470
        lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id))
471
        self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED)
472
        self.assertDictEqual(lv_ac_db.result, expected_result)
473
474
        ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id))
475
        self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED)
476
        self.assertDictEqual(ac_ex_db.result, expected_result)
477
478
    def test_fail_task_publish(self):
479
        expected_errors = [
480
            {
481
                'message': 'Unknown function "foobar"',
482
                'task_transition_id': 'task2__0',
483
                'task_id': 'task1'
484
            }
485
        ]
486
487
        expected_result = {'output': None, 'errors': expected_errors}
488
489
        wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-task-publish.yaml')
490
        lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'])
491
        lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db)
492
493
        # Assert task1 is already completed.
494
        wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0]
495
        tk_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))[0]
496
        tk_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_db.id))[0]
497
        tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk_ac_ex_db.liveaction['id'])
498
        self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED)
499
500
        # Manually handle action execution completion for task1 which has an error in publish.
501
        wf_svc.handle_action_execution_completion(tk_ac_ex_db)
502
503
        # Assert task1 succeeded but workflow failed.
504
        tk_ex_db = wf_db_access.TaskExecution.get_by_id(tk_ex_db.id)
505
        self.assertEqual(tk_ex_db.status, wf_states.SUCCEEDED)
506
        wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id)
507
        self.assertEqual(wf_ex_db.status, wf_states.FAILED)
508
        self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors)
509
510
        lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id))
511
        self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED)
512
        self.assertDictEqual(lv_ac_db.result, expected_result)
513
514
        ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id))
515
        self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED)
516
        self.assertDictEqual(ac_ex_db.result, expected_result)
517
518
    def test_fail_output_rendering(self):
519
        expected_errors = [
520
            {
521
                'message': 'Unknown function "#property#value"'
522
            }
523
        ]
524
525
        expected_result = {'output': None, 'errors': expected_errors}
526
527
        wf_meta = base.get_wf_fixture_meta_data(TEST_PACK_PATH, 'fail-output-rendering.yaml')
528
        lv_ac_db = lv_db_models.LiveActionDB(action=wf_meta['name'])
529
        lv_ac_db, ac_ex_db = ac_svc.request(lv_ac_db)
530
531
        # Assert task1 is already completed.
532
        wf_ex_db = wf_db_access.WorkflowExecution.query(action_execution=str(ac_ex_db.id))[0]
533
        tk_ex_db = wf_db_access.TaskExecution.query(workflow_execution=str(wf_ex_db.id))[0]
534
        tk_ac_ex_db = ex_db_access.ActionExecution.query(task_execution=str(tk_ex_db.id))[0]
535
        tk_lv_ac_db = lv_db_access.LiveAction.get_by_id(tk_ac_ex_db.liveaction['id'])
536
        self.assertEqual(tk_lv_ac_db.status, ac_const.LIVEACTION_STATUS_SUCCEEDED)
537
538
        # Manually handle action execution completion for task1 which has an error in publish.
539
        wf_svc.handle_action_execution_completion(tk_ac_ex_db)
540
541
        # Assert task1 succeeded but workflow failed.
542
        tk_ex_db = wf_db_access.TaskExecution.get_by_id(tk_ex_db.id)
543
        self.assertEqual(tk_ex_db.status, wf_states.SUCCEEDED)
544
        wf_ex_db = wf_db_access.WorkflowExecution.get_by_id(wf_ex_db.id)
545
        self.assertEqual(wf_ex_db.status, wf_states.FAILED)
546
        self.assertListEqual(self.sort_wf_runtime_errors(wf_ex_db.errors), expected_errors)
547
548
        lv_ac_db = lv_db_access.LiveAction.get_by_id(str(lv_ac_db.id))
549
        self.assertEqual(lv_ac_db.status, ac_const.LIVEACTION_STATUS_FAILED)
550
        self.assertDictEqual(lv_ac_db.result, expected_result)
551
552
        ac_ex_db = ex_db_access.ActionExecution.get_by_id(str(ac_ex_db.id))
553
        self.assertEqual(ac_ex_db.status, ac_const.LIVEACTION_STATUS_FAILED)
554
        self.assertDictEqual(ac_ex_db.result, expected_result)
555