def _handle_er_incomplete_params(method: TEventHandler):
        # Setup:
        # ... Create an OE service
        oe = ObjectExplorerService()
        oe._service_provider = utils.get_mock_service_provider({})

        # ... Create a set of invalid parameters to test
        param_sets = [
            None,
            ExpandParameters.from_dict({
                'session_id': None,
                'node_path': '/'
            }),
            ExpandParameters.from_dict({
                'session_id': 'session',
                'node_path': None
            })
        ]

        for params in param_sets:
            # If: I expand with an invalid set of parameters
            rc = RequestFlowValidator().add_expected_error(
                type(None), RequestFlowValidator.basic_error_validation)
            method(oe, rc.request_context, params)

            # Then: I should get an error response
            rc.validate()
    def test_generate_uri_missing_params(self):
        # Setup: Create the parameter sets that will be missing a param each
        params = [
            ConnectionDetails.from_data({
                'host': None,
                'dbname': TEST_DBNAME,
                'user': TEST_USER,
                'port': TEST_PORT
            }),
            ConnectionDetails.from_data({
                'host': TEST_HOST,
                'dbname': None,
                'user': TEST_USER,
                'port': TEST_PORT
            }),
            ConnectionDetails.from_data({
                'host': TEST_HOST,
                'dbname': TEST_DBNAME,
                'user': None,
                'port': TEST_PORT
            }),
            ConnectionDetails.from_data({
                'host': TEST_HOST,
                'dbname': TEST_DBNAME,
                'user': TEST_USER,
                'port': None
            })
        ]

        for param_set in params:
            # If: I generate a session URI from params that are missing a value
            # Then: I should get an exception
            with self.assertRaises(Exception):
                ObjectExplorerService._generate_session_uri(
                    param_set, constants.PG_PROVIDER_NAME)
    def _preloaded_oe_service(
            self) -> Tuple[ObjectExplorerService, ObjectExplorerSession, str]:
        oe = ObjectExplorerService()
        oe._service_provider = utils.get_mock_service_provider({})
        oe._routing_table = PG_ROUTING_TABLE

        conn_details, session_uri = _connection_details()
        session = ObjectExplorerSession(session_uri, conn_details)
        session.server = mock.Mock()
        session.is_ready = True
        oe._session_map[session_uri] = session

        return oe, session, session_uri
    def _handle_er_no_session_match(method: TEventHandler):
        # Setup: Create an OE service
        oe = ObjectExplorerService()
        oe._service_provider = utils.get_mock_service_provider({})

        # If: I expand a node on a session that doesn't exist
        rc = RequestFlowValidator().add_expected_error(
            type(None), RequestFlowValidator.basic_error_validation)
        params = ExpandParameters.from_dict({
            'session_id': 'session',
            'node_path': None
        })
        method(oe, rc.request_context, params)

        # Then: I should get an error back
        rc.validate()
    def test_handle_create_session_missing_params(self):
        # Setup: Create an OE service
        oe = ObjectExplorerService()
        oe._service_provider = utils.get_mock_service_provider({})

        # If: I create an OE session with missing params
        rc = RequestFlowValidator().add_expected_error(
            type(None), RequestFlowValidator.basic_error_validation)
        oe._handle_create_session_request(rc.request_context, None)

        # Then:
        # ... I should get an error response
        rc.validate()

        # ... A session should not have been created
        self.assertDictEqual(oe._session_map, {})
    def test_create_connection_successful(self):
        # Setup:
        mock_connection = MockPGServerConnection()
        oe = ObjectExplorerService()
        cs = ConnectionService()
        cs.connect = mock.MagicMock(return_value=ConnectionCompleteParams())
        cs.get_connection = mock.MagicMock(return_value=mock_connection)
        oe._service_provider = utils.get_mock_service_provider(
            {constants.CONNECTION_SERVICE_NAME: cs})
        params, session_uri = _connection_details()
        session = ObjectExplorerSession(session_uri, params)
        connection = oe._create_connection(session, 'foo_database')

        self.assertIsNotNone(connection)
        self.assertEqual(connection, mock_connection)
        cs.connect.assert_called_once()
        cs.get_connection.assert_called_once()
    def test_handle_create_session_successful(self):
        # Setup:
        # ... Create OE service with mock connection service that returns a successful connection response
        mock_connection = MockPGServerConnection(cur=None,
                                                 host='myserver',
                                                 name='postgres',
                                                 user='******',
                                                 port=123)
        cs = ConnectionService()
        cs.connect = mock.MagicMock(return_value=ConnectionCompleteParams())
        cs.get_connection = mock.MagicMock(return_value=mock_connection)
        oe = ObjectExplorerService()
        oe._service_provider = utils.get_mock_service_provider(
            {constants.CONNECTION_SERVICE_NAME: cs})
        oe._provider = constants.PG_PROVIDER_NAME
        oe._server = Server

        # ... Create parameters, session, request context validator
        params, session_uri = _connection_details()

        # ... Create validation of success notification
        def validate_success_notification(response: SessionCreatedParameters):
            self.assertTrue(response.success)
            self.assertEqual(response.session_id, session_uri)
            self.assertIsNone(response.error_message)

            self.assertIsInstance(response.root_node, NodeInfo)
            self.assertEqual(response.root_node.label, TEST_DBNAME)
            self.assertEqual(response.root_node.node_path, session_uri)
            self.assertEqual(response.root_node.node_type, 'Database')
            self.assertIsInstance(response.root_node.metadata, ObjectMetadata)
            self.assertEqual(response.root_node.metadata.urn,
                             oe._session_map[session_uri].server.urn_base)
            self.assertEqual(
                response.root_node.metadata.name,
                oe._session_map[session_uri].server.maintenance_db_name)
            self.assertEqual(response.root_node.metadata.metadata_type_name,
                             'Database')
            self.assertFalse(response.root_node.is_leaf)

        rc = RequestFlowValidator()
        rc.add_expected_response(
            CreateSessionResponse,
            lambda param: self.assertEqual(param.session_id, session_uri))
        rc.add_expected_notification(SessionCreatedParameters,
                                     SESSION_CREATED_METHOD,
                                     validate_success_notification)

        # If: I create a session
        oe._handle_create_session_request(rc.request_context, params)
        oe._session_map[session_uri].init_task.join()

        # Then:
        # ... Error notification should have been returned, session should be cleaned up from OE service
        rc.validate()

        # ... The session should still exist and should have connection and server setup
        self.assertIn(session_uri, oe._session_map)
        self.assertIsInstance(oe._session_map[session_uri].server, Server)
        self.assertTrue(oe._session_map[session_uri].is_ready)
    def test_create_connection_failed(self):
        # Setup:
        oe = ObjectExplorerService()
        cs = ConnectionService()
        connect_response = ConnectionCompleteParams()
        error = 'Failed'
        connect_response.error_message = error
        cs.connect = mock.MagicMock(return_value=connect_response)
        oe._service_provider = utils.get_mock_service_provider(
            {constants.CONNECTION_SERVICE_NAME: cs})
        params, session_uri = _connection_details()
        session = ObjectExplorerSession(session_uri, params)

        with self.assertRaises(RuntimeError) as context:
            oe._create_connection(session, 'foo_database')
            self.assertEqual(error, str(context.exception))

        cs.connect.assert_called_once()
    def test_init(self):
        # If: I create a new OE service
        oe = ObjectExplorerService()

        # Then:
        # ... The service should have its internal state initialized
        self.assertIsNone(oe._service_provider)
        self.assertDictEqual(oe._session_map, {})
        self.assertIsNotNone(oe._session_lock)
    def test_handle_create_session_incomplete_params(self):
        # Setup: Create an OE service
        oe = ObjectExplorerService()
        oe._service_provider = utils.get_mock_service_provider({})

        # If: I create an OE session for with missing params
        # NOTE: We only need to get the generate uri method to throw, we make sure it throws in all
        #       scenarios in a different test
        rc = RequestFlowValidator().add_expected_error(
            type(None), RequestFlowValidator.basic_error_validation)
        params = ConnectionDetails.from_data({})
        oe._handle_create_session_request(rc.request_context, params)

        # Then:
        # ... I should get an error response
        rc.validate()

        # ... A session should not have been created
        self.assertDictEqual(oe._session_map, {})
def _connection_details() -> Tuple[ConnectionDetails, str]:
    param = ConnectionDetails()
    param.options = {
        'host': TEST_HOST,
        'dbname': TEST_DBNAME,
        'user': TEST_USER,
        'port': TEST_PORT
    }
    session_uri = ObjectExplorerService._generate_session_uri(
        param, constants.PG_PROVIDER_NAME)
    return param, session_uri
    def setUp(self):
        # Setup: Create an OE service and add a session to it
        self.cs = ConnectionService()
        self.mock_connection = {}
        self.oe = ObjectExplorerService()
        params, session_uri = _connection_details()
        self.session = ObjectExplorerSession(session_uri, params)
        self.oe._session_map[session_uri] = self.session
        name = 'dbname'
        self.mock_server = Server(MockPGServerConnection())
        self.session.server = self.mock_server
        self.db = Database(self.mock_server, name)
        self.db._connection = self.mock_server._conn
        self.session.server._child_objects[Database.__name__] = [self.db]
        self.cs.get_connection = mock.MagicMock(
            return_value=self.mock_connection)

        self.cs.disconnect = mock.MagicMock(return_value=True)
        self.oe._service_provider = utils.get_mock_service_provider(
            {constants.CONNECTION_SERVICE_NAME: self.cs})
    def test_register(self):
        # Setup:
        # ... Create a mock service provider
        server: JSONRPCServer = JSONRPCServer(None, None)
        server.set_notification_handler = mock.MagicMock()
        server.set_request_handler = mock.MagicMock()
        sp: ServiceProvider = ServiceProvider(server, {},
                                              constants.PG_PROVIDER_NAME,
                                              utils.get_mock_logger())

        # If: I register a OE service
        oe = ObjectExplorerService()
        oe.register(sp)

        # Then:
        # ... The service should have registered its request handlers
        server.set_request_handler.assert_called()
        server.set_notification_handler.assert_not_called()

        # ... The service provider should have been stored
        self.assertIs(oe._service_provider, sp)
    def test_handle_create_session_threading_fail(self):
        # Setup:
        # ... Create an OE service
        oe = ObjectExplorerService()
        oe._service_provider = utils.get_mock_service_provider({})
        oe._provider = constants.PG_PROVIDER_NAME

        # ... Patch the threading to throw
        patch_mock = mock.MagicMock(side_effect=Exception('Boom!'))
        patch_path = 'ossdbtoolsservice.object_explorer.object_explorer_service.threading.Thread'
        with mock.patch(patch_path, patch_mock):
            # If: I create a new session
            params, session_uri = _connection_details()

            rc = RequestFlowValidator()
            rc.add_expected_response(
                CreateSessionResponse,
                lambda param: self.assertEqual(param.session_id, session_uri))
            rc.add_expected_notification(
                SessionCreatedParameters, SESSION_CREATED_METHOD,
                lambda param: self._validate_init_error(param, session_uri))
            oe._handle_create_session_request(rc.request_context, params)

        # Then:
        # ... The error notification should have been returned
        rc.validate()

        # ... The session should have been cleaned up
        self.assertDictEqual(oe._session_map, {})
    def test_init_session_failed_connection(self):
        # Setup:
        # ... Create OE service with mock connection service that returns a failed connection response
        cs = ConnectionService()
        connect_response = ConnectionCompleteParams()
        connect_response.error_message = 'Boom!'
        cs.connect = mock.MagicMock(return_value=connect_response)
        oe = ObjectExplorerService()
        oe._service_provider = utils.get_mock_service_provider(
            {constants.CONNECTION_SERVICE_NAME: cs})

        # If: I initialize a session (NOTE: We're bypassing request handler to avoid threading issues)
        params, session_uri = _connection_details()
        session = ObjectExplorerSession(session_uri, params)
        oe._session_map[session_uri] = session

        rc = RequestFlowValidator()
        rc.add_expected_notification(
            SessionCreatedParameters, SESSION_CREATED_METHOD,
            lambda param: self._validate_init_error(param, session_uri))
        oe._initialize_session(rc.request_context, session)

        # Then:
        # ... Error notification should have been returned, session should be cleaned up from OE service
        rc.validate()
        self.assertDictEqual(oe._session_map, {})
    def test_generate_uri_valid_params(self):
        # If: I generate a session URI from a valid connection details object
        params, session_uri = _connection_details()
        output = ObjectExplorerService._generate_session_uri(
            params, constants.PG_PROVIDER_NAME)

        # Then: The output should be a properly formed URI
        parse_result = url_parse.urlparse(output)
        self.assertEqual(parse_result.scheme, 'objectexplorer')
        self.assertTrue(parse_result.netloc)

        re_match = re.match(
            r'(?P<username>\w+)@(?P<host>\w+):(?P<port>\w+):(?P<db_name>\w+)',
            parse_result.netloc)
        self.assertIsNotNone(re_match)
        self.assertEqual(re_match.group('username'), TEST_USER)
        self.assertEqual(re_match.group('host'), TEST_HOST)
        self.assertEqual(int(re_match.group('port')), TEST_PORT)
        self.assertEqual(re_match.group('db_name'), TEST_DBNAME)
    def test_handle_create_session_session_exists(self):
        # Setup: Create an OE service and pre-load a session
        oe = ObjectExplorerService()
        oe._service_provider = utils.get_mock_service_provider({})
        params, session_uri = _connection_details()
        session = ObjectExplorerSession(session_uri, params)
        oe._session_map[session_uri] = session
        oe._provider = constants.PG_PROVIDER_NAME

        # If: I attempt to create an OE session that already exists
        rc = RequestFlowValidator().add_expected_response(
            bool, self.assertFalse)
        oe._handle_create_session_request(rc.request_context, params)

        # Then:
        # ... I should get a response as False
        rc.validate()

        # ... The old session should remain
        self.assertIs(oe._session_map[session_uri], session)
class SessionTestCase(unittest.TestCase):
    TEST_HOST = 'testhost'
    TEST_DBNAME = 'testdb'
    TEST_USER = '******'
    TEST_PASSWORD = '******'

    def setUp(self):
        # Setup: Create an OE service and add a session to it
        self.cs = ConnectionService()
        self.mock_connection = {}
        self.oe = ObjectExplorerService()
        params, session_uri = _connection_details()
        self.session = ObjectExplorerSession(session_uri, params)
        self.oe._session_map[session_uri] = self.session
        name = 'dbname'
        self.mock_server = Server(MockPGServerConnection())
        self.session.server = self.mock_server
        self.db = Database(self.mock_server, name)
        self.db._connection = self.mock_server._conn
        self.session.server._child_objects[Database.__name__] = [self.db]
        self.cs.get_connection = mock.MagicMock(
            return_value=self.mock_connection)

        self.cs.disconnect = mock.MagicMock(return_value=True)
        self.oe._service_provider = utils.get_mock_service_provider(
            {constants.CONNECTION_SERVICE_NAME: self.cs})

    # CLOSE SESSION ########################################################

    def test_handle_close_session_missing_params(self):
        # If: I close an OE session with missing params
        rc = RequestFlowValidator().add_expected_error(
            type(None), RequestFlowValidator.basic_error_validation)
        self.oe._handle_close_session_request(rc.request_context, None)

        # Then: I should get an error response
        rc.validate()

    def test_handle_close_session_incomplete_params(self):
        # If: I close an OE session for with missing params
        # NOTE: We only need to get the generate uri method to throw, we make sure it throws in all
        #       scenarios in a different test
        rc = RequestFlowValidator().add_expected_error(
            type(None), RequestFlowValidator.basic_error_validation)
        params = ConnectionDetails.from_data({})
        self.oe._handle_close_session_request(rc.request_context, params)

        # Then:
        # ... I should get an error response
        rc.validate()

    def test_handle_close_session_nosession(self):
        # Setup: Create an empty session dictionary
        self.oe._session_map = {}

        # If: I close an OE session that doesn't exist
        rc = RequestFlowValidator().add_expected_response(
            bool, self.assertFalse)
        session_id = _connection_details()[1]
        params = _close_session_params()
        params.session_id = session_id
        self.oe._handle_close_session_request(rc.request_context, params)

        # Then: I should get a successful response
        rc.validate()

    def test_handle_close_session_unsuccessful(self):
        self.cs.disconnect = mock.MagicMock(return_value=False)

        # If: I close an OE session that doesn't exist
        rc = RequestFlowValidator().add_expected_response(
            bool, self.assertFalse)
        session_id = _connection_details()[1]
        params = _close_session_params()
        params.session_id = session_id
        self.oe._handle_close_session_request(rc.request_context, params)

        # Then: I should get a successful response
        rc.validate()
        self.oe._service_provider.logger.info.assert_called_with(
            'Could not close the OE session with Id objectexplorer://testuser@testhost:5432:testdb/'
        )

    def test_handle_close_session_throwsException(self):
        # setup to throw exception on disconnect
        self.cs.disconnect = mock.MagicMock(side_effect=Exception)

        # If: I close an OE session that doesn't exist
        rc = RequestFlowValidator().add_expected_error(type(None))
        session_id = _connection_details()[1]
        params = _close_session_params()
        params.session_id = session_id
        self.oe._handle_close_session_request(rc.request_context, params)

        # Then: I should get a successful response
        rc.validate()
        self.oe._service_provider.logger.error.assert_called_once()

    def test_handle_close_session_successful(self):

        # If: I close a session
        rc = RequestFlowValidator().add_expected_response(
            bool, self.assertTrue)
        session_id = _connection_details()[1]
        params = _close_session_params()
        params.session_id = session_id
        self.oe._handle_close_session_request(rc.request_context, params)

        # Then:
        # ... I should get a successful response
        rc.validate()

        # ... The session should no longer be in the
        self.assertDictEqual(self.oe._session_map, {})

    # SHUTDOWN NODE #########################################################

    def test_handle_shutdown_successfulWithSessions(self):
        # shutdown the session
        self.oe._handle_shutdown()
        self.oe._service_provider.logger.info.assert_called_with(
            'Closed the OE session with Id: objectexplorer://testuser@testhost:5432:testdb/'
        )

    def test_handle_shutdown_successfulNoDatabase(self):
        # Setup: Create an OE service and add a session to it
        self.session.server._child_objects[Database.__name__] = []

        # shutdown the session
        self.oe._handle_shutdown()
        self.oe._service_provider.logger.info.assert_called_with(
            'Closed the OE session with Id: objectexplorer://testuser@testhost:5432:testdb/'
        )

    def test_handle_shutdown_UnsuccessfulWithSessions(self):
        # Setup: Create an OE service and add a session to it
        self.cs.disconnect = mock.MagicMock(return_value=False)

        # shutdown the session
        self.oe._handle_shutdown()
        self.oe._service_provider.logger.info.assert_called_with(
            'Could not close the OE session with Id: objectexplorer://testuser@testhost:5432:testdb/'
        )

    def test_handle_shutdown_successfulNoSessions(self):
        # Setup: Create an empty session dictionary
        self.oe._session_map = {}

        # shutdown the session
        self.oe._handle_shutdown()
        self.oe._service_provider.logger.info.assert_called_with(
            'Closing all the OE sessions')
示例#19
0
class TestObjectExplorerRouting(unittest.TestCase):
    def setUp(self):
        service_provider = ServiceProvider(None, {}, PG_PROVIDER_NAME)
        self.object_explorer_service = ObjectExplorerService()
        self.object_explorer_service.service_provider = service_provider
        self.object_explorer_service._routing_table = PG_ROUTING_TABLE

    # FOLDER TESTING #######################################################
    def test_folder_init(self):
        # If: I create a folder
        label = 'FolderName'
        path = 'folder_path'
        folder = session.Folder(label, path)

        # Then: The internal state of the folder should be set up properly
        self.assertEqual(folder.path, path + '/')
        self.assertEqual(folder.label, label)

    def test_folder_as_node(self):
        # If: I have a folder and ask for it to be turned into a node
        label = 'FolderName'
        path = 'folder_path'
        current_path = '/'
        node = session.Folder(label, path).as_node(current_path)

        # Then: The node state should be setup properly
        self.assertIsInstance(node, NodeInfo)
        self.assertFalse(node.is_leaf)
        self.assertEqual(node.label, label)
        self.assertIsNotNone(urlparse(node.node_path))
        self.assertTrue(node.node_path.endswith('/'))
        self.assertEqual(node.node_type, 'Folder')

    # ROUTING TARGET TESTS #################################################
    def test_routing_target_init_no_folders(self):
        # If: I create a routing target without any folders defined
        node_generator = mock.MagicMock()
        rt = session.RoutingTarget(None, node_generator)

        # Then: The internal state should show an empty array of folders
        self.assertListEqual(rt.folders, [])
        self.assertIs(rt.node_generator, node_generator)

    def test_routing_target_init_with_folders(self):
        # If: I create a routing target with folders defined
        node_generator = mock.MagicMock()
        folder_list = [session.Folder('FolderName', 'folder_path')]
        rt = session.RoutingTarget(folder_list, node_generator)

        # Then: The internal state should reflect a list of folders being provided
        self.assertIs(rt.folders, folder_list)
        self.assertIs(rt.node_generator, node_generator)

    def test_routing_target_get_nodes_empty(self):
        # If: I ask for nodes for an empty routing target
        rt = session.RoutingTarget(None, None)
        output = rt.get_nodes(
            False, '/', ObjectExplorerSession('session_id',
                                              ConnectionDetails()), {})

        # Then: The results should be empty
        self.assertListEqual(output, [])

    def test_routing_target_get_nodes_not_empty(self):
        # Setup: Create mock node generator and folder node list
        node1 = NodeInfo()
        node2 = NodeInfo()
        node_generator = mock.MagicMock(return_value=[node1, node2])
        folder_list = [
            session.Folder('Folder1', 'fp1'),
            session.Folder('Folder2', 'fp2')
        ]

        # If: I ask for nodes for a routing target
        rt = session.RoutingTarget(folder_list, node_generator)
        current_path = '/'
        match_params = {}
        object_explorer_session = ObjectExplorerSession(
            'session_id', ConnectionDetails())
        output = rt.get_nodes(False, current_path, object_explorer_session,
                              match_params)

        # Then:
        # ... I should get back a list of nodes
        self.assertIsInstance(output, list)
        for node in output:
            self.assertIsInstance(node, NodeInfo)
        self.assertEqual(len(output), 4)
        self.assertEqual(output[0].node_type, 'Folder')
        self.assertEqual(output[1].node_type, 'Folder')
        self.assertIs(output[2], node1)
        self.assertIs(output[3], node2)

        # ... The node generator should have been called
        node_generator.assert_called_once_with(False, current_path,
                                               object_explorer_session,
                                               match_params)

    # ROUTING TABLE TESTS ##################################################
    def test_routing_table(self):
        # Make sure that all keys in the routing table are regular expressions
        # Make sure that all items in the routing table are RoutingTargets
        re_class = re.compile('^/$').__class__
        for key, item in PG_ROUTING_TABLE.items():
            self.assertIsInstance(key, re_class)
            self.assertIsInstance(item, session.RoutingTarget)

    def test_routing_invalid_path(self):
        # If: Ask to route a path without a route

        # Then: I should get an exception
        with self.assertRaises(ValueError):
            self.object_explorer_service._route_request(
                False, ObjectExplorerSession('session_id',
                                             ConnectionDetails()),
                '!/invalid!/')

    def test_routing_match(self):
        # If: Ask to route a request that is valid
        output = self.object_explorer_service._route_request(
            False, ObjectExplorerSession('session_id', ConnectionDetails()),
            '/')

        # Then: The output should be a list of nodes
        self.assertIsInstance(output, list)
        for node in output:
            self.assertIsInstance(node, NodeInfo)
示例#20
0
 def setUp(self):
     service_provider = ServiceProvider(None, {}, PG_PROVIDER_NAME)
     self.object_explorer_service = ObjectExplorerService()
     self.object_explorer_service.service_provider = service_provider
     self.object_explorer_service._routing_table = PG_ROUTING_TABLE
 def refresh_method(oe: ObjectExplorerService, rc: RequestContext,
                    p: ExpandParameters):
     oe._handle_refresh_request(rc, p)