Test Failed
Push — master ( 94b1f7...ff0954 )
by Oleksandr
12:55 queued 02:06
created

tests.unit.server_tests.test_config   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 339
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 36
eloc 234
dl 0
loc 339
rs 9.52
c 0
b 0
f 0

29 Methods

Rating   Name   Duplication   Size   Complexity  
A TestTransferProtocolValidation.test_https_without_key() 0 10 1
A TestConfigEnvironmentCalls.test_no_state_ini_file_or_state_dir() 0 15 1
A TestTransferProtocolValidation.test_invalid_protocol() 0 5 1
A TestTransferProtocolValidation.__init__() 0 3 1
A TestTransferProtocolValidation.test_https_without_cert() 0 8 1
A TestCertificateValidation.test_future_cert() 0 7 1
A TestTransferProtocolValidation.tearDown() 0 3 1
A TestPartialConfigFile.test_custom_evaluate_timeout_invalid() 0 15 2
A TestPartialConfigFile.tearDown() 0 3 1
A TestPartialConfigFile.setUp() 0 2 1
A TestConfigEnvironmentCalls.test_config_file_does_not_exist() 0 12 1
A TestTransferProtocolValidation.test_https_cert_file_not_found() 0 16 2
A TestCertificateValidation.test_valid_cert() 0 3 1
A TestTransferProtocolValidation.test_https_success() 0 16 1
A TestTransferProtocolValidation.mock_isfile() 0 5 2
A TestPartialConfigFile.test_config_file_present() 0 38 1
A TestCertificateValidation.assertValidateCertRaisesRuntimeError() 0 4 2
A TestPartialConfigFile.test_env_variables_in_config() 0 14 1
A TestTransferProtocolValidation.test_https_cert_and_key_file_not_found() 0 14 2
A TestTransferProtocolValidation.test_https_without_cert_and_key() 0 6 1
A TestTransferProtocolValidation.test_http() 0 6 1
A TestConfigEnvironmentCalls.test_no_config_file() 0 29 1
A TestTransferProtocolValidation.test_https_key_file_not_found() 0 16 2
A TestPartialConfigFile.test_custom_evaluate_timeout_valid() 0 13 1
A TestTransferProtocolValidation.assertTabPyAppRaisesRuntimeError() 0 4 2
A TestCertificateValidation.test_expired_cert() 0 7 1
A TestCertificateValidation.__init__() 0 3 1
A TestTransferProtocolValidation.raise_attribute_error() 0 3 1
A TestTransferProtocolValidation.setUp() 0 2 1
1
import os
2
import unittest
3
from tempfile import NamedTemporaryFile
4
import tabpy
5
from tabpy.tabpy_server.app.util import validate_cert
6
from tabpy.tabpy_server.app.app import TabPyApp
7
8
from unittest.mock import patch
9
10
11
class TestConfigEnvironmentCalls(unittest.TestCase):
12
    def test_config_file_does_not_exist(self):
13
        app = TabPyApp("/folder_does_not_exit/file_does_not_exist.conf")
14
15
        self.assertEqual(app.settings["port"], 9004)
16
        self.assertEqual(
17
            app.settings["server_version"], open("tabpy/VERSION").read().strip()
18
        )
19
        self.assertEqual(app.settings["transfer_protocol"], "http")
20
        self.assertTrue("certificate_file" not in app.settings)
21
        self.assertTrue("key_file" not in app.settings)
22
        self.assertEqual(app.settings["log_request_context"], False)
23
        self.assertEqual(app.settings["evaluate_timeout"], 30)
24
25
    @patch("tabpy.tabpy_server.app.app.TabPyState")
26
    @patch("tabpy.tabpy_server.app.app._get_state_from_file")
27
    @patch("tabpy.tabpy_server.app.app.PythonServiceHandler")
28
    @patch("tabpy.tabpy_server.app.app.os.path.exists", return_value=True)
29
    @patch("tabpy.tabpy_server.app.app.os")
30
    def test_no_config_file(
31
        self,
32
        mock_os,
33
        mock_path_exists,
34
        mock_psws,
35
        mock_management_util,
36
        mock_tabpy_state,
37
    ):
38
        pkg_path = os.path.dirname(tabpy.__file__)
39
        obj_path = os.path.join(pkg_path, "tmp", "query_objects")
40
        state_path = os.path.join(pkg_path, "tabpy_server")
41
        mock_os.environ = {
42
            "TABPY_PORT": "9004",
43
            "TABPY_QUERY_OBJECT_PATH": obj_path,
44
            "TABPY_STATE_PATH": state_path,
45
        }
46
47
        TabPyApp(None)
48
49
        self.assertEqual(len(mock_psws.mock_calls), 1)
50
        self.assertEqual(len(mock_tabpy_state.mock_calls), 1)
51
        self.assertEqual(len(mock_path_exists.mock_calls), 1)
52
        self.assertTrue(len(mock_management_util.mock_calls) > 0)
53
        mock_os.makedirs.assert_not_called()
54
55
    @patch("tabpy.tabpy_server.app.app.TabPyState")
56
    @patch("tabpy.tabpy_server.app.app._get_state_from_file")
57
    @patch("tabpy.tabpy_server.app.app.PythonServiceHandler")
58
    @patch("tabpy.tabpy_server.app.app.os.path.exists", return_value=False)
59
    @patch("tabpy.tabpy_server.app.app.os")
60
    def test_no_state_ini_file_or_state_dir(
61
        self,
62
        mock_os,
63
        mock_path_exists,
64
        mock_psws,
65
        mock_management_util,
66
        mock_tabpy_state,
67
    ):
68
        TabPyApp(None)
69
        self.assertEqual(len(mock_os.makedirs.mock_calls), 1)
70
71
72
class TestPartialConfigFile(unittest.TestCase):
73
    def setUp(self):
74
        self.config_file = NamedTemporaryFile(delete=False)
75
76
    def tearDown(self):
77
        os.remove(self.config_file.name)
78
        self.config_file = None
79
80
    @patch("tabpy.tabpy_server.app.app.TabPyState")
81
    @patch("tabpy.tabpy_server.app.app._get_state_from_file")
82
    @patch("tabpy.tabpy_server.app.app.PythonServiceHandler")
83
    @patch("tabpy.tabpy_server.app.app.os.path.exists", return_value=True)
84
    @patch("tabpy.tabpy_server.app.app.os")
85
    def test_config_file_present(
86
        self,
87
        mock_os,
88
        mock_path_exists,
89
        mock_psws,
90
        mock_management_util,
91
        mock_tabpy_state,
92
    ):
93
        self.assertTrue(self.config_file is not None)
94
        config_file = self.config_file
95
        config_file.write(
96
            "[TabPy]\n"
97
            "TABPY_QUERY_OBJECT_PATH = foo\n"
98
            "TABPY_STATE_PATH = bar\n".encode()
99
        )
100
        config_file.close()
101
102
        mock_os.path.realpath.return_value = "bar"
103
        mock_os.environ = {"TABPY_PORT": "1234"}
104
105
        app = TabPyApp(config_file.name)
106
107
        self.assertEqual(app.settings["port"], "1234")
108
        self.assertEqual(
109
            app.settings["server_version"], open("tabpy/VERSION").read().strip()
110
        )
111
        self.assertEqual(app.settings["upload_dir"], "foo")
112
        self.assertEqual(app.settings["state_file_path"], "bar")
113
        self.assertEqual(app.settings["transfer_protocol"], "http")
114
        self.assertTrue("certificate_file" not in app.settings)
115
        self.assertTrue("key_file" not in app.settings)
116
        self.assertEqual(app.settings["log_request_context"], False)
117
        self.assertEqual(app.settings["evaluate_timeout"], 30)
118
119
    @patch("tabpy.tabpy_server.app.app.os.path.exists", return_value=True)
120
    @patch("tabpy.tabpy_server.app.app._get_state_from_file")
121
    @patch("tabpy.tabpy_server.app.app.TabPyState")
122
    def test_custom_evaluate_timeout_valid(
123
        self, mock_state, mock_get_state_from_file, mock_path_exists
124
    ):
125
        self.assertTrue(self.config_file is not None)
126
        config_file = self.config_file
127
        config_file.write("[TabPy]\n" "TABPY_EVALUATE_TIMEOUT = 1996".encode())
128
        config_file.close()
129
130
        app = TabPyApp(self.config_file.name)
131
        self.assertEqual(app.settings["evaluate_timeout"], 1996.0)
132
133
    @patch("tabpy.tabpy_server.app.app.os.path.exists", return_value=True)
134
    @patch("tabpy.tabpy_server.app.app._get_state_from_file")
135
    @patch("tabpy.tabpy_server.app.app.TabPyState")
136
    def test_custom_evaluate_timeout_invalid(
137
        self, mock_state, mock_get_state_from_file, mock_path_exists
138
    ):
139
        self.assertTrue(self.config_file is not None)
140
        config_file = self.config_file
141
        config_file.write(
142
            "[TabPy]\n" 'TABPY_EVALUATE_TIMEOUT = "im not a float"'.encode()
143
        )
144
        config_file.close()
145
146
        with self.assertRaises(ValueError):
147
            TabPyApp(self.config_file.name)
148
149
    @patch("tabpy.tabpy_server.app.app.os")
150
    @patch("tabpy.tabpy_server.app.app.os.path.exists", return_value=True)
151
    @patch("tabpy.tabpy_server.app.app._get_state_from_file")
152
    @patch("tabpy.tabpy_server.app.app.TabPyState")
153
    def test_env_variables_in_config(
154
        self, mock_state, mock_get_state, mock_path_exists, mock_os
155
    ):
156
        mock_os.environ = {"foo": "baz"}
157
        config_file = self.config_file
158
        config_file.write("[TabPy]\n" "TABPY_PORT = %(foo)sbar".encode())
159
        config_file.close()
160
161
        app = TabPyApp(self.config_file.name)
162
        self.assertEqual(app.settings["port"], "bazbar")
163
164
165
class TestTransferProtocolValidation(unittest.TestCase):
166
    def assertTabPyAppRaisesRuntimeError(self, expected_message):
167
        with self.assertRaises(RuntimeError) as err:
168
            TabPyApp(self.fp.name)
169
        self.assertEqual(err.exception.args[0], expected_message)
170
171
    @staticmethod
172
    def mock_isfile(target_file, existing_files):
173
        if target_file in existing_files:
174
            return True
175
        return False
176
177
    @staticmethod
178
    def raise_attribute_error():
179
        raise AttributeError()
180
181
    def __init__(self, *args, **kwargs):
182
        super(TestTransferProtocolValidation, self).__init__(*args, **kwargs)
183
        self.fp = None
184
185
    def setUp(self):
186
        self.fp = NamedTemporaryFile(mode="w+t", delete=False)
187
188
    def tearDown(self):
189
        os.remove(self.fp.name)
190
        self.fp = None
191
192
    def test_invalid_protocol(self):
193
        self.fp.write("[TabPy]\n" "TABPY_TRANSFER_PROTOCOL = gopher")
194
        self.fp.close()
195
196
        self.assertTabPyAppRaisesRuntimeError("Unsupported transfer protocol: gopher")
197
198
    def test_http(self):
199
        self.fp.write("[TabPy]\n" "TABPY_TRANSFER_PROTOCOL = http")
200
        self.fp.close()
201
202
        app = TabPyApp(self.fp.name)
203
        self.assertEqual(app.settings["transfer_protocol"], "http")
204
205
    def test_https_without_cert_and_key(self):
206
        self.fp.write("[TabPy]\n" "TABPY_TRANSFER_PROTOCOL = https")
207
        self.fp.close()
208
209
        self.assertTabPyAppRaisesRuntimeError(
210
            "Error using HTTPS: The paramete"
211
            "r(s) TABPY_CERTIFICATE_FILE and"
212
            " TABPY_KEY_FILE must be set."
213
        )
214
215
    def test_https_without_cert(self):
216
        self.fp.write(
217
            "[TabPy]\n" "TABPY_TRANSFER_PROTOCOL = https\n" "TABPY_KEY_FILE = foo"
218
        )
219
        self.fp.close()
220
221
        self.assertTabPyAppRaisesRuntimeError(
222
            "Error using HTTPS: The parameter(s) TABPY_CERTIFICATE_FILE must " "be set."
223
        )
224
225
    def test_https_without_key(self):
226
        self.fp.write(
227
            "[TabPy]\n"
228
            "TABPY_TRANSFER_PROTOCOL = https\n"
229
            "TABPY_CERTIFICATE_FILE = foo"
230
        )
231
        self.fp.close()
232
233
        self.assertTabPyAppRaisesRuntimeError(
234
            "Error using HTTPS: The parameter(s) TABPY_KEY_FILE must be set."
235
        )
236
237
    @patch("tabpy.tabpy_server.app.app.os.path")
238
    def test_https_cert_and_key_file_not_found(self, mock_path):
239
        self.fp.write(
240
            "[TabPy]\n"
241
            "TABPY_TRANSFER_PROTOCOL = https\n"
242
            "TABPY_CERTIFICATE_FILE = foo\n"
243
            "TABPY_KEY_FILE = bar"
244
        )
245
        self.fp.close()
246
247
        mock_path.isfile.side_effect = lambda x: self.mock_isfile(x, {self.fp.name})
248
249
        self.assertTabPyAppRaisesRuntimeError(
250
            "Error using HTTPS: The parameter(s) TABPY_CERTIFICATE_FILE and "
251
            "TABPY_KEY_FILE must point to an existing file."
252
        )
253
254
    @patch("tabpy.tabpy_server.app.app.os.path")
255
    def test_https_cert_file_not_found(self, mock_path):
256
        self.fp.write(
257
            "[TabPy]\n"
258
            "TABPY_TRANSFER_PROTOCOL = https\n"
259
            "TABPY_CERTIFICATE_FILE = foo\n"
260
            "TABPY_KEY_FILE = bar"
261
        )
262
        self.fp.close()
263
264
        mock_path.isfile.side_effect = lambda x: self.mock_isfile(
265
            x, {self.fp.name, "bar"}
266
        )
267
268
        self.assertTabPyAppRaisesRuntimeError(
269
            "Error using HTTPS: The parameter(s) TABPY_CERTIFICATE_FILE "
270
            "must point to an existing file."
271
        )
272
273
    @patch("tabpy.tabpy_server.app.app.os.path")
274
    def test_https_key_file_not_found(self, mock_path):
275
        self.fp.write(
276
            "[TabPy]\n"
277
            "TABPY_TRANSFER_PROTOCOL = https\n"
278
            "TABPY_CERTIFICATE_FILE = foo\n"
279
            "TABPY_KEY_FILE = bar"
280
        )
281
        self.fp.close()
282
283
        mock_path.isfile.side_effect = lambda x: self.mock_isfile(
284
            x, {self.fp.name, "foo"}
285
        )
286
287
        self.assertTabPyAppRaisesRuntimeError(
288
            "Error using HTTPS: The parameter(s) TABPY_KEY_FILE "
289
            "must point to an existing file."
290
        )
291
292
    @patch("tabpy.tabpy_server.app.app.os.path.isfile", return_value=True)
293
    @patch("tabpy.tabpy_server.app.util.validate_cert")
294
    def test_https_success(self, mock_isfile, mock_validate_cert):
295
        self.fp.write(
296
            "[TabPy]\n"
297
            "TABPY_TRANSFER_PROTOCOL = HtTpS\n"
298
            "TABPY_CERTIFICATE_FILE = foo\n"
299
            "TABPY_KEY_FILE = bar"
300
        )
301
        self.fp.close()
302
303
        app = TabPyApp(self.fp.name)
304
305
        self.assertEqual(app.settings["transfer_protocol"], "https")
306
        self.assertEqual(app.settings["certificate_file"], "foo")
307
        self.assertEqual(app.settings["key_file"], "bar")
308
309
310
class TestCertificateValidation(unittest.TestCase):
311
    def assertValidateCertRaisesRuntimeError(self, expected_message, path):
312
        with self.assertRaises(RuntimeError) as err:
313
            validate_cert(path)
314
        self.assertEqual(err.exception.args[0], expected_message)
315
316
    def __init__(self, *args, **kwargs):
317
        super(TestCertificateValidation, self).__init__(*args, **kwargs)
318
        self.resources_path = os.path.join(os.path.dirname(__file__), "resources")
319
320
    def test_expired_cert(self):
321
        path = os.path.join(self.resources_path, "expired.crt")
322
        message = (
323
            "Error using HTTPS: The certificate provided expired "
324
            "on 2018-08-18 19:47:18."
325
        )
326
        self.assertValidateCertRaisesRuntimeError(message, path)
327
328
    def test_future_cert(self):
329
        path = os.path.join(self.resources_path, "future.crt")
330
        message = (
331
            "Error using HTTPS: The certificate provided is not valid "
332
            "until 3001-01-01 00:00:00."
333
        )
334
        self.assertValidateCertRaisesRuntimeError(message, path)
335
336
    def test_valid_cert(self):
337
        path = os.path.join(self.resources_path, "valid.crt")
338
        validate_cert(path)
339