Пример #1
0
    def test_query_member(self):
        with patch('patroni.ctl.get_cursor',
                   Mock(return_value=MockConnect().cursor())):
            rows = query_member(None, None, None, 'master',
                                'SELECT pg_is_in_recovery()', {})
            self.assertTrue('False' in str(rows))

            rows = query_member(None, None, None, 'replica',
                                'SELECT pg_is_in_recovery()', {})
            self.assertEquals(rows, (None, None))

            with patch('test_postgresql.MockCursor.execute',
                       Mock(side_effect=OperationalError('bla'))):
                rows = query_member(None, None, None, 'replica',
                                    'SELECT pg_is_in_recovery()', {})

        with patch('patroni.ctl.get_cursor', Mock(return_value=None)):
            rows = query_member(None, None, None, None,
                                'SELECT pg_is_in_recovery()', {})
            self.assertTrue('No connection to' in str(rows))

            rows = query_member(None, None, None, 'replica',
                                'SELECT pg_is_in_recovery()', {})
            self.assertTrue('No connection to' in str(rows))

        with patch('patroni.ctl.get_cursor',
                   Mock(side_effect=OperationalError('bla'))):
            rows = query_member(None, None, None, 'replica',
                                'SELECT pg_is_in_recovery()', {})
Пример #2
0
class TestCtl(unittest.TestCase):
    @patch('socket.getaddrinfo', socket_getaddrinfo)
    @patch.object(Client, 'machines')
    def setUp(self, mock_machines):
        mock_machines.__get__ = Mock(return_value=['http://*****:*****@patch('psycopg2.connect', psycopg2_connect)
    def test_get_cursor(self):
        c = get_cursor(get_cluster_initialized_without_leader(), role='master')
        assert c is None

        c = get_cursor(get_cluster_initialized_with_leader(), role='master')
        assert c is not None

        c = get_cursor(get_cluster_initialized_with_leader(), role='replica')
        # # MockCursor returns pg_is_in_recovery as false
        assert c is None

        c = get_cursor(get_cluster_initialized_with_leader(), role='any')
        assert c is not None

    def test_output_members(self):
        cluster = get_cluster_initialized_with_leader()
        output_members(cluster, name='abc', format='pretty')
        output_members(cluster, name='abc', format='json')
        output_members(cluster, name='abc', format='tsv')

    @patch('patroni.etcd.Etcd.get_cluster',
           Mock(return_value=get_cluster_initialized_with_leader()))
    @patch('patroni.etcd.Etcd.get_etcd_client', Mock(return_value=None))
    @patch('patroni.etcd.Etcd.set_failover_value', Mock(return_value=None))
    @patch('patroni.ctl.wait_for_leader',
           Mock(return_value=get_cluster_initialized_with_leader()))
    @patch('requests.get', requests_get)
    @patch('requests.post', requests_get)
    @patch('patroni.ctl.post_patroni', Mock(return_value=MockResponse()))
    def test_failover(self):
        runner = CliRunner()

        with patch('patroni.etcd.Etcd.get_cluster',
                   Mock(return_value=get_cluster_initialized_with_leader())):
            result = runner.invoke(ctl,
                                   ['failover', 'dummy', '--dcs', '8.8.8.8'],
                                   input='''leader
other
y''')
            assert 'Failing over to new leader' in result.output

            result = runner.invoke(ctl,
                                   ['failover', 'dummy', '--dcs', '8.8.8.8'],
                                   input='''leader
other
N''')
            assert 'Aborting failover' in str(result.exception)

            result = runner.invoke(ctl,
                                   ['failover', 'dummy', '--dcs', '8.8.8.8'],
                                   input='''leader
leader
y''')
            assert 'target and source are the same' in str(result.exception)

            result = runner.invoke(ctl,
                                   ['failover', 'dummy', '--dcs', '8.8.8.8'],
                                   input='''leader
Reality
y''')
            assert 'Reality does not exist' in str(result.exception)

            result = runner.invoke(ctl, ['failover', 'dummy', '--force'])
            assert 'Failing over to new leader' in result.output

            result = runner.invoke(ctl,
                                   ['failover', 'dummy', '--dcs', '8.8.8.8'],
                                   input='dummy')
            assert 'is not the leader of cluster' in str(result.exception)

        with patch(
                'patroni.etcd.Etcd.get_cluster',
                Mock(return_value=get_cluster_initialized_with_only_leader())):
            result = runner.invoke(ctl,
                                   ['failover', 'dummy', '--dcs', '8.8.8.8'],
                                   input='''leader
other
y''')
            assert 'No candidates found to failover to' in str(
                result.exception)

        with patch(
                'patroni.etcd.Etcd.get_cluster',
                Mock(return_value=get_cluster_initialized_without_leader())):
            result = runner.invoke(ctl,
                                   ['failover', 'dummy', '--dcs', '8.8.8.8'],
                                   input='''leader
other
y''')
            assert 'This cluster has no master' in str(result.exception)

        with patch('patroni.ctl.post_patroni', Mock(side_effect=Exception())):
            result = runner.invoke(ctl,
                                   ['failover', 'dummy', '--dcs', '8.8.8.8'],
                                   input='''leader
other
y''')
            assert 'falling back to DCS' in result.output
            assert 'Failover failed' in result.output

        mocked = Mock()
        mocked.return_value.status_code = 500
        with patch('patroni.ctl.post_patroni', Mock(return_value=mocked)):
            result = runner.invoke(ctl,
                                   ['failover', 'dummy', '--dcs', '8.8.8.8'],
                                   input='''leader
other
y''')
            assert 'Failover failed, details' in result.output

#        with patch('patroni.dcs.AbstractDCS.get_cluster', Mock(return_value=get_cluster_initialized_with_leader())):
#            result = runner.invoke(ctl, ['failover', 'alpha', '--dcs', '8.8.8.8'], input='nonsense')
#            assert 'is not the leader of cluster' in str(result.exception)

# result = runner.invoke(ctl, ['failover', 'alpha', '--dcs', '8.8.8.8', '--master', 'nonsense'])
# assert 'is not the leader of cluster' in str(result.exception)

# result = runner.invoke(ctl, ['failover', 'alpha', '--dcs', '8.8.8.8'], input='leader\nother\nn')
# assert 'Aborting failover' in str(result.exception)

# with patch('patroni.ctl.wait_for_leader', Mock(return_value = get_cluster_initialized_with_leader())):
# result = runner.invoke(ctl, ['failover', 'alpha', '--dcs', '8.8.8.8'], input='leader\nother\nY')
# assert 'master did not change after' in result.output

# result = runner.invoke(ctl, ['failover', 'alpha', '--dcs', '8.8.8.8'], input='leader\nother\nY')
# assert 'Failover failed' in result.output

    def test_(self):
        self.assertRaises(patroni.exceptions.PatroniCtlException, get_dcs,
                          {'scheme': 'dummy'}, 'dummy')

    @patch('psycopg2.connect', psycopg2_connect)
    @patch('patroni.ctl.query_member',
           Mock(return_value=([['mock column']], None)))
    def test_query(self):
        runner = CliRunner()

        with patch('patroni.ctl.get_dcs', Mock(return_value=self.e)):
            result = runner.invoke(ctl, [
                'query',
                'alpha',
                '--member',
                'abc',
                '--role',
                'master',
            ])
            assert 'mutually exclusive' in str(result.exception)

            with runner.isolated_filesystem():
                dummy_file = open('dummy', 'w')
                dummy_file.write('SELECT 1')
                dummy_file.close()

                result = runner.invoke(ctl, [
                    'query',
                    'alpha',
                    '--file',
                    'dummy',
                    '--command',
                    'dummy',
                ])
                assert 'mutually exclusive' in str(result.exception)

                result = runner.invoke(ctl,
                                       ['query', 'alpha', '--file', 'dummy'])

                os.remove('dummy')

            result = runner.invoke(ctl,
                                   ['query', 'alpha', '--command', 'SELECT 1'])
            assert 'mock column' in result.output

    @patch('patroni.ctl.get_cursor', Mock(return_value=MockConnect().cursor()))
    def test_query_member(self):
        rows = query_member(None, None, None, 'master',
                            'SELECT pg_is_in_recovery()')
        assert 'False' in str(rows)

        rows = query_member(None, None, None, 'replica',
                            'SELECT pg_is_in_recovery()')
        assert rows == (None, None)

        with patch('patroni.ctl.get_cursor', Mock(return_value=None)):
            rows = query_member(None, None, None, None,
                                'SELECT pg_is_in_recovery()')
            assert 'No connection to' in str(rows)

            rows = query_member(None, None, None, 'replica',
                                'SELECT pg_is_in_recovery()')
            assert 'No connection to' in str(rows)

        with patch('patroni.ctl.get_cursor',
                   Mock(side_effect=psycopg2.OperationalError('bla'))):
            rows = query_member(None, None, None, 'replica',
                                'SELECT pg_is_in_recovery()')

        with patch('test_postgresql.MockCursor.execute',
                   Mock(side_effect=psycopg2.OperationalError('bla'))):
            rows = query_member(None, None, None, 'replica',
                                'SELECT pg_is_in_recovery()')

    @patch('patroni.dcs.AbstractDCS.get_cluster',
           Mock(return_value=get_cluster_initialized_with_leader()))
    def test_dsn(self):
        runner = CliRunner()

        with patch('patroni.ctl.get_dcs', Mock(return_value=self.e)):
            result = runner.invoke(ctl, ['dsn', 'alpha', '--dcs', '8.8.8.8'])
            assert 'host=127.0.0.1 port=5435' in result.output

            result = runner.invoke(ctl, [
                'dsn',
                'alpha',
                '--role',
                'master',
                '--member',
                'dummy',
            ])
            assert 'mutually exclusive' in str(result.exception)

            result = runner.invoke(ctl, ['dsn', 'alpha', '--member', 'dummy'])
            assert 'Can not find' in str(result.exception)

        # result = runner.invoke(ctl, ['dsn', 'alpha', '--dcs', '8.8.8.8', '--role', 'replica'])
        # assert 'host=127.0.0.1 port=5436' in result.output

    @patch('patroni.etcd.Etcd.get_cluster',
           Mock(return_value=get_cluster_initialized_with_leader()))
    @patch('patroni.etcd.Etcd.get_etcd_client', Mock(return_value=None))
    @patch('requests.get', requests_get)
    @patch('requests.post', requests_get)
    def test_restart_reinit(self):
        runner = CliRunner()

        result = runner.invoke(ctl, ['restart', 'alpha', '--dcs', '8.8.8.8'],
                               input='y')
        result = runner.invoke(ctl, ['reinit', 'alpha', '--dcs', '8.8.8.8'],
                               input='y')

        result = runner.invoke(ctl, ['restart', 'alpha', '--dcs', '8.8.8.8'],
                               input='N')
        result = runner.invoke(ctl, [
            'restart',
            'alpha',
            '--dcs',
            '8.8.8.8',
            'dummy',
            '--any',
        ],
                               input='y')
        assert 'not a member' in str(result.exception)

        with patch('requests.post', Mock(return_value=MockResponse())):
            result = runner.invoke(ctl,
                                   ['restart', 'alpha', '--dcs', '8.8.8.8'],
                                   input='y')

    @patch('patroni.etcd.Etcd.get_cluster',
           Mock(return_value=get_cluster_initialized_with_leader()))
    @patch('patroni.etcd.Etcd.get_etcd_client', Mock(return_value=None))
    def test_remove(self):
        runner = CliRunner()

        result = runner.invoke(ctl, ['remove', 'alpha', '--dcs', '8.8.8.8'],
                               input='alpha\nslave')
        assert 'Please confirm' in result.output
        assert 'You are about to remove all' in result.output
        assert 'You did not exactly type' in str(result.exception)

        result = runner.invoke(ctl, ['remove', 'alpha', '--dcs', '8.8.8.8'],
                               input='''alpha
Yes I am aware
slave''')
        assert 'You did not specify the current master of the cluster' in str(
            result.exception)

        result = runner.invoke(ctl, ['remove', 'alpha', '--dcs', '8.8.8.8'],
                               input='beta\nleader')
        assert 'Cluster names specified do not match' in str(result.exception)

        with patch('patroni.etcd.Etcd.get_cluster',
                   get_cluster_initialized_with_leader):
            result = runner.invoke(ctl,
                                   ['remove', 'alpha', '--dcs', '8.8.8.8'],
                                   input='''alpha
Yes I am aware
leader''')
            assert 'object has no attribute' in str(result.exception)

        with patch('patroni.ctl.get_dcs', Mock(return_value=Mock())):
            result = runner.invoke(ctl,
                                   ['remove', 'alpha', '--dcs', '8.8.8.8'],
                                   input='''alpha
Yes I am aware
leader''')
            assert 'We have not implemented this for DCS of type' in str(
                result.exception)

    @patch('patroni.etcd.Etcd.watch', Mock(return_value=None))
    @patch('patroni.etcd.Etcd.get_cluster',
           Mock(return_value=get_cluster_initialized_with_leader()))
    def test_wait_for_leader(self):
        dcs = self.e
        self.assertRaises(patroni.exceptions.PatroniCtlException,
                          wait_for_leader, dcs, 0)

        cluster = wait_for_leader(dcs=dcs, timeout=2)
        assert cluster.leader.member.name == 'leader'

    def test_post_patroni(self):
        member = get_cluster_initialized_with_leader().leader.member
        self.assertRaises(requests.exceptions.ConnectionError, post_patroni,
                          member, 'dummy', {})

    def test_ctl(self):
        runner = CliRunner()

        runner.invoke(ctl, ['list'])

        result = runner.invoke(ctl, ['--help'])
        assert 'Usage:' in result.output

    def test_get_any_member(self):
        m = get_any_member(get_cluster_initialized_without_leader(),
                           role='master')
        assert m is None

        m = get_any_member(get_cluster_initialized_with_leader(),
                           role='master')
        assert m.name == 'leader'

    def test_get_all_members(self):
        r = list(
            get_all_members(get_cluster_initialized_without_leader(),
                            role='master'))
        assert len(r) == 0

        r = list(
            get_all_members(get_cluster_initialized_with_leader(),
                            role='master'))
        assert len(r) == 1
        assert r[0].name == 'leader'

        r = list(
            get_all_members(get_cluster_initialized_with_leader(),
                            role='replica'))
        assert len(r) == 1
        assert r[0].name == 'other'

        r = list(
            get_all_members(get_cluster_initialized_without_leader(),
                            role='replica'))
        assert len(r) == 2

    @patch('patroni.etcd.Etcd.get_cluster',
           Mock(return_value=get_cluster_initialized_with_leader()))
    @patch('patroni.etcd.Etcd.get_etcd_client', Mock(return_value=None))
    @patch('requests.get', requests_get)
    @patch('requests.post', requests_get)
    def test_members(self):
        runner = CliRunner()

        result = runner.invoke(members, ['alpha'])
        assert result.exit_code == 0

    def test_configure(self):
        runner = CliRunner()

        result = runner.invoke(configure, [
            '--dcs',
            'abc',
            '-c',
            'dummy',
            '-n',
            'bla',
        ])

        assert result.exit_code == 0