Completed
Pull Request — master (#3048)
by W
04:48
created

MistralAuthTest   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 172
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 172
rs 10
wmc 7

6 Methods

Rating   Name   Duplication   Size   Complexity  
A test_launch_workflow_with_st2_auth() 0 52 1
A get_runner_class() 0 3 1
A setUp() 0 8 1
A setUpClass() 0 21 2
A test_launch_workflow_with_mistral_auth() 0 63 1
A tearDown() 0 6 1
1
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
2
# contributor license agreements.  See the NOTICE file distributed with
3
# this work for additional information regarding copyright ownership.
4
# The ASF licenses this file to You under the Apache License, Version 2.0
5
# (the "License"); you may not use this file except in compliance with
6
# the License.  You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15
16
import copy
17
import uuid
18
19
import mock
20
import yaml
21
22
from mistralclient.api.v2 import client
23
from mistralclient.api.v2 import executions
24
from mistralclient.api.v2 import workflows
25
from oslo_config import cfg
26
27
# XXX: actionsensor import depends on config being setup.
28
import st2tests.config as tests_config
29
tests_config.parse_args()
30
31
from mistral_v2 import MistralRunner
32
from st2common.bootstrap import actionsregistrar
33
import st2common.bootstrap.runnersregistrar as runners_registrar
34
from st2common.constants import action as action_constants
35
from st2common.models.api.auth import TokenAPI
36
from st2common.models.db.liveaction import LiveActionDB
37
from st2common.persistence.liveaction import LiveAction
38
from st2common.runners import base as runners
39
from st2common.services import access as access_service
40
from st2common.services import action as action_service
41
from st2common.transport.liveaction import LiveActionPublisher
42
from st2common.transport.publishers import CUDPublisher
43
from st2common.util import isotime
44
from st2common.util import date as date_utils
45
from st2common.util import loader
46
from st2tests import DbTestCase
47
from st2tests import fixturesloader
48
from st2tests.mocks.liveaction import MockLiveActionPublisher
49
50
51
TEST_FIXTURES = {
52
    'workflows': [
53
        'workflow_v2.yaml'
54
    ],
55
    'actions': [
56
        'workflow_v2.yaml'
57
    ]
58
}
59
60
TEST_PACK = 'mistral_tests'
61
TEST_PACK_PATH = fixturesloader.get_fixtures_packs_base_path() + '/' + TEST_PACK
62
63
PACKS = [
64
    TEST_PACK_PATH,
65
    fixturesloader.get_fixtures_packs_base_path() + '/core'
66
]
67
68
# Action executions requirements
69
MISTRAL_EXECUTION = {'id': str(uuid.uuid4()), 'state': 'RUNNING', 'workflow_name': None}
70
ACTION_CONTEXT = {'user': 'stanley'}
71
ACTION_PARAMS = {'friend': 'Rocky'}
72
NON_EMPTY_RESULT = 'non-empty'
73
74
# Non-workbook with a single workflow
75
WF1_META_FILE_NAME = TEST_FIXTURES['workflows'][0]
76
WF1_META_FILE_PATH = TEST_PACK_PATH + '/actions/' + WF1_META_FILE_NAME
77
WF1_META_CONTENT = loader.load_meta_file(WF1_META_FILE_PATH)
78
WF1_NAME = WF1_META_CONTENT['pack'] + '.' + WF1_META_CONTENT['name']
79
WF1_ENTRY_POINT = TEST_PACK_PATH + '/actions/' + WF1_META_CONTENT['entry_point']
80
WF1_SPEC = yaml.safe_load(MistralRunner.get_workflow_definition(WF1_ENTRY_POINT))
81
WF1_YAML = yaml.safe_dump(WF1_SPEC, default_flow_style=False)
82
WF1 = workflows.Workflow(None, {'name': WF1_NAME, 'definition': WF1_YAML})
83
WF1_OLD = workflows.Workflow(None, {'name': WF1_NAME, 'definition': ''})
84
WF1_EXEC = copy.deepcopy(MISTRAL_EXECUTION)
85
WF1_EXEC['workflow_name'] = WF1_NAME
86
87
# Token for auth test cases
88
TOKEN_API = TokenAPI(
89
    user=ACTION_CONTEXT['user'], token=uuid.uuid4().hex,
90
    expiry=isotime.format(date_utils.get_datetime_utc_now(), offset=False))
91
TOKEN_DB = TokenAPI.to_model(TOKEN_API)
92
93
94
@mock.patch.object(
95
    CUDPublisher,
96
    'publish_update',
97
    mock.MagicMock(return_value=None))
98
@mock.patch.object(
99
    CUDPublisher,
100
    'publish_create',
101
    mock.MagicMock(side_effect=MockLiveActionPublisher.publish_create))
102
@mock.patch.object(
103
    LiveActionPublisher,
104
    'publish_state',
105
    mock.MagicMock(side_effect=MockLiveActionPublisher.publish_state))
106
class MistralAuthTest(DbTestCase):
107
108
    @classmethod
109
    def setUpClass(cls):
110
        super(MistralAuthTest, cls).setUpClass()
111
112
        # Override the retry configuration here otherwise st2tests.config.parse_args
113
        # in DbTestCase.setUpClass will reset these overrides.
114
        cfg.CONF.set_override('retry_exp_msec', 100, group='mistral')
115
        cfg.CONF.set_override('retry_exp_max_msec', 200, group='mistral')
116
        cfg.CONF.set_override('retry_stop_max_msec', 200, group='mistral')
117
118
        # Register runners.
119
        runners_registrar.register_runners()
120
121
        # Register test pack(s).
122
        registrar = actionsregistrar.ActionsRegistrar(
123
            use_pack_cache=False,
124
            fail_on_failure=True
125
        )
126
127
        for pack in PACKS:
128
            registrar.register_from_pack(pack)
129
130
    def setUp(self):
131
        super(MistralAuthTest, self).setUp()
132
        cfg.CONF.set_override('api_url', 'http://0.0.0.0:9101', group='auth')
133
134
        # Mock the local runner run method.
135
        local_runner_cls = self.get_runner_class('local_runner')
136
        local_run_result = (action_constants.LIVEACTION_STATUS_SUCCEEDED, NON_EMPTY_RESULT, None)
137
        local_runner_cls.run = mock.Mock(return_value=local_run_result)
138
139
    @classmethod
140
    def get_runner_class(cls, runner_name):
141
        return runners.get_runner(runner_name).__class__
142
143
    def tearDown(self):
144
        super(MistralAuthTest, self).tearDown()
145
        cfg.CONF.set_default('keystone_username', None, group='mistral')
146
        cfg.CONF.set_default('keystone_password', None, group='mistral')
147
        cfg.CONF.set_default('keystone_project_name', None, group='mistral')
148
        cfg.CONF.set_default('keystone_auth_url', None, group='mistral')
149
150
    @mock.patch.object(
151
        workflows.WorkflowManager, 'list',
152
        mock.MagicMock(return_value=[]))
153
    @mock.patch.object(
154
        workflows.WorkflowManager, 'get',
155
        mock.MagicMock(return_value=WF1))
156
    @mock.patch.object(
157
        workflows.WorkflowManager, 'create',
158
        mock.MagicMock(return_value=[WF1]))
159
    @mock.patch.object(
160
        executions.ExecutionManager, 'create',
161
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
162
    @mock.patch.object(
163
        access_service, 'create_token',
164
        mock.MagicMock(return_value=TOKEN_DB))
165
    def test_launch_workflow_with_st2_auth(self):
166
        liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS, context=ACTION_CONTEXT)
167
        liveaction, execution = action_service.request(liveaction)
168
        liveaction = LiveAction.get_by_id(str(liveaction.id))
169
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING)
170
171
        mistral_context = liveaction.context.get('mistral', None)
172
        self.assertIsNotNone(mistral_context)
173
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
174
        self.assertEqual(mistral_context['workflow_name'], WF1_EXEC.get('workflow_name'))
175
176
        workflow_input = copy.deepcopy(ACTION_PARAMS)
177
        workflow_input.update({'count': '3'})
178
179
        env = {
180
            'st2_execution_id': str(execution.id),
181
            'st2_liveaction_id': str(liveaction.id),
182
            'st2_action_api_url': 'http://0.0.0.0:9101/v1',
183
            '__actions': {
184
                'st2.action': {
185
                    'st2_context': {
186
                        'auth_token': TOKEN_DB.token,
187
                        'api_url': 'http://0.0.0.0:9101/v1',
188
                        'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions',
189
                        'parent': {
190
                            'user': liveaction.context['user'],
191
                            'execution_id': str(execution.id)
192
                        },
193
                        'notify': {},
194
                        'skip_notify_tasks': []
195
                    }
196
                }
197
            }
198
        }
199
200
        executions.ExecutionManager.create.assert_called_with(
201
            WF1_NAME, workflow_input=workflow_input, env=env)
202
203
    @mock.patch.object(
204
        client.Client, 'authenticate',
205
        mock.MagicMock(return_value=(cfg.CONF.mistral.v2_base_url, '123', 'abc', 'xyz')))
206
    @mock.patch.object(
207
        workflows.WorkflowManager, 'list',
208
        mock.MagicMock(return_value=[]))
209
    @mock.patch.object(
210
        workflows.WorkflowManager, 'get',
211
        mock.MagicMock(return_value=WF1))
212
    @mock.patch.object(
213
        workflows.WorkflowManager, 'create',
214
        mock.MagicMock(return_value=[WF1]))
215
    @mock.patch.object(
216
        executions.ExecutionManager, 'create',
217
        mock.MagicMock(return_value=executions.Execution(None, WF1_EXEC)))
218
    def test_launch_workflow_with_mistral_auth(self):
219
        cfg.CONF.set_default('keystone_username', 'foo', group='mistral')
220
        cfg.CONF.set_default('keystone_password', 'bar', group='mistral')
221
        cfg.CONF.set_default('keystone_project_name', 'admin', group='mistral')
222
        cfg.CONF.set_default('keystone_auth_url', 'http://127.0.0.1:5000/v3', group='mistral')
223
224
        liveaction = LiveActionDB(action=WF1_NAME, parameters=ACTION_PARAMS)
225
        liveaction, execution = action_service.request(liveaction)
226
        liveaction = LiveAction.get_by_id(str(liveaction.id))
227
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING)
228
229
        mistral_context = liveaction.context.get('mistral', None)
230
        self.assertIsNotNone(mistral_context)
231
        self.assertEqual(mistral_context['execution_id'], WF1_EXEC.get('id'))
232
        self.assertEqual(mistral_context['workflow_name'], WF1_EXEC.get('workflow_name'))
233
234
        workflow_input = copy.deepcopy(ACTION_PARAMS)
235
        workflow_input.update({'count': '3'})
236
237
        env = {
238
            'st2_execution_id': str(execution.id),
239
            'st2_liveaction_id': str(liveaction.id),
240
            'st2_action_api_url': 'http://0.0.0.0:9101/v1',
241
            '__actions': {
242
                'st2.action': {
243
                    'st2_context': {
244
                        'api_url': 'http://0.0.0.0:9101/v1',
245
                        'endpoint': 'http://0.0.0.0:9101/v1/actionexecutions',
246
                        'parent': {
247
                            'execution_id': str(execution.id)
248
                        },
249
                        'notify': {},
250
                        'skip_notify_tasks': []
251
                    }
252
                }
253
            }
254
        }
255
256
        client.Client.authenticate.assert_called_with(
257
            cfg.CONF.mistral.v2_base_url,
258
            cfg.CONF.mistral.keystone_username,
259
            cfg.CONF.mistral.keystone_password,
260
            cfg.CONF.mistral.keystone_project_name,
261
            cfg.CONF.mistral.keystone_auth_url,
262
            None, 'publicURL', 'workflow', None, None, None, False)
263
264
        executions.ExecutionManager.create.assert_called_with(
265
            WF1_NAME, workflow_input=workflow_input, env=env)
266