コード例 #1
0
ファイル: test_config.py プロジェクト: twiese86/TabPy
 def test_no_state_ini_file_or_state_dir(self, mock_os, mock_file_exists,
                                         mock_path_exists, mock_psws,
                                         mock_management_util,
                                         mock_tabpy_state,
                                         mock_parse_arguments):
     TabPyApp(None)
     self.assertEqual(len(mock_os.makedirs.mock_calls), 1)
コード例 #2
0
ファイル: test_config.py プロジェクト: twiese86/TabPy
    def test_http(self):
        self.fp.write("[TabPy]\n"
                      "TABPY_TRANSFER_PROTOCOL = http")
        self.fp.close()

        app = TabPyApp(self.fp.name)
        self.assertEqual(app.settings['transfer_protocol'], 'http')
コード例 #3
0
ファイル: test_config.py プロジェクト: twiese86/TabPy
    def test_config_file_present(self, mock_os, mock_path_exists,
                                 mock_psws, mock_management_util,
                                 mock_tabpy_state, mock_parse_arguments):
        config_file = NamedTemporaryFile(delete=False)

        config_file.write("[TabPy]\n"
                          "TABPY_QUERY_OBJECT_PATH = foo\n"
                          "TABPY_STATE_PATH = bar\n".encode())
        config_file.close()

        mock_parse_arguments.return_value = Namespace(config=config_file.name)

        mock_os.getenv.side_effect = [1234]
        mock_os.path.realpath.return_value = 'bar'

        app = TabPyApp(config_file.name)
        getenv_calls = [call('TABPY_PORT', 9004)]

        mock_os.getenv.assert_has_calls(getenv_calls, any_order=True)
        self.assertEqual(app.settings['port'], 1234)
        self.assertEqual(app.settings['server_version'],
                         open('VERSION').read().strip())
        self.assertEqual(app.settings['upload_dir'], 'foo')
        self.assertEqual(app.settings['state_file_path'], 'bar')
        self.assertEqual(app.settings['transfer_protocol'], 'http')
        self.assertTrue('certificate_file' not in app.settings)
        self.assertTrue('key_file' not in app.settings)

        os.remove(config_file.name)
コード例 #4
0
class TestServiceInfoHandlerDefault(AsyncHTTPTestCase):
    @classmethod
    def setUpClass(cls):
        cls.patcher = patch(
            'tabpy_server.app.app.TabPyApp._parse_cli_arguments',
            return_value=Namespace(
                config=None))
        cls.patcher.start()

    @classmethod
    def tearDownClass(cls):
        cls.patcher.stop()

    def get_app(self):
        self.app = TabPyApp()
        return self.app._create_tornado_web_app()

    def test_given_vanilla_tabpy_server_expect_correct_info_response(self):
        response = self.fetch('/info')
        self.assertEqual(response.code, 200)
        actual_response = json.loads(response.body)
        expected_response = _create_expected_info_response(
            self.app.settings, self.app.tabpy_state)

        self.assertDictEqual(actual_response, expected_response)
コード例 #5
0
class TestServiceInfoHandlerWithoutAuth(AsyncHTTPTestCase):
    @classmethod
    def setUpClass(cls):
        prefix = '__TestServiceInfoHandlerWithoutAuth_'

        # create state.ini dir and file
        cls.state_dir = tempfile.mkdtemp(prefix=prefix)
        with open(os.path.join(cls.state_dir, 'state.ini'), 'w+')\
                as cls.state_file:
            cls.state_file.write('[Service Info]\n'
                                 'Name = TabPy Serve\n'
                                 'Description = \n'
                                 'Creation Time = 0\n'
                                 'Access-Control-Allow-Origin = \n'
                                 'Access-Control-Allow-Headers = \n'
                                 'Access-Control-Allow-Methods = \n'
                                 '\n'
                                 '[Query Objects Service Versions]\n'
                                 '\n'
                                 '[Query Objects Docstrings]\n'
                                 '\n'
                                 '[Meta]\n'
                                 'Revision Number = 1\n')
        cls.state_file.close()

        # create config file
        cls.config_file = tempfile.NamedTemporaryFile(prefix=prefix,
                                                      suffix='.conf',
                                                      delete=False,
                                                      mode='w+')
        cls.config_file.write('[TabPy]\n'
                              'TABPY_STATE_PATH = {}'.format(cls.state_dir))
        cls.config_file.close()

    @classmethod
    def tearDownClass(cls):
        os.remove(cls.state_file.name)
        os.remove(cls.config_file.name)
        os.rmdir(cls.state_dir)

    def get_app(self):
        self.app = TabPyApp(self.config_file.name)
        return self.app._create_tornado_web_app()

    def test_tabpy_server_with_no_auth_expect_correct_info_response(self):
        response = self.fetch('/info')
        self.assertEqual(response.code, 200)
        actual_response = json.loads(response.body)
        expected_response = _create_expected_info_response(
            self.app.settings, self.app.tabpy_state)

        self.assertDictEqual(actual_response, expected_response)
        self.assertTrue('versions' in actual_response)
        versions = actual_response['versions']
        self.assertTrue('v1' in versions)
        v1 = versions['v1']
        self.assertTrue('features' in v1)
        features = v1['features']
        self.assertDictEqual({}, features)
コード例 #6
0
    def test_given_no_pwd_file_expect_empty_credentials_list(self):
        self._set_file(self.config_file.name, "[TabPy]\n"
                       "TABPY_TRANSFER_PROTOCOL = http")

        app = TabPyApp(self.config_file.name)
        self.assertDictEqual(
            app.credentials, {},
            'Expected no credentials with no password file provided')
コード例 #7
0
    def test_given_missing_pwd_file_expect_app_fails(self):
        self._set_file(self.config_file.name, "[TabPy]\n"
                       "TABPY_PWD_FILE = foo")

        with self.assertRaises(RuntimeError) as cm:
            TabPyApp(self.config_file.name)
            ex = cm.exception
            self.assertEqual(
                'Failed to read password file {}'.format(self.pwd_file.name),
                ex.args[0])
コード例 #8
0
    def test_custom_evaluate_timeout_invalid(self, mock_state,
                                             mock_get_state_from_file,
                                             mock_path_exists):
        self.assertTrue(self.config_file is not None)
        config_file = self.config_file
        config_file.write('[TabPy]\n'
                          'TABPY_EVALUATE_TIMEOUT = "im not a float"'.encode())
        config_file.close()

        app = TabPyApp(self.config_file.name)
        self.assertEqual(app.settings['evaluate_timeout'], 30.0)
コード例 #9
0
ファイル: test_config.py プロジェクト: twiese86/TabPy
    def test_https_success(self, mock_isfile, mock_validate_cert):
        self.fp.write("[TabPy]\n"
                      "TABPY_TRANSFER_PROTOCOL = HtTpS\n"
                      "TABPY_CERTIFICATE_FILE = foo\n"
                      "TABPY_KEY_FILE = bar")
        self.fp.close()

        app = TabPyApp(self.fp.name)

        self.assertEqual(app.settings['transfer_protocol'], 'https')
        self.assertEqual(app.settings['certificate_file'], 'foo')
        self.assertEqual(app.settings['key_file'], 'bar')
コード例 #10
0
    def test_given_empty_pwd_file_expect_app_fails(self):
        self._set_file(self.config_file.name,
                       '[TabPy]\n'
                       f'TABPY_PWD_FILE = {self.pwd_file.name}')

        self._set_file(self.pwd_file.name, "# just a comment")

        with self.assertRaises(RuntimeError) as cm:
            TabPyApp(self.config_file.name)
            ex = cm.exception
            self.assertEqual(
                f'Failed to read password file {self.pwd_file.name}',
                ex.args[0])
コード例 #11
0
    def test_given_different_cases_in_pwd_file_expect_app_fails(self):
        self._set_file(self.config_file.name,
                       "[TabPy]\n"
                       "TABPY_PWD_FILE = {}".format(self.pwd_file.name))

        self._set_file(self.pwd_file.name,
                       "# passwords\n"
                       "user1 pwd1\n"
                       "user_2 pwd#2"
                       "UseR1 pwd@3")

        with self.assertRaises(RuntimeError) as cm:
            TabPyApp(self.config_file.name)
            ex = cm.exception
            self.assertEqual('Failed to read password file {}'.format(
                self.pwd_file.name), ex.args[0])
コード例 #12
0
    def test_given_one_password_in_pwd_file_expect_one_credentials_entry(self):
        self._set_file(
            self.config_file.name, "[TabPy]\n"
            "TABPY_PWD_FILE = {}".format(self.pwd_file.name))

        login = '******'
        pwd = 'someting@something_else'
        self._set_file(self.pwd_file.name, "# passwords\n"
                       "\n"
                       "{} {}".format(login, pwd))

        app = TabPyApp(self.config_file.name)

        self.assertEqual(len(app.credentials), 1)
        self.assertIn(login, app.credentials)
        self.assertEqual(app.credentials[login], pwd)
コード例 #13
0
    def test_given_one_line_with_too_many_params_expect_app_fails(self):
        self._set_file(self.config_file.name,
                       "[TabPy]\n"
                       f'TABPY_PWD_FILE = {self.pwd_file.name}')

        self._set_file(self.pwd_file.name,
                       "# passwords\n"
                       "user1 pwd1\n"
                       "user_2 pwd#2"
                       "user1 pwd@3")

        with self.assertRaises(RuntimeError) as cm:
            TabPyApp(self.config_file.name)
            ex = cm.exception
            self.assertEqual(
                f'Failed to read password file {self.pwd_file.name}',
                ex.args[0])
コード例 #14
0
    def test_given_username_but_no_password_expect_parsing_fails(self):
        self._set_file(
            self.config_file.name, "[TabPy]\n"
            "TABPY_PWD_FILE = {}".format(self.pwd_file.name))

        login = '******'
        pwd = ''
        self._set_file(self.pwd_file.name, "# passwords\n"
                       "\n"
                       "{} {}".format(login, pwd))

        with self.assertRaises(RuntimeError) as cm:
            TabPyApp(self.config_file.name)
            ex = cm.exception
            self.assertEqual(
                'Failed to read password file {}'.format(self.pwd_file.name),
                ex.args[0])
コード例 #15
0
    def test_given_multiple_credentials_expect_all_parsed(self):
        self._set_file(
            self.config_file.name, "[TabPy]\n"
            "TABPY_PWD_FILE = {}".format(self.pwd_file.name))
        creds = {'user_1': 'pwd_1', 'user@2': 'pwd@2', 'user#3': 'pwd#3'}

        pwd_file_context = ""
        for login in creds:
            pwd_file_context += '{} {}\n'.format(login, creds[login])

        self._set_file(self.pwd_file.name, pwd_file_context)
        app = TabPyApp(self.config_file.name)

        self.assertCountEqual(creds, app.credentials)
        for login in creds:
            self.assertIn(login, app.credentials)
            self.assertEqual(creds[login], app.credentials[login])
コード例 #16
0
ファイル: test_config.py プロジェクト: twiese86/TabPy
    def test_no_config_file(self, mock_os, mock_file_exists,
                            mock_path_exists, mock_psws,
                            mock_management_util, mock_tabpy_state,
                            mock_parse_arguments):
        TabPyApp(None)

        getenv_calls = [call('TABPY_PORT', 9004),
                        call('TABPY_QUERY_OBJECT_PATH', '/tmp/query_objects'),
                        call('TABPY_STATE_PATH',
                             './tabpy-server/tabpy_server')]
        mock_os.getenv.assert_has_calls(getenv_calls, any_order=True)
        self.assertEqual(len(mock_file_exists.mock_calls), 2)
        self.assertEqual(len(mock_psws.mock_calls), 1)
        self.assertEqual(len(mock_tabpy_state.mock_calls), 1)
        self.assertEqual(len(mock_path_exists.mock_calls), 1)
        self.assertTrue(len(mock_management_util.mock_calls) > 0)
        mock_os.makedirs.assert_not_called()
コード例 #17
0
    def test_given_duplicate_usernames_expect_parsing_fails(self):
        self._set_file(self.config_file.name,
                       "[TabPy]\n"
                       f'TABPY_PWD_FILE = {self.pwd_file.name}')

        login = '******'
        pwd = 'hashedpw'
        self._set_file(self.pwd_file.name,
                       "# passwords\n"
                       "\n"
                       f'{login} {pwd}\n{login} {pwd}')

        with self.assertRaises(RuntimeError) as cm:
            TabPyApp(self.config_file.name)
            ex = cm.exception
            self.assertEqual(
                f'Failed to read password file {self.pwd_file.name}',
                ex.args[0])
コード例 #18
0
 def get_app(self):
     self.app = TabPyApp(self.config_file.name)
     return self.app._create_tornado_web_app()
コード例 #19
0
class TestEvaluationPlainHandlerWithAuth(AsyncHTTPTestCase):
    @classmethod
    def setUpClass(cls):
        cls.patcher = patch(
            'tabpy_server.app.app.TabPyApp._parse_cli_arguments',
            return_value=Namespace(config=None))
        cls.patcher.start()

        prefix = '__TestEvaluationPlainHandlerWithAuth_'
        # create password file
        cls.pwd_file = tempfile.NamedTemporaryFile(mode='w+t',
                                                   prefix=prefix,
                                                   suffix='.txt',
                                                   delete=False)
        username = '******'
        password = '******'
        cls.pwd_file.write(f'{username} {hash_password(username, password)}\n')
        cls.pwd_file.close()

        # create state.ini dir and file
        cls.state_dir = tempfile.mkdtemp(prefix=prefix)
        cls.state_file = open(os.path.join(cls.state_dir, 'state.ini'), 'w+')
        cls.state_file.write('[Service Info]\n'
                             'Name = TabPy Serve\n'
                             'Description = \n'
                             'Creation Time = 0\n'
                             'Access-Control-Allow-Origin = \n'
                             'Access-Control-Allow-Headers = \n'
                             'Access-Control-Allow-Methods = \n'
                             '\n'
                             '[Query Objects Service Versions]\n'
                             '\n'
                             '[Query Objects Docstrings]\n'
                             '\n'
                             '[Meta]\n'
                             'Revision Number = 1\n')
        cls.state_file.close()

        # create config file
        cls.config_file = tempfile.NamedTemporaryFile(mode='w+t',
                                                      prefix=prefix,
                                                      suffix='.conf',
                                                      delete=False)
        cls.config_file.write('[TabPy]\n'
                              f'TABPY_PWD_FILE = {cls.pwd_file.name}\n'
                              f'TABPY_STATE_PATH = {cls.state_dir}')
        cls.config_file.close()

        cls.script =\
            '{"data":{"_arg1":[2,3],"_arg2":[3,-1]},'\
            '"script":"res=[]\\nfor i in range(len(_arg1)):\\n  '\
            'res.append(_arg1[i] * _arg2[i])\\nreturn res"}'

        cls.script_not_present =\
            '{"data":{"_arg1":[2,3],"_arg2":[3,-1]},'\
            '"":"res=[]\\nfor i in range(len(_arg1)):\\n  '\
            'res.append(_arg1[i] * _arg2[i])\\nreturn res"}'

        cls.args_not_present =\
            '{"script":"res=[]\\nfor i in range(len(_arg1)):\\n  '\
            'res.append(_arg1[i] * _arg2[i])\\nreturn res"}'

        cls.args_not_sequential =\
            '{"data":{"_arg1":[2,3],"_arg3":[3,-1]},'\
            '"script":"res=[]\\nfor i in range(len(_arg1)):\\n  '\
            'res.append(_arg1[i] * _arg3[i])\\nreturn res"}'

    @classmethod
    def tearDownClass(cls):
        cls.patcher.stop()
        os.remove(cls.pwd_file.name)
        os.remove(cls.state_file.name)
        os.remove(cls.config_file.name)
        os.rmdir(cls.state_dir)

    def get_app(self):
        self.app = TabPyApp(self.config_file.name)
        return self.app._create_tornado_web_app()

    def test_no_creds_required_auth_fails(self):
        response = self.fetch('/evaluate', method='POST', body=self.script)
        self.assertEqual(401, response.code)

    def test_invalid_creds_fails(self):
        response = self.fetch(
            '/evaluate',
            method='POST',
            body=self.script,
            headers={
                'Authorization':
                'Basic {}'.format(
                    base64.b64encode(
                        'user:wrong_password'.encode('utf-8')).decode('utf-8'))
            })
        self.assertEqual(401, response.code)

    def test_valid_creds_pass(self):
        response = self.fetch(
            '/evaluate',
            method='POST',
            body=self.script,
            headers={
                'Authorization':
                'Basic {}'.format(
                    base64.b64encode(
                        'username:password'.encode('utf-8')).decode('utf-8'))
            })
        self.assertEqual(200, response.code)

    def test_null_request(self):
        response = self.fetch('')
        self.assertEqual(404, response.code)

    def test_script_not_present(self):
        response = self.fetch(
            '/evaluate',
            method='POST',
            body=self.script_not_present,
            headers={
                'Authorization':
                'Basic {}'.format(
                    base64.b64encode(
                        'username:password'.encode('utf-8')).decode('utf-8'))
            })
        self.assertEqual(400, response.code)

    def test_arguments_not_present(self):
        response = self.fetch(
            '/evaluate',
            method='POST',
            body=self.args_not_present,
            headers={
                'Authorization':
                'Basic {}'.format(
                    base64.b64encode(
                        'username:password'.encode('utf-8')).decode('utf-8'))
            })
        self.assertEqual(500, response.code)

    def test_arguments_not_sequential(self):
        response = self.fetch(
            '/evaluate',
            method='POST',
            body=self.args_not_sequential,
            headers={
                'Authorization':
                'Basic {}'.format(
                    base64.b64encode(
                        'username:password'.encode('utf-8')).decode('utf-8'))
            })
        self.assertEqual(400, response.code)
コード例 #20
0
def main():
    app = TabPyApp()
    app.run()
コード例 #21
0
 def get_app(self):
     self.app = TabPyApp()
     return self.app._create_tornado_web_app()
コード例 #22
0
class TestEndpointHandlerWithAuth(AsyncHTTPTestCase):
    @classmethod
    def setUpClass(cls):
        cls.patcher = patch(
            'tabpy_server.app.app.TabPyApp._parse_cli_arguments',
            return_value=Namespace(
                config=None))
        cls.patcher.start()

        prefix = '__TestEndpointHandlerWithAuth_'
        # create password file
        cls.pwd_file = tempfile.NamedTemporaryFile(
            mode='w+t', prefix=prefix, suffix='.txt', delete=False)
        username = '******'
        password = '******'
        cls.pwd_file.write('{} {}'.format(
            username,
            hash_password(username, password)))
        cls.pwd_file.close()

        # create state.ini dir and file
        cls.state_dir = tempfile.mkdtemp(prefix=prefix)
        cls.state_file = open(os.path.join(cls.state_dir, 'state.ini'), 'w+')
        cls.state_file.write('[Service Info]\n'
                             'Name = TabPy Serve\n'
                             'Description = \n'
                             'Creation Time = 0\n'
                             'Access-Control-Allow-Origin = \n'
                             'Access-Control-Allow-Headers = \n'
                             'Access-Control-Allow-Methods = \n'
                             '\n'
                             '[Query Objects Service Versions]\n'
                             '\n'
                             '[Query Objects Docstrings]\n'
                             '\n'
                             '[Meta]\n'
                             'Revision Number = 1\n')
        cls.state_file.close()

        # create config file
        cls.config_file = tempfile.NamedTemporaryFile(
            mode='w+t', prefix=prefix, suffix='.conf', delete=False)
        cls.config_file.write(
            '[TabPy]\n'
            'TABPY_PWD_FILE = {}\n'
            'TABPY_STATE_PATH = {}'.format(
                cls.pwd_file.name,
                cls.state_dir))
        cls.config_file.close()

    @classmethod
    def tearDownClass(cls):
        cls.patcher.stop()
        os.remove(cls.pwd_file.name)
        os.remove(cls.state_file.name)
        os.remove(cls.config_file.name)
        os.rmdir(cls.state_dir)

    def get_app(self):
        self.app = TabPyApp(self.config_file.name)
        return self.app._create_tornado_web_app()

    def test_no_creds_required_auth_fails(self):
        response = self.fetch('/endpoints/anything')
        self.assertEqual(401, response.code)

    def test_invalid_creds_fails(self):
        response = self.fetch(
            '/endpoints/anything',
            method='GET',
            headers={
                'Authorization': 'Basic {}'.
                format(
                    base64.b64encode('user:wrong_password'.encode('utf-8')).
                    decode('utf-8'))
            })
        self.assertEqual(401, response.code)

    def test_valid_creds_pass(self):
        response = self.fetch(
            '/endpoints/',
            method='GET',
            headers={
                'Authorization': 'Basic {}'.
                format(
                    base64.b64encode('username:password'.encode('utf-8')).
                    decode('utf-8'))
            })
        self.assertEqual(200, response.code)

    def test_valid_creds_unknown_endpoint_fails(self):
        response = self.fetch(
            '/endpoints/unknown_endpoint',
            method='GET',
            headers={
                'Authorization': 'Basic {}'.
                format(
                    base64.b64encode('username:password'.encode('utf-8')).
                    decode('utf-8'))
            })
        self.assertEqual(404, response.code)