示例#1
0
    def test_network_disconnect_primary(self):
        # Application operation fails against primary. Test that topology
        # type changes from ReplicaSetWithPrimary to ReplicaSetNoPrimary.
        # http://bit.ly/1B5ttuL
        primary, secondary = servers = [MockupDB() for _ in range(2)]
        for server in servers:
            server.run()
            self.addCleanup(server.stop)

        hosts = [server.address_string for server in servers]
        primary_response = OpReply(ismaster=True, setName='rs', hosts=hosts,
                                   minWireVersion=2, maxWireVersion=6)
        primary.autoresponds('ismaster', primary_response)
        secondary.autoresponds(
            'ismaster',
            ismaster=False, secondary=True, setName='rs', hosts=hosts,
            minWireVersion=2, maxWireVersion=6)

        client = MongoClient(primary.uri, replicaSet='rs')
        self.addCleanup(client.close)
        wait_until(lambda: client.primary == primary.address,
                   'discover primary')

        topology = client._topology
        self.assertEqual(TOPOLOGY_TYPE.ReplicaSetWithPrimary,
                         topology.description.topology_type)

        # Open a socket in the application pool (calls ismaster).
        with going(client.db.command, 'buildinfo'):
            primary.receives('buildinfo').ok()

        # The primary hangs replying to ismaster.
        ismaster_future = Future()
        primary.autoresponds('ismaster',
                             lambda r: r.ok(ismaster_future.result()))

        # Network error on application operation.
        with self.assertRaises(ConnectionFailure):
            with going(client.db.command, 'buildinfo'):
                primary.receives('buildinfo').hangup()

        # Topology type is updated.
        self.assertEqual(TOPOLOGY_TYPE.ReplicaSetNoPrimary,
                         topology.description.topology_type)

        # Let ismasters through again.
        ismaster_future.set_result(primary_response)

        # Demand a primary.
        with going(client.db.command, 'buildinfo'):
            wait_until(lambda: client.primary == primary.address,
                       'rediscover primary')
            primary.receives('buildinfo').ok()

        self.assertEqual(TOPOLOGY_TYPE.ReplicaSetWithPrimary,
                         topology.description.topology_type)
示例#2
0
    def test_client_handshake_saslSupportedMechs(self):
        server = MockupDB()
        server.run()
        self.addCleanup(server.stop)

        primary_response = OpReply('ismaster', True,
                                   minWireVersion=2, maxWireVersion=6)
        client = MongoClient(server.uri,
                             username='******',
                             password='******')

        self.addCleanup(client.close)

        # New monitoring sockets send data during handshake.
        heartbeat = server.receives('ismaster')
        heartbeat.ok(primary_response)

        future = go(client.db.command, 'whatever')
        for request in server:
            if request.matches('ismaster'):
                if request.client_port == heartbeat.client_port:
                    # This is the monitor again, keep going.
                    request.ok(primary_response)
                else:
                    # Handshaking a new application socket should send
                    # saslSupportedMechs and speculativeAuthenticate.
                    self.assertEqual(request['saslSupportedMechs'],
                                     'admin.username')
                    self.assertIn(
                        'saslStart', request['speculativeAuthenticate'])
                    auth = {'conversationId': 1, 'done': False,
                            'payload': b'r=wPleNM8S5p8gMaffMDF7Py4ru9bnmmoqb0'
                                       b'1WNPsil6o=pAvr6B1garhlwc6MKNQ93ZfFky'
                                       b'tXdF9r,s=4dcxugMJq2P4hQaDbGXZR8uR3ei'
                                       b'PHrSmh4uhkg==,i=15000'}
                    request.ok('ismaster', True,
                               saslSupportedMechs=['SCRAM-SHA-256'],
                               speculativeAuthenticate=auth,
                               minWireVersion=2, maxWireVersion=6)
                    # Authentication should immediately fail with:
                    # OperationFailure: Server returned an invalid nonce.
                    with self.assertRaises(OperationFailure):
                        future()
                    return
示例#3
0
    def test_client_handshake_data(self):
        primary, secondary = MockupDB(), MockupDB()
        for server in primary, secondary:
            server.run()
            self.addCleanup(server.stop)

        hosts = [server.address_string for server in primary, secondary]
        primary_response = OpReply('ismaster', True, setName='rs', hosts=hosts)

        secondary_response = OpReply('ismaster',
                                     False,
                                     setName='rs',
                                     hosts=hosts,
                                     secondary=True)

        client = MongoClient(primary.uri,
                             replicaSet='rs',
                             appname='my app',
                             heartbeatFrequencyMS=500)  # Speed up the test.

        self.addCleanup(client.close)

        # New monitoring sockets send data during handshake.
        heartbeat = primary.receives('ismaster')
        _check_handshake_data(heartbeat)
        heartbeat.ok(primary_response)

        heartbeat = secondary.receives('ismaster')
        _check_handshake_data(heartbeat)
        heartbeat.ok(secondary_response)

        # Subsequent heartbeats have no client data.
        primary.receives('ismaster', 1, client=absent).ok(primary_response)
        secondary.receives('ismaster', 1, client=absent).ok(secondary_response)

        # After a disconnect, next ismaster has client data again.
        primary.receives('ismaster', 1, client=absent).hangup()
        heartbeat = primary.receives('ismaster')
        _check_handshake_data(heartbeat)
        heartbeat.ok(primary_response)

        secondary.autoresponds('ismaster', secondary_response)

        # Start a command, so the client opens an application socket.
        future = go(client.db.command, 'whatever')

        for request in primary:
            if request.matches(Command('ismaster')):
                if request.client_port == heartbeat.client_port:
                    # This is the monitor again, keep going.
                    request.ok(primary_response)
                else:
                    # Handshaking a new application socket.
                    _check_handshake_data(heartbeat)
                    request.ok(primary_response)
            else:
                # Command succeeds.
                request.assert_matches(Command('whatever'))
                request.ok()
                assert future()
                return
示例#4
0
    def test_client_handshake_data(self):
        primary, secondary = MockupDB(), MockupDB()
        for server in primary, secondary:
            server.run()
            self.addCleanup(server.stop)

        hosts = [server.address_string for server in (primary, secondary)]
        primary_response = OpReply('ismaster', True,
                                   setName='rs', hosts=hosts,
                                   minWireVersion=2, maxWireVersion=6)
        error_response = OpReply(
            0, errmsg='Cache Reader No keys found for HMAC ...', code=211)

        secondary_response = OpReply('ismaster', False,
                                     setName='rs', hosts=hosts,
                                     secondary=True,
                                     minWireVersion=2, maxWireVersion=6)

        client = MongoClient(primary.uri,
                             replicaSet='rs',
                             appname='my app',
                             heartbeatFrequencyMS=500)  # Speed up the test.

        self.addCleanup(client.close)

        # New monitoring sockets send data during handshake.
        heartbeat = primary.receives('ismaster')
        _check_handshake_data(heartbeat)
        heartbeat.ok(primary_response)

        heartbeat = secondary.receives('ismaster')
        _check_handshake_data(heartbeat)
        heartbeat.ok(secondary_response)

        # Subsequent heartbeats have no client data.
        primary.receives('ismaster', 1, client=absent).ok(error_response)
        secondary.receives('ismaster', 1, client=absent).ok(error_response)
        # The heartbeat retry has no client data after a command failure.
        primary.receives('ismaster', 1, client=absent).ok(error_response)
        secondary.receives('ismaster', 1, client=absent).ok(error_response)
        # Still no client data.
        primary.receives('ismaster', 1, client=absent).ok(primary_response)
        secondary.receives('ismaster', 1, client=absent).ok(secondary_response)

        # After a disconnect, next ismaster has client data again.
        primary.receives('ismaster', 1, client=absent).hangup()
        heartbeat = primary.receives('ismaster')
        _check_handshake_data(heartbeat)
        heartbeat.ok(primary_response)

        secondary.autoresponds('ismaster', secondary_response)

        # Start a command, so the client opens an application socket.
        future = go(client.db.command, 'whatever')

        for request in primary:
            if request.matches(Command('ismaster')):
                if request.client_port == heartbeat.client_port:
                    # This is the monitor again, keep going.
                    request.ok(primary_response)
                else:
                    # Handshaking a new application socket.
                    _check_handshake_data(request)
                    request.ok(primary_response)
            else:
                # Command succeeds.
                if version_tuple >= (3, 7):
                    request.assert_matches(OpMsg('whatever'))
                else:
                    request.assert_matches(Command('whatever'))
                request.ok()
                assert future()
                return