Passed
Pull Request — master (#3640)
by Lakshmi
06:19
created

ta()   F

Complexity

Conditions 11

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 11
dl 0
loc 31
rs 3.1764
c 1
b 0
f 0

How to fix   Complexity   

Complexity

Complex classes like TestStreamController.dispatch_and_handle_mock_data() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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
18
from oslo_config import cfg
19
20
from st2common.models.api.action import ActionAPI
21
from st2common.models.api.action import RunnerTypeAPI
22
from st2common.models.api.execution import ActionExecutionAPI
23
from st2common.models.api.execution import LiveActionAPI
24
from st2common.models.db.liveaction import LiveActionDB
25
from st2common.models.db.execution import ActionExecutionDB
26
from st2common.persistence.action import Action, RunnerType
27
import st2stream.listener
28
from st2stream.controllers.v1 import stream
29
from st2tests.api import SUPER_SECRET_PARAMETER
30
from base import FunctionalTest
31
32
33
RUNNER_TYPE_1 = {
34
    'description': '',
35
    'enabled': True,
36
    'name': 'local-shell-cmd',
37
    'runner_module': 'local_runner',
38
    'runner_parameters': {}
39
}
40
41
ACTION_1 = {
42
    'name': 'st2.dummy.action1',
43
    'description': 'test description',
44
    'enabled': True,
45
    'entry_point': '/tmp/test/action1.sh',
46
    'pack': 'sixpack',
47
    'runner_type': 'local-shell-cmd',
48
    'parameters': {
49
        'a': {
50
            'type': 'string',
51
            'default': 'abc'
52
        },
53
        'b': {
54
            'type': 'number',
55
            'default': 123
56
        },
57
        'c': {
58
            'type': 'number',
59
            'default': 123,
60
            'immutable': True
61
        },
62
        'd': {
63
            'type': 'string',
64
            'secret': True
65
        }
66
    }
67
}
68
69
LIVE_ACTION_1 = {
70
    'action': 'sixpack.st2.dummy.action1',
71
    'parameters': {
72
        'hosts': 'localhost',
73
        'cmd': 'uname -a',
74
        'd': SUPER_SECRET_PARAMETER
75
    }
76
}
77
78
EXECUTION_1 = {
79
    'id': '598dbf0c0640fd54bffc688b',
80
    'action': {
81
        'ref': 'sixpack.st2.dummy.action1'
82
    },
83
    'parameters': {
84
        'hosts': 'localhost',
85
        'cmd': 'uname -a',
86
        'd': SUPER_SECRET_PARAMETER
87
    }
88
}
89
90
91
class META(object):
92
    delivery_info = {}
93
94
    def __init__(self, exchange='some', routing_key='thing'):
95
        self.delivery_info['exchange'] = exchange
96
        self.delivery_info['routing_key'] = routing_key
97
98
    def ack(self):
99
        pass
100
101
102
class TestStreamController(FunctionalTest):
103
104
    @classmethod
105
    def setUpClass(cls):
106
        super(TestStreamController, cls).setUpClass()
107
108
        instance = RunnerTypeAPI(**RUNNER_TYPE_1)
109
        RunnerType.add_or_update(RunnerTypeAPI.to_model(instance))
110
111
        instance = ActionAPI(**ACTION_1)
112
        Action.add_or_update(ActionAPI.to_model(instance))
113
114
    @mock.patch.object(st2stream.listener, 'listen', mock.Mock())
115
    def test_get_all(self):
116
        resp = stream.StreamController().get_all()
117
        self.assertEqual(resp._status, '200 OK')
118
        self.assertIn(('Content-Type', 'text/event-stream; charset=UTF-8'), resp._headerlist)
119
120
        listener = st2stream.listener.get_listener()
121
        process = listener.processor(LiveActionAPI)
122
123
        message = None
124
125
        for message in resp._app_iter:
126
            if message != '\n':
127
                break
128
            process(LiveActionDB(**LIVE_ACTION_1), META())
129
130
        self.assertIn('event: some__thing', message)
131
        self.assertIn('data: {"', message)
132
        self.assertNotIn(SUPER_SECRET_PARAMETER, message)
133
134
    @mock.patch.object(st2stream.listener, 'listen', mock.Mock())
135
    def test_get_all_with_filters(self):
136
        cfg.CONF.set_override(name='heartbeat', group='stream', override=0.1)
137
138
        listener = st2stream.listener.get_listener()
139
        process_execution = listener.processor(ActionExecutionAPI)
140
        process_liveaction = listener.processor(LiveActionAPI)
141
142
        execution_api = ActionExecutionDB(**EXECUTION_1)
143
        liveaction_api = LiveActionDB(**LIVE_ACTION_1)
144
        liveaction_api_2 = LiveActionDB(**LIVE_ACTION_1)
145
        liveaction_api_2.action = 'dummy.action1'
146
147
        def dispatch_and_handle_mock_data(resp):
148
            received_messages_data = ''
149
            for index, message in enumerate(resp._app_iter):
150
                if message.strip():
151
                    received_messages_data += message
152
153
                # Dispatch some mock events
154
                if index == 0:
155
                    meta = META('st2.execution', 'create')
156
                    process_execution(execution_api, meta)
157
                elif index == 1:
158
                    meta = META('st2.execution', 'update')
159
                    process_execution(execution_api, meta)
160
                elif index == 2:
161
                    meta = META('st2.execution', 'delete')
162
                    process_execution(execution_api, meta)
163
                elif index == 3:
164
                    meta = META('st2.liveaction', 'create')
165
                    process_liveaction(liveaction_api, meta)
166
                elif index == 4:
167
                    meta = META('st2.liveaction', 'create')
168
                    process_liveaction(liveaction_api, meta)
169
                elif index == 5:
170
                    meta = META('st2.liveaction', 'delete')
171
                    process_liveaction(liveaction_api_2, meta)
172
                else:
173
                    break
174
175
            received_messages = received_messages_data.split('\n\n')
176
            received_messages = [message for message in received_messages if message]
177
            return received_messages
178
179
        # 1. Default filter
180
        resp = stream.StreamController().get_all()
181
182
        received_messages = dispatch_and_handle_mock_data(resp)
183
        self.assertEqual(len(received_messages), 6)
184
185
        # 1. ?events= filter
186
        # No filter provided - all messages should be received
187
        resp = stream.StreamController().get_all()
188
189
        received_messages = dispatch_and_handle_mock_data(resp)
190
        self.assertEqual(len(received_messages), 6)
191
192
        # Filter provided, only two messages should be received
193
        events = ['st2.execution__create', 'st2.liveaction__delete']
194
        events = ','.join(events)
195
        resp = stream.StreamController().get_all(events=events)
196
197
        received_messages = dispatch_and_handle_mock_data(resp)
198
        self.assertEqual(len(received_messages), 2)
199
200
        # Filter provided, invalid , no message should be received
201
        events = ['invalid1', 'invalid2']
202
        events = ','.join(events)
203
        resp = stream.StreamController().get_all(events=events)
204
205
        received_messages = dispatch_and_handle_mock_data(resp)
206
        self.assertEqual(len(received_messages), 0)
207
208
        # 2. ?action_refs= filter
209
        action_refs = ['invalid1', 'invalid2']
210
        action_refs = ','.join(action_refs)
211
        resp = stream.StreamController().get_all(action_refs=action_refs)
212
213
        received_messages = dispatch_and_handle_mock_data(resp)
214
        self.assertEqual(len(received_messages), 0)
215
216
        action_refs = ['dummy.action1']
217
        action_refs = ','.join(action_refs)
218
        resp = stream.StreamController().get_all(action_refs=action_refs)
219
220
        received_messages = dispatch_and_handle_mock_data(resp)
221
        self.assertEqual(len(received_messages), 1)
222
223
        # 3. ?execution_ids= filter
224
        execution_ids = ['invalid1', 'invalid2']
225
        execution_ids = ','.join(execution_ids)
226
        resp = stream.StreamController().get_all(execution_ids=execution_ids)
227
228
        received_messages = dispatch_and_handle_mock_data(resp)
229
        self.assertEqual(len(received_messages), 0)
230
231
        execution_ids = [EXECUTION_1['id']]
232
        execution_ids = ','.join(execution_ids)
233
        resp = stream.StreamController().get_all(execution_ids=execution_ids)
234
235
        received_messages = dispatch_and_handle_mock_data(resp)
236
        self.assertEqual(len(received_messages), 3)
237