GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — plexxi-v2.1.1 ( 2317c4...ed2af2 )
by
unknown
05:10
created

MistralRunnerCallbackTest.test_callback_retry()   B

Complexity

Conditions 2

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 2
dl 0
loc 24
rs 8.9713
c 1
b 1
f 0
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 mock
17
from mock import call
18
import requests
19
20
from mistralclient.api.v2 import action_executions
21
from oslo_config import cfg
22
23
# XXX: actionsensor import depends on config being setup.
24
import st2tests.config as tests_config
25
tests_config.parse_args()
26
27
from st2actions.handlers.mistral import MistralCallbackHandler
28
from st2actions.handlers.mistral import STATUS_MAP as mistral_status_map
29
from st2common.bootstrap import actionsregistrar
30
from st2common.bootstrap import runnersregistrar
31
from st2common.constants import action as action_constants
32
from st2common.models.db.liveaction import LiveActionDB
33
from st2common.persistence.liveaction import LiveAction
34
from st2common.runners import base as runners
35
from st2common.services import action as action_service
36
from st2common.transport.liveaction import LiveActionPublisher
37
from st2common.transport.publishers import CUDPublisher
38
from st2tests import DbTestCase
39
from st2tests import fixturesloader
40
from st2tests.mocks.liveaction import MockLiveActionPublisher
41
42
43
TEST_PACK = 'mistral_tests'
44
TEST_PACK_PATH = fixturesloader.get_fixtures_packs_base_path() + '/' + TEST_PACK
45
46
PACKS = [
47
    TEST_PACK_PATH,
48
    fixturesloader.get_fixtures_packs_base_path() + '/core'
49
]
50
51
NON_EMPTY_RESULT = 'non-empty'
52
53
54
@mock.patch.object(
55
    CUDPublisher,
56
    'publish_update',
57
    mock.MagicMock(return_value=None))
58
@mock.patch.object(
59
    CUDPublisher,
60
    'publish_create',
61
    mock.MagicMock(side_effect=MockLiveActionPublisher.publish_create))
62
@mock.patch.object(
63
    LiveActionPublisher,
64
    'publish_state',
65
    mock.MagicMock(side_effect=MockLiveActionPublisher.publish_state))
66
class MistralRunnerCallbackTest(DbTestCase):
67
68
    @classmethod
69
    def setUpClass(cls):
70
        super(MistralRunnerCallbackTest, cls).setUpClass()
71
72
        # Override the retry configuration here otherwise st2tests.config.parse_args
73
        # in DbTestCase.setUpClass will reset these overrides.
74
        cfg.CONF.set_override('retry_exp_msec', 100, group='mistral')
75
        cfg.CONF.set_override('retry_exp_max_msec', 200, group='mistral')
76
        cfg.CONF.set_override('retry_stop_max_msec', 200, group='mistral')
77
        cfg.CONF.set_override('api_url', 'http://0.0.0.0:9101', group='auth')
78
79
        # Register runners.
80
        runnersregistrar.register_runners()
81
82
        # Register test pack(s).
83
        actions_registrar = actionsregistrar.ActionsRegistrar(
84
            use_pack_cache=False,
85
            fail_on_failure=True
86
        )
87
88
        for pack in PACKS:
89
            actions_registrar.register_from_pack(pack)
90
91
    @classmethod
92
    def get_runner_class(cls, runner_name):
93
        return runners.get_runner(runner_name).__class__
94
95
    def test_callback_handler_status_map(self):
96
        # Ensure all StackStorm status are mapped otherwise leads to zombie workflow.
97
        self.assertListEqual(sorted(mistral_status_map.keys()),
98
                             sorted(action_constants.LIVEACTION_STATUSES))
99
100
    @mock.patch.object(
101
        action_executions.ActionExecutionManager, 'update',
102
        mock.MagicMock(return_value=None))
103
    def test_callback_handler_with_result_as_text(self):
104
        MistralCallbackHandler.callback('http://127.0.0.1:8989/v2/action_executions/12345', {},
105
                                        action_constants.LIVEACTION_STATUS_SUCCEEDED,
106
                                        '<html></html>')
107
108
    @mock.patch.object(
109
        action_executions.ActionExecutionManager, 'update',
110
        mock.MagicMock(return_value=None))
111
    def test_callback_handler_with_result_as_dict(self):
112
        MistralCallbackHandler.callback('http://127.0.0.1:8989/v2/action_executions/12345', {},
113
                                        action_constants.LIVEACTION_STATUS_SUCCEEDED, {'a': 1})
114
115
    @mock.patch.object(
116
        action_executions.ActionExecutionManager, 'update',
117
        mock.MagicMock(return_value=None))
118
    def test_callback_handler_with_result_as_json_str(self):
119
        MistralCallbackHandler.callback('http://127.0.0.1:8989/v2/action_executions/12345', {},
120
                                        action_constants.LIVEACTION_STATUS_SUCCEEDED, '{"a": 1}')
121
        MistralCallbackHandler.callback('http://127.0.0.1:8989/v2/action_executions/12345', {},
122
                                        action_constants.LIVEACTION_STATUS_SUCCEEDED, "{'a': 1}")
123
124
    @mock.patch.object(
125
        action_executions.ActionExecutionManager, 'update',
126
        mock.MagicMock(return_value=None))
127
    def test_callback_handler_with_result_as_list(self):
128
        MistralCallbackHandler.callback('http://127.0.0.1:8989/v2/action_executions/12345', {},
129
                                        action_constants.LIVEACTION_STATUS_SUCCEEDED,
130
                                        ["a", "b", "c"])
131
132
    @mock.patch.object(
133
        action_executions.ActionExecutionManager, 'update',
134
        mock.MagicMock(return_value=None))
135
    def test_callback_handler_with_result_as_list_str(self):
136
        MistralCallbackHandler.callback('http://127.0.0.1:8989/v2/action_executions/12345', {},
137
                                        action_constants.LIVEACTION_STATUS_SUCCEEDED,
138
                                        '["a", "b", "c"]')
139
140
    @mock.patch.object(
141
        action_executions.ActionExecutionManager, 'update',
142
        mock.MagicMock(return_value=None))
143
    def test_callback(self):
144
        local_runner_cls = self.get_runner_class('local_runner')
145
146
        liveaction = LiveActionDB(
147
            action='core.local', parameters={'cmd': 'uname -a'},
148
            callback={
149
                'source': 'mistral',
150
                'url': 'http://127.0.0.1:8989/v2/action_executions/12345'
151
            }
152
        )
153
154
        for status in action_constants.LIVEACTION_COMPLETED_STATES:
155
            expected_mistral_status = mistral_status_map[status]
156
            local_runner_cls.run = mock.Mock(return_value=(status, NON_EMPTY_RESULT, None))
157
            liveaction, execution = action_service.request(liveaction)
158
            liveaction = LiveAction.get_by_id(str(liveaction.id))
159
            self.assertEqual(liveaction.status, status)
160
            action_executions.ActionExecutionManager.update.assert_called_with(
161
                '12345', state=expected_mistral_status, output=NON_EMPTY_RESULT)
162
163
    @mock.patch.object(
164
        action_executions.ActionExecutionManager, 'update',
165
        mock.MagicMock(return_value=None))
166
    def test_callback_incomplete_state(self):
167
        local_runner_cls = self.get_runner_class('local_runner')
168
        local_run_result = (action_constants.LIVEACTION_STATUS_RUNNING, NON_EMPTY_RESULT, None)
169
        local_runner_cls.run = mock.Mock(return_value=local_run_result)
170
171
        liveaction = LiveActionDB(
172
            action='core.local', parameters={'cmd': 'uname -a'},
173
            callback={
174
                'source': 'mistral',
175
                'url': 'http://127.0.0.1:8989/v2/action_executions/12345'
176
            }
177
        )
178
179
        liveaction, execution = action_service.request(liveaction)
180
        liveaction = LiveAction.get_by_id(str(liveaction.id))
181
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_RUNNING)
182
        self.assertFalse(action_executions.ActionExecutionManager.update.called)
183
184
    @mock.patch.object(
185
        action_executions.ActionExecutionManager, 'update',
186
        mock.MagicMock(side_effect=[
187
            requests.exceptions.ConnectionError(),
188
            None]))
189
    def test_callback_retry(self):
190
        local_runner_cls = self.get_runner_class('local_runner')
191
        local_run_result = (action_constants.LIVEACTION_STATUS_SUCCEEDED, NON_EMPTY_RESULT, None)
192
        local_runner_cls.run = mock.Mock(return_value=local_run_result)
193
194
        liveaction = LiveActionDB(
195
            action='core.local', parameters={'cmd': 'uname -a'},
196
            callback={
197
                'source': 'mistral',
198
                'url': 'http://127.0.0.1:8989/v2/action_executions/12345'
199
            }
200
        )
201
202
        liveaction, execution = action_service.request(liveaction)
203
        liveaction = LiveAction.get_by_id(str(liveaction.id))
204
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_SUCCEEDED)
205
206
        calls = [call('12345', state='SUCCESS', output=NON_EMPTY_RESULT) for i in range(0, 2)]
207
        action_executions.ActionExecutionManager.update.assert_has_calls(calls)
208
209
    @mock.patch.object(
210
        action_executions.ActionExecutionManager, 'update',
211
        mock.MagicMock(side_effect=[
212
            requests.exceptions.ConnectionError(),
213
            requests.exceptions.ConnectionError(),
214
            requests.exceptions.ConnectionError(),
215
            requests.exceptions.ConnectionError(),
216
            None]))
217
    def test_callback_retry_exhausted(self):
218
        local_runner_cls = self.get_runner_class('local_runner')
219
        local_run_result = (action_constants.LIVEACTION_STATUS_SUCCEEDED, NON_EMPTY_RESULT, None)
220
        local_runner_cls.run = mock.Mock(return_value=local_run_result)
221
222
        liveaction = LiveActionDB(
223
            action='core.local', parameters={'cmd': 'uname -a'},
224
            callback={
225
                'source': 'mistral',
226
                'url': 'http://127.0.0.1:8989/v2/action_executions/12345'
227
            }
228
        )
229
230
        liveaction, execution = action_service.request(liveaction)
231
        liveaction = LiveAction.get_by_id(str(liveaction.id))
232
        self.assertEqual(liveaction.status, action_constants.LIVEACTION_STATUS_SUCCEEDED)
233
234
        # This test initially setup mock for action_executions.ActionExecutionManager.update
235
        # to fail the first 4 times and return success on the 5th times. The max attempts
236
        # is set to 3. We expect only 3 calls to pass thru the update method.
237
        calls = [call('12345', state='SUCCESS', output=NON_EMPTY_RESULT) for i in range(0, 2)]
238
        action_executions.ActionExecutionManager.update.assert_has_calls(calls)
239