467f60af09
* Made workflow execution creation idempotent. We can now pass an execution ID which is used when creating a new execution object. If the object with this ID doesn't exist, then a new execution is created and this ID is assigned to, and also the corresponding workflow gets started normally. If the object exists then the endpoint just returns properties of this object in JSON w/o starting the workflow. If an execution ID is not passed then the endpoint works as before, so it is backwards compatible with the previous version. * Added unit tests to check all possible logic branches depending on whether we passed an execution ID. * Had to add "wf_ex_id" paramter to the "start_workflow" method of the Engine API and fix all relevant calls. * Other minor style changes. Implements blueprint: mistral-idempotent-execution-create Change-Id: I1f650efbd23b00298a30e16893ca4f18d87c99b3
155 lines
4.2 KiB
Python
155 lines
4.2 KiB
Python
# Copyright 2015 - Mirantis, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
from oslo_config import cfg
|
|
|
|
from mistral.db.v2 import api as db_api
|
|
from mistral.services import workflows as wf_service
|
|
from mistral.tests.unit.engine import base
|
|
from mistral.workflow import states
|
|
|
|
|
|
# Use the set_default method to set value otherwise in certain test cases
|
|
# the change in value is not permanent.
|
|
cfg.CONF.set_default('auth_enable', False, group='pecan')
|
|
|
|
|
|
class WorkflowVariablesTest(base.EngineTestCase):
|
|
def test_workflow_variables(self):
|
|
wf_text = """---
|
|
version: '2.0'
|
|
|
|
wf:
|
|
input:
|
|
- param1: "Hello"
|
|
- param2
|
|
|
|
vars:
|
|
literal_var: "Literal value"
|
|
yaql_var: "<% $.param1 %> <% $.param2 %>"
|
|
|
|
output:
|
|
literal_var: <% $.literal_var %>
|
|
yaql_var: <% $.yaql_var %>
|
|
|
|
tasks:
|
|
task1:
|
|
action: std.noop
|
|
"""
|
|
|
|
wf_service.create_workflows(wf_text)
|
|
|
|
# Start workflow.
|
|
wf_ex = self.engine.start_workflow('wf', wf_input={'param2': 'Renat'})
|
|
|
|
self.await_workflow_success(wf_ex.id)
|
|
|
|
with db_api.transaction():
|
|
# Note: We need to reread execution to access related tasks.
|
|
wf_ex = db_api.get_workflow_execution(wf_ex.id)
|
|
|
|
wf_output = wf_ex.output
|
|
tasks = wf_ex.task_executions
|
|
|
|
task1 = self._assert_single_item(tasks, name='task1')
|
|
|
|
self.assertEqual(states.SUCCESS, task1.state)
|
|
|
|
self.assertDictEqual(
|
|
{
|
|
'literal_var': 'Literal value',
|
|
'yaql_var': 'Hello Renat'
|
|
},
|
|
wf_output
|
|
)
|
|
|
|
def test_dynamic_action_names(self):
|
|
wf_text = """---
|
|
version: '2.0'
|
|
|
|
wf2:
|
|
input:
|
|
- wf_action
|
|
- param1
|
|
|
|
tasks:
|
|
task1:
|
|
action: <% $.wf_action %> output=<% $.param1 %>
|
|
publish:
|
|
var1: <% task(task1).result %>
|
|
|
|
"""
|
|
|
|
wf_service.create_workflows(wf_text)
|
|
|
|
# Start workflow.
|
|
wf_ex = self.engine.start_workflow(
|
|
'wf2',
|
|
wf_input={'wf_action': 'std.echo', 'param1': 'Hello'}
|
|
)
|
|
|
|
self.await_workflow_success(wf_ex.id)
|
|
|
|
with db_api.transaction():
|
|
# Note: We need to reread execution to access related tasks.
|
|
wf_ex = db_api.get_workflow_execution(wf_ex.id)
|
|
|
|
wf_output = wf_ex.output
|
|
tasks = wf_ex.task_executions
|
|
|
|
task1 = self._assert_single_item(tasks, name='task1')
|
|
|
|
self.assertEqual(states.SUCCESS, task1.state)
|
|
self.assertEqual("Hello", wf_output['var1'])
|
|
|
|
def test_dynamic_action_names_and_input(self):
|
|
wf_text = """---
|
|
version: '2.0'
|
|
|
|
wf3:
|
|
input:
|
|
- wf_action
|
|
- wf_input
|
|
|
|
tasks:
|
|
task1:
|
|
action: <% $.wf_action %>
|
|
input: <% $.wf_input %>
|
|
publish:
|
|
var1: <% task(task1).result %>
|
|
|
|
"""
|
|
|
|
wf_service.create_workflows(wf_text)
|
|
|
|
# Start workflow.
|
|
wf_ex = self.engine.start_workflow(
|
|
'wf3',
|
|
wf_input={'wf_action': 'std.echo', 'wf_input': {'output': 'Hello'}}
|
|
)
|
|
|
|
self.await_workflow_success(wf_ex.id)
|
|
|
|
with db_api.transaction():
|
|
# Note: We need to reread execution to access related tasks.
|
|
wf_ex = db_api.get_workflow_execution(wf_ex.id)
|
|
|
|
wf_output = wf_ex.output
|
|
tasks = wf_ex.task_executions
|
|
|
|
task1 = self._assert_single_item(tasks, name='task1')
|
|
|
|
self.assertEqual(states.SUCCESS, task1.state)
|
|
self.assertEqual("Hello", wf_output['var1'])
|