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

BaseFunctionalTest   A

Complexity

Total Complexity 3

Size/Duplication

Total Lines 32
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 32
rs 10
wmc 3

2 Methods

Rating   Name   Duplication   Size   Complexity  
A _do_setUpClass() 0 14 2
A setUpClass() 0 4 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
"""
17
Various base classes and test utility functions for API related tests.
18
"""
19
20
import webtest
21
import mock
22
from oslo_config import cfg
23
24
from st2common.router import Router
25
from st2common.rbac.types import SystemRole
26
from st2common.persistence.auth import User
27
from st2common.persistence.rbac import UserRoleAssignment
28
from st2common.models.db.auth import UserDB
29
from st2common.models.db.rbac import UserRoleAssignmentDB
30
from st2common.rbac.migrations import run_all as run_all_rbac_migrations
31
from st2common.bootstrap import runnersregistrar as runners_registrar
32
from st2tests.base import DbTestCase
33
from st2tests.base import CleanDbTestCase
34
from st2tests import config as tests_config
35
36
__all__ = [
37
    'BaseFunctionalTest',
38
    'BaseAPIControllerWithRBACTestCase',
39
40
    'TestApp'
41
]
42
43
44
SUPER_SECRET_PARAMETER = 'SUPER_SECRET_PARAMETER_THAT_SHOULD_NEVER_APPEAR_IN_RESPONSES_OR_LOGS'
45
ANOTHER_SUPER_SECRET_PARAMETER = 'ANOTHER_SUPER_SECRET_PARAMETER_TO_TEST_OVERRIDING'
46
47
48
class ResponseValidationError(ValueError):
49
    pass
50
51
52
class ResponseLeakError(ValueError):
53
    pass
54
55
56
class TestApp(webtest.TestApp):
57
    def do_request(self, req, **kwargs):
58
        self.cookiejar.clear()
59
60
        if req.environ['REQUEST_METHOD'] != 'OPTIONS':
61
            # Making sure endpoint handles OPTIONS method properly
62
            self.options(req.environ['PATH_INFO'])
63
64
        res = super(TestApp, self).do_request(req, **kwargs)
65
66
        if res.headers.get('Warning', None):
67
            raise ResponseValidationError('Endpoint produced invalid response. Make sure the '
68
                                          'response matches OpenAPI scheme for the endpoint.')
69
70
        if not kwargs.get('expect_errors', None):
71
            if SUPER_SECRET_PARAMETER in res.body or ANOTHER_SUPER_SECRET_PARAMETER in res.body:
72
                raise ResponseLeakError('Endpoint response contains secret parameter. '
73
                                        'Find the leak.')
74
75
        if 'Access-Control-Allow-Origin' not in res.headers:
76
            raise ResponseValidationError('Response missing a required CORS header')
77
78
        return res
79
80
81
class BaseFunctionalTest(DbTestCase):
82
    """
83
    Base test case class for testing API controllers with auth and RBAC disabled.
84
    """
85
86
    # App used by the tests
87
    app_module = None
88
89
    # By default auth is disabled
90
    enable_auth = False
91
92
    register_runners = True
93
94
    @classmethod
95
    def setUpClass(cls):
96
        super(BaseFunctionalTest, cls).setUpClass()
97
        cls._do_setUpClass()
98
99
    @classmethod
100
    def _do_setUpClass(cls):
101
        tests_config.parse_args()
102
103
        cfg.CONF.set_default('enable', cls.enable_auth, group='auth')
104
105
        cfg.CONF.set_override(name='enable', override=False, group='rbac')
106
107
        # TODO(manas) : register action types here for now. RunnerType registration can be moved
108
        # to posting to /runnertypes but that implies implementing POST.
109
        if cls.register_runners:
110
            runners_registrar.register_runners()
111
112
        cls.app = TestApp(cls.app_module.setup_app())
113
114
115
class BaseAPIControllerWithRBACTestCase(BaseFunctionalTest, CleanDbTestCase):
116
    """
117
    Base test case class for testing API controllers with RBAC enabled.
118
    """
119
120
    enable_auth = True
121
122
    @classmethod
123
    def setUpClass(cls):
124
        super(BaseAPIControllerWithRBACTestCase, cls).setUpClass()
125
126
        # Make sure RBAC is enabeld
127
        cfg.CONF.set_override(name='enable', override=True, group='rbac')
128
129
    @classmethod
130
    def tearDownClass(cls):
131
        super(BaseAPIControllerWithRBACTestCase, cls).tearDownClass()
132
133
    def setUp(self):
134
        super(BaseAPIControllerWithRBACTestCase, self).setUp()
135
136
        self.users = {}
137
        self.roles = {}
138
139
        # Run RBAC migrations
140
        run_all_rbac_migrations()
141
142
        # Insert mock users with default role assignments
143
        role_names = [SystemRole.SYSTEM_ADMIN, SystemRole.ADMIN, SystemRole.OBSERVER]
144
        for role_name in role_names:
145
            user_db = UserDB(name=role_name)
146
            user_db = User.add_or_update(user_db)
147
            self.users[role_name] = user_db
148
149
            role_assignment_db = UserRoleAssignmentDB(
150
                user=user_db.name,
151
                role=role_name)
152
            UserRoleAssignment.add_or_update(role_assignment_db)
153
154
        # Insert a user with no permissions and role assignments
155
        user_1_db = UserDB(name='no_permissions')
156
        user_1_db = User.add_or_update(user_1_db)
157
        self.users['no_permissions'] = user_1_db
158
159
    def tearDown(self):
160
        super(BaseAPIControllerWithRBACTestCase, self).tearDown()
161
162
        if getattr(self, 'request_context_mock', None):
163
            self.request_context_mock.stop()
164
            del(Router.mock_context)
0 ignored issues
show
Unused Code Coding Style introduced by
There is an unnecessary parenthesis after del.
Loading history...
165
166
    def use_user(self, user_db):
167
        """
168
        Select a user which is to be used by the HTTP request following this call.
169
        """
170
        if not user_db:
171
            raise ValueError('"user_db" is mandatory')
172
173
        mock_context = {
174
            'user': user_db
175
        }
176
        self.request_context_mock = mock.PropertyMock(return_value=mock_context)
177
        Router.mock_context = self.request_context_mock
178