class TestInstanceStarted(unittest.TestCase): def setUp(self): self.cookie = 'secret' self.console_sock = './tmp/x.sock' self.instance = Instance(self.console_sock, self.cookie) self.instance.start() def template_test_instance_not_started(self, stateboard): # console sock doesn't exists self.instance.remove_file(self.console_sock) res = call_check_instance_started(self.console_sock, stateboard) self.assertFalse(res.success) self.assertIn('Instance socket not found', res.msg) # cannot connect to console sock bad_socket_path = 'bad-socket-path' self.instance.write_file(bad_socket_path) res = call_check_instance_started(bad_socket_path, stateboard) self.assertFalse(res.success) self.assertIn('Failed to connect to socket', res.msg) def test_instance_not_started(self): self.template_test_instance_not_started(stateboard=False) def test_stateboard_not_started(self): self.template_test_instance_not_started(stateboard=True) def test_alive(self): # not stateboard # require('membership').myself().status is 'active' set_myself(self.instance, status='alive') self.instance.clear_calls('membership_myself') res = call_check_instance_started(self.console_sock) self.assertTrue(res.success, msg=res.msg) calls = self.instance.get_calls('membership_myself') self.assertEqual(len(calls), 1) # stateboard set_myself(self.instance, status='alive') self.instance.clear_calls('membership_myself') res = call_check_instance_started(self.console_sock, stateboard=True) self.assertTrue(res.success, msg=res.msg) calls = self.instance.get_calls('membership_myself') self.assertEqual(len(calls), 0) def test_dead(self): # not stateboard # require('membership').myself().status is 'dead' set_myself(self.instance, status='dead') self.instance.clear_calls('membership_myself') res = call_check_instance_started(self.console_sock) self.assertFalse(res.success) def tearDown(self): self.instance.stop()
class TestAppConfig(unittest.TestCase): def setUp(self): self.cookie = 'secret' self.console_sock = './tmp/x.sock' self.instance = Instance(self.console_sock, self.cookie) self.instance.start() def test_empty_config(self): res = call_config_app(self.console_sock, {}) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) def test_edit_system_sections(self): system_sections = [ 'topology', 'vshard', 'vshard_groups', 'auth', 'users_acl', ] for section in system_sections: self.instance.clear_calls('config_patch_clusterwide') res = call_config_app(self.console_sock, {section: {}}) self.assertFalse(res.success) self.assertIn('Unable to patch config system section', res.msg) calls = self.instance.get_calls('config_patch_clusterwide') self.assertEqual(len(calls), 0) def test_adding_new_sections(self): SECTION_NAME = 'new-section' SECTION_BODY = 'SECTION BODY' # config is empty self.instance.set_variable('config', {}) self.instance.clear_calls('config_patch_clusterwide') res = call_config_app(self.console_sock, {SECTION_NAME: { 'body': SECTION_BODY, }}) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('config_patch_clusterwide') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], {SECTION_NAME: SECTION_BODY}) # config is already set (res.changed should be false) self.instance.set_variable('config', {SECTION_NAME: SECTION_BODY}) self.instance.clear_calls('config_patch_clusterwide') res = call_config_app(self.console_sock, {SECTION_NAME: { 'body': SECTION_BODY, }}) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('config_patch_clusterwide') self.assertEqual(len(calls), 0) def test_deleting_sections(self): SECTION1_NAME = 'section-1' SECTION1_BODY = 'SECTION-1 BODY' SECTION2_NAME = 'section-2' SECTION2_BODY = 'SECTION-2 BODY' # set two sections self.instance.set_variable('config', { SECTION1_NAME: SECTION1_BODY, SECTION2_NAME: SECTION2_BODY, }) self.instance.clear_calls('config_patch_clusterwide') # delete section-1 res = call_config_app(self.console_sock, {SECTION1_NAME: { 'deleted': True, }}) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('config_patch_clusterwide') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], {SECTION1_NAME: None}) # set only section-2 self.instance.set_variable('config', { SECTION2_NAME: SECTION2_BODY, }) self.instance.clear_calls('config_patch_clusterwide') # delete section-1 res = call_config_app(self.console_sock, {SECTION1_NAME: { 'deleted': True, }}) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('config_patch_clusterwide') self.assertEqual(len(calls), 0) # set two sections self.instance.set_variable('config', { SECTION1_NAME: SECTION1_BODY, SECTION2_NAME: SECTION2_BODY, }) self.instance.clear_calls('config_patch_clusterwide') # set deleted to False for section-1 res = call_config_app( self.console_sock, {SECTION1_NAME: { 'deleted': False, 'body': SECTION1_BODY, }}) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('config_patch_clusterwide') self.assertEqual(len(calls), 0) def test_changing_section(self): SECTION1_NAME = 'section-1' SECTION1_BODY = 'SECTION-1 BODY' SECTION2_NAME = 'section-2' SECTION2_BODY = 'SECTION-2 BODY' SECTION1_NEW_BODY = {'hi': 'I am section-1 new body'} # set two sections self.instance.set_variable('config', { SECTION1_NAME: SECTION1_BODY, SECTION2_NAME: SECTION2_BODY, }) self.instance.clear_calls('config_patch_clusterwide') # change only section-1 res = call_config_app( self.console_sock, { SECTION1_NAME: { 'body': SECTION1_NEW_BODY, }, SECTION2_NAME: { 'body': SECTION2_BODY, } }) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('config_patch_clusterwide') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], {SECTION1_NAME: SECTION1_NEW_BODY}) def test_patch_config_fails(self): SECTION_NAME = 'new-section' SECTION_BODY = 'SECTION BODY' SECTION_NEW_BODY = 'NEW SECTION BODY' self.instance.set_variable('config', {SECTION_NAME: SECTION_BODY}) self.instance.clear_calls('config_patch_clusterwide') self.instance.set_fail_on('config_patch_clusterwide') # change section res = call_config_app(self.console_sock, { SECTION_NAME: { 'body': SECTION_NEW_BODY, }, }) self.assertFalse(res.success) self.assertIn('Config patch failed', res.msg) self.assertIn('cartridge err', res.msg) def tearDown(self): self.instance.stop()
class TestFailoverDeprecated(unittest.TestCase): def setUp(self): self.cookie = 'secret' self.console_sock = './tmp/x.sock' self.instance = Instance(self.console_sock, self.cookie) self.instance.start() def test_enable_failover_old_cartridge(self): self.instance.set_cartridge_version('1.2.0') # failover disabled self.instance.set_variable('failover', False) self.instance.clear_calls('manage_failover') res = call_manage_failover_deprecated(self.console_sock, True) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('manage_failover') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], 'enable') # failover enabled self.instance.set_variable('failover', True) self.instance.clear_calls('manage_failover') res = call_manage_failover_deprecated(self.console_sock, True) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('manage_failover') self.assertEqual(len(calls), 0) def test_disable_failover_old_cartridge(self): self.instance.set_cartridge_version('1.2.0') # failover enabled self.instance.set_variable('failover', True) self.instance.clear_calls('manage_failover') res = call_manage_failover_deprecated(self.console_sock, False) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('manage_failover') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], 'disable') # failover disabled self.instance.set_variable('failover', False) self.instance.clear_calls('manage_failover') res = call_manage_failover_deprecated(self.console_sock, False) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('manage_failover') self.assertEqual(len(calls), 0) def test_fail_on_manage_failover_old_cartridge(self): self.instance.set_cartridge_version('1.2.0') # enable failover self.instance.set_variable('failover', False) self.instance.clear_calls('manage_failover') self.instance.set_fail_on('manage_failover') res = call_manage_failover_deprecated(self.console_sock, True) self.assertFalse(res.success) self.assertIn('Failed admin_enable_failover', res.msg) self.assertIn('cartridge err', res.msg) # disable failover self.instance.set_variable('failover', True) self.instance.clear_calls('manage_failover') self.instance.set_fail_on('manage_failover') res = call_manage_failover_deprecated(self.console_sock, False) self.assertFalse(res.success) self.assertIn('Failed admin_disable_failover', res.msg) self.assertIn('cartridge err', res.msg) def test_enable_failover(self): self.instance.set_cartridge_version('2.1.0') # failover disabled self.instance.set_variable('failover_params', {'mode': 'disabled'}) self.instance.clear_calls('failover_set_params') res = call_manage_failover_deprecated(self.console_sock, True) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], {'mode': 'eventual'}) # failover enabled self.instance.set_variable('failover_params', {'mode': 'eventual'}) self.instance.clear_calls('failover_set_params') res = call_manage_failover_deprecated(self.console_sock, True) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], {'mode': 'eventual'}) def test_disable_failover(self): self.instance.set_cartridge_version('2.1.0') # failover enabled self.instance.set_variable('failover_params', {'mode': 'eventual'}) self.instance.clear_calls('failover_set_params') res = call_manage_failover_deprecated(self.console_sock, False) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], {'mode': 'disabled'}) # failover disabled self.instance.set_variable('failover_params', {'mode': 'disabled'}) self.instance.clear_calls('failover_set_params') res = call_manage_failover_deprecated(self.console_sock, False) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], {'mode': 'disabled'}) def test_fail_on_manage_failover(self): self.instance.set_cartridge_version('2.1.0') # enable failover self.instance.set_variable('failover_params', {'mode': 'disabled'}) self.instance.clear_calls('failover_set_params') self.instance.set_fail_on('failover_set_params') res = call_manage_failover_deprecated(self.console_sock, True) self.assertFalse(res.success) self.assertIn('Failed to set failover params', res.msg) self.assertIn('cartridge err', res.msg) # disable failover self.instance.set_variable('failover_params', {'mode': 'enabled'}) self.instance.clear_calls('failover_set_params') self.instance.set_fail_on('failover_set_params') res = call_manage_failover_deprecated(self.console_sock, False) self.assertFalse(res.success) self.assertIn('Failed to set failover params', res.msg) self.assertIn('cartridge err', res.msg) def tearDown(self): self.instance.stop()
class TestProbeInstance(unittest.TestCase): def setUp(self): self.cookie = 'secret' self.console_sock = './tmp/x.sock' self.instance = Instance(self.console_sock, self.cookie) self.instance.start() def test_probe_ok(self): set_known_servers(self.instance, [URI1, URI2]) # one instance self.instance.clear_calls('admin_probe_server') res = call_probe_instance( control_sock=self.console_sock, hostvars={'instance-1': { 'config': { 'advertise_uri': URI1 }, }}) self.assertTrue(res.success, msg=res.msg) calls = self.instance.get_calls('admin_probe_server') self.assertEqual(len(calls), 1) self.assertIn(URI1, calls) # two instances self.instance.clear_calls('admin_probe_server') res = call_probe_instance(control_sock=self.console_sock, hostvars={ 'instance-1': { 'config': { 'advertise_uri': URI1 }, }, 'instance-2': { 'config': { 'advertise_uri': URI2 }, } }) self.assertTrue(res.success, msg=res.msg) calls = self.instance.get_calls('admin_probe_server') self.assertEqual(len(calls), 2) self.assertIn(URI1, calls) self.assertIn(URI2, calls) def test_probe_one_fails(self): set_known_servers(self.instance, [URI1]) # probe not known server self.instance.clear_calls('admin_probe_server') res = call_probe_instance( control_sock=self.console_sock, hostvars={'instance-2': { 'config': { 'advertise_uri': URI2 }, }}) self.assertFalse(res.success) calls = self.instance.get_calls('admin_probe_server') self.assertEqual(len(calls), 1) self.assertIn(URI2, calls) # probe both known and not known server self.instance.clear_calls('admin_probe_server') res = call_probe_instance(control_sock=self.console_sock, hostvars={ 'instance-1': { 'config': { 'advertise_uri': URI1 }, }, 'instance-2': { 'config': { 'advertise_uri': URI2 }, } }) self.assertFalse(res.success) calls = self.instance.get_calls('admin_probe_server') self.assertIn(len(calls), [1, 2]) if len(calls) == 1: self.assertIn(URI2, calls) else: self.assertIn(URI1, calls) self.assertIn(URI2, calls) def test_probe_expelled(self): # expelled server shouldn't be probed set_known_servers(self.instance, [URI1]) # probe only expelled self.instance.clear_calls('admin_probe_server') res = call_probe_instance(control_sock=self.console_sock, hostvars={ 'instance-2': { 'expelled': True, 'config': { 'advertise_uri': URI2 }, } }) self.assertTrue(res.success, msg=res.msg) calls = self.instance.get_calls('admin_probe_server') self.assertEqual(len(calls), 0) # probe both expelled and not self.instance.clear_calls('admin_probe_server') res = call_probe_instance(control_sock=self.console_sock, hostvars={ 'instance-1': { 'config': { 'advertise_uri': URI1 }, }, 'instance-2': { 'expelled': True, 'config': { 'advertise_uri': URI2 }, } }) self.assertTrue(res.success, msg=res.msg) calls = self.instance.get_calls('admin_probe_server') self.assertEqual(len(calls), 1) self.assertIn(URI1, calls) def test_probe_restarted(self): # restarted server should be probed set_known_servers(self.instance, []) self.instance.clear_calls('admin_probe_server') res = call_probe_instance(control_sock=self.console_sock, hostvars={ 'instance-2': { 'restarted': True, 'config': { 'advertise_uri': URI2 }, } }) self.assertFalse(res.success) calls = self.instance.get_calls('admin_probe_server') self.assertEqual(len(calls), 1) self.assertIn(URI2, calls) def test_failed_for_non_play_host(self): set_known_servers(self.instance, [URI1]) # probe can fail for instance not mentioned in play_hosts # but it should be probed self.instance.clear_calls('admin_probe_server') res = call_probe_instance(control_sock=self.console_sock, hostvars={ 'instance-1': { 'config': { 'advertise_uri': URI1 }, }, 'instance-2': { 'config': { 'advertise_uri': URI2 }, } }, play_hosts=['instance-1']) self.assertTrue(res.success, msg=res.msg) calls = self.instance.get_calls('admin_probe_server') self.assertEqual(len(calls), 2) self.assertIn(URI1, calls) self.assertIn(URI2, calls) def tearDown(self): self.instance.stop()
class TestManageInstance(unittest.TestCase): def setUp(self): self.cookie = 'secret' self.console_sock = './tmp/x.sock' self.instance = Instance(self.console_sock, self.cookie) self.instance.start() def test_create_replicaset(self): # create replicaset with instances not known by cluster self.instance.clear_calls('edit_topology') res = call_manage_replicaset(self.console_sock, alias='r1', failover_priority=['r1-master'], instances=['r1-master', 'r1-replica'], roles=['role-1']) self.assertFalse(res.success, msg=res.msg) self.assertIn( 'Leader "r1-master" (replicaset "r1") not found in cluster', res.msg) self.assertEqual(len(self.instance.get_calls('edit_topology')), 0) # add unjoined self.instance.add_unjoined_server(alias='r1-master', uri='r1-master-uri') self.instance.add_unjoined_server(alias='r1-replica', uri='r1-replica-uri') # create replicaset with instances known by cluster self.instance.clear_calls('edit_topology') res = call_manage_replicaset(self.console_sock, alias='r1', failover_priority=['r1-master'], instances=['r1-master', 'r1-replica'], roles=['role-1']) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) # check performed `edit_topology` calls calls = self.instance.get_calls('edit_topology') self.assertEqual(len(calls), 2) join_leader_call = calls[0] join_replica_call = calls[1] # check join leader call self.assertIn('replicasets', join_leader_call) self.assertEqual(len(join_leader_call['replicasets']), 1) r_params = join_leader_call['replicasets'][0] self.assertEqual( r_params, { 'alias': 'r1', 'roles': ['role-1'], 'join_servers': [{ 'uri': 'r1-master-uri' }], }) # check join replica call self.assertIn('replicasets', join_replica_call) self.assertEqual(len(join_replica_call['replicasets']), 1) r_params = join_replica_call['replicasets'][0] self.assertEqual(r_params, { 'uuid': 'r1-uuid', 'join_servers': [{ 'uri': 'r1-replica-uri' }], }) # repeat the call (res.changed should be false) self.instance.clear_calls('edit_topology') res = call_manage_replicaset(self.console_sock, alias='r1', failover_priority=['r1-master'], instances=['r1-master', 'r1-replica'], roles=['role-1']) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) # check performed `edit_topology` calls calls = self.instance.get_calls('edit_topology') self.assertEqual(len(calls), 1) self.assertIn('replicasets', calls[0]) r_params = calls[0]['replicasets'][0] self.assertEqual( r_params, { 'uuid': 'r1-uuid', 'roles': ['role-1'], 'failover_priority': ['r1-master-uuid'], }) def test_edit_replicaset_parameters(self): add_replicaset( self.instance, alias='r1', roles=['role-1'], servers=['r1-master'], ) params = { 'all_rw': True, 'weight': 1, 'vshard_group': 'hot', 'roles': ['role-2'], } for param, value in params.items(): self.instance.clear_calls('edit_topology') res = call_manage_replicaset( self.console_sock, alias='r1', failover_priority=['r1-master'], instances=['r1-master'], **{param: value}, ) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) # check performed `edit_topology` calls calls = self.instance.get_calls('edit_topology') self.assertEqual(len(calls), 1) self.assertIn('replicasets', calls[0]) r_params = calls[0]['replicasets'][0] self.assertEqual( r_params, { 'uuid': 'r1-uuid', 'failover_priority': ['r1-master-uuid'], **{ param: value }, }) # set the same parameter again (res.changed should be false) self.instance.clear_calls('edit_topology') res = call_manage_replicaset( self.console_sock, alias='r1', failover_priority=['r1-master'], instances=['r1-master'], **{param: value}, ) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) # check performed `edit_topology` calls calls = self.instance.get_calls('edit_topology') self.assertEqual(len(calls), 1) self.assertIn('replicasets', calls[0]) r_params = calls[0]['replicasets'][0] self.assertEqual( r_params, { 'uuid': 'r1-uuid', 'failover_priority': ['r1-master-uuid'], **{ param: value }, }) def test_joining_new_servers(self): add_replicaset( self.instance, alias='r1', roles=['role-1'], servers=['r1-master', 'r1-replica'], ) # add unjoined self.instance.add_unjoined_server(alias='r1-new-master', uri='r1-new-master-uri') # join new server and set it to be a new master self.instance.clear_calls('edit_topology') res = call_manage_replicaset( self.console_sock, alias='r1', failover_priority=['r1-new-master', 'r1-master'], instances=['r1-master', 'r1-replica', 'r1-new-master'], ) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) # check performed `edit_topology` calls calls = self.instance.get_calls('edit_topology') self.assertEqual(len(calls), 2) join_call = calls[0] edit_priority_call = calls[1] self.assertIn('replicasets', join_call) r_params = join_call['replicasets'][0] self.assertEqual(r_params, { 'uuid': 'r1-uuid', 'join_servers': [{ 'uri': 'r1-new-master-uri' }], }) self.assertIn('replicasets', edit_priority_call) r_params = edit_priority_call['replicasets'][0] self.assertEqual( r_params, { 'uuid': 'r1-uuid', 'failover_priority': ['r1-new-master-uuid', 'r1-master-uuid'], }) # call again (res.changed should be false) res = call_manage_replicaset( self.console_sock, alias='r1', failover_priority=['r1-new-master', 'r1-master'], instances=['r1-master', 'r1-replica', 'r1-new-master'], ) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) def test_fail_on_edit_topology(self): # fail on create self.instance.add_unjoined_server(alias='r1-master', uri='r1-master-uri') self.instance.clear_calls('edit_topology') self.instance.set_fail_on('edit_topology') # create replicaset with instances known by cluster self.instance.clear_calls('edit_topology') res = call_manage_replicaset(self.console_sock, alias='r1', failover_priority=['r1-master'], instances=['r1-master'], roles=['role-1']) self.assertFalse(res.success) self.assertIn('Failed to create', res.msg) self.assertIn('cartridge err', res.msg) # fail on edit add_replicaset( self.instance, alias='r1', roles=['role-1'], servers=['r1-master', 'r1-replica'], ) self.instance.clear_calls('edit_topology') self.instance.set_fail_on('edit_topology') res = call_manage_replicaset( self.console_sock, alias='r1', failover_priority=['r1-master'], instances=['r1-master'], roles=['role-1', 'role-2'], ) self.assertFalse(res.success) self.assertIn('Failed to edit replicaset', res.msg) self.assertIn('cartridge err', res.msg) self.instance.set_fail_on('edit_topology', False) def test_replicaset_in_unhealthy(self): # try to edit unhealthy replicaset add_replicaset( self.instance, alias='r1', roles=['role-1'], servers=['r1-master'], status='unhealthy', ) res = call_manage_replicaset( self.console_sock, alias='r1', roles=['role-2'], failover_priority=['r1-master'], instances=['r1-master'], ) self.assertFalse(res.success) self.assertIn('Replicaset "r1" is not healthy', res.msg) # replicaset becomes unhealthy after creation self.instance.set_variable('become_unhealthy_after_edit', True) self.instance.add_unjoined_server(alias='r2-master', uri='r2-master-uri') res = call_manage_replicaset( self.console_sock, alias='r2', roles=['role-2'], failover_priority=['r2-master'], instances=['r2-master'], ) self.assertFalse(res.success) self.assertIn('Replicaset "r2" is not healthy', res.msg) # replicaset becomes unhealthy after edit self.instance.set_variable('become_unhealthy_after_edit', True) add_replicaset( self.instance, alias='r3', roles=['role-1'], servers=['r3-master'], status='unhealthy', ) res = call_manage_replicaset( self.console_sock, alias='r3', roles=['role-2'], failover_priority=['r3-master'], instances=['r3-master'], ) self.assertFalse(res.success) self.assertIn('Replicaset "r3" is not healthy', res.msg) def tearDown(self): self.instance.stop()
class TestFailover(unittest.TestCase): def setUp(self): self.cookie = 'secret' self.console_sock = './tmp/x.sock' self.instance = Instance(self.console_sock, self.cookie) self.instance.start() def test_enable_failover(self): # failover disabled self.instance.set_variable('failover', False) self.instance.clear_calls('manage_failover') res = call_manage_failover(self.console_sock, True) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('manage_failover') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], 'enable') # failover enabled self.instance.set_variable('failover', True) self.instance.clear_calls('manage_failover') res = call_manage_failover(self.console_sock, True) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('manage_failover') self.assertEqual(len(calls), 0) def test_disable_failover(self): # failover enabled self.instance.set_variable('failover', True) self.instance.clear_calls('manage_failover') res = call_manage_failover(self.console_sock, False) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('manage_failover') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], 'disable') # failover disabled self.instance.set_variable('failover', False) self.instance.clear_calls('manage_failover') res = call_manage_failover(self.console_sock, False) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('manage_failover') self.assertEqual(len(calls), 0) def test_fail_on_manage_failover(self): # enable failover self.instance.set_variable('failover', False) self.instance.clear_calls('manage_failover') self.instance.set_fail_on('manage_failover') res = call_manage_failover(self.console_sock, True) self.assertFalse(res.success) self.assertIn('Failed admin_enable_failover', res.msg) self.assertIn('cartridge err', res.msg) # disable failover self.instance.set_variable('failover', True) self.instance.clear_calls('manage_failover') self.instance.set_fail_on('manage_failover') res = call_manage_failover(self.console_sock, False) self.assertFalse(res.success) self.assertIn('Failed admin_disable_failover', res.msg) self.assertIn('cartridge err', res.msg) def tearDown(self): self.instance.stop()
class TestManageInstance(unittest.TestCase): def setUp(self): self.cookie = 'secret' self.console_sock = './tmp/x.sock' self.instance = Instance(self.console_sock, self.cookie) self.instance.start() def test_instance_not_started(self): # console sock doesn't exists self.instance.clear_calls('box_cfg') self.instance.remove_file(self.console_sock) res = call_manage_instance( control_sock=self.console_sock ) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) self.assertEqual(len(self.instance.get_calls('box_cfg')), 0) # cennot connect to console sock self.instance.clear_calls('box_cfg') bad_socket_path = 'bad-socket-path' self.instance.write_file(bad_socket_path) res = call_manage_instance( control_sock=bad_socket_path ) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) self.assertEqual(len(self.instance.get_calls('box_cfg')), 0) # memtx_memory is nil self.instance.clear_calls('box_cfg') set_box_cfg(self.instance, memtx_memory=None) res = call_manage_instance( control_sock=self.console_sock ) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) self.assertEqual(len(self.instance.get_calls('box_cfg')), 0) def test_non_dynamic_params(self): param_name = 'advertise_uri' old_value = 'localhost:3301' new_instance_value = 'localhost:3311' new_app_value = 'localhost:3322' # changed only in instance config self.instance.clear_calls('box_cfg') set_box_cfg(self.instance, **{param_name: old_value}) res = call_manage_instance( control_sock=self.console_sock, config={ param_name: new_instance_value, } ) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('box_cfg') self.assertEqual(len(calls), 0) # changed only in app config self.instance.clear_calls('box_cfg') set_box_cfg(self.instance, **{param_name: old_value}) res = call_manage_instance( control_sock=self.console_sock, cartridge_defaults={ param_name: new_app_value, } ) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('box_cfg') self.assertEqual(len(calls), 0) # changed in both app and instance config self.instance.clear_calls('box_cfg') set_box_cfg(self.instance, **{param_name: old_value}) res = call_manage_instance( control_sock=self.console_sock, config={ param_name: new_instance_value, }, cartridge_defaults={ param_name: new_app_value, } ) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('box_cfg') self.assertEqual(len(calls), 0) @parameterized.expand([ ["memtx_memory"], ["vinyl_memory"], ]) def test_memory_decreasing(self, param_name): BIG_MEMORY = 1024 SMALL_MEMORY = 512 self.instance.clear_calls('box_cfg') set_box_cfg(self.instance, **{param_name: BIG_MEMORY}) res = call_manage_instance( control_sock=self.console_sock, config={ param_name: SMALL_MEMORY, } ) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) self.assertEqual(len(self.instance.get_calls('box_cfg')), 0) @parameterized.expand([ ["memtx_memory"], ["vinyl_memory"], ]) def test_memtx_memory_increasing(self, param_name): SMALL_MEMORY = 512 INSTANCE_BIG_MEMORY = 1024 APP_BIG_MEMORY = 2048 # increased only in instance config self.instance.clear_calls('box_cfg') set_box_cfg(self.instance, **{param_name: SMALL_MEMORY}) res = call_manage_instance( control_sock=self.console_sock, config={ param_name: INSTANCE_BIG_MEMORY, } ) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('box_cfg') self.assertEqual(len(calls), 1) self.assertIn({param_name: INSTANCE_BIG_MEMORY}, calls) # increased only in app config self.instance.clear_calls('box_cfg') set_box_cfg(self.instance, **{param_name: SMALL_MEMORY}) res = call_manage_instance( control_sock=self.console_sock, cartridge_defaults={ param_name: APP_BIG_MEMORY, } ) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('box_cfg') self.assertEqual(len(calls), 1) self.assertIn({param_name: APP_BIG_MEMORY}, calls) # increased in both app and instance config self.instance.clear_calls('box_cfg') set_box_cfg(self.instance, **{param_name: SMALL_MEMORY}) res = call_manage_instance( control_sock=self.console_sock, config={ param_name: INSTANCE_BIG_MEMORY, }, cartridge_defaults={ param_name: APP_BIG_MEMORY, } ) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('box_cfg') self.assertEqual(len(calls), 1) self.assertIn({param_name: INSTANCE_BIG_MEMORY}, calls) @parameterized.expand([ ["memtx_memory"], ["vinyl_memory"], ]) def test_memtx_memory_increasing_fails(self, param_name): SMALL_MEMORY = 512 INSTANCE_BIG_MEMORY = 1024 APP_BIG_MEMORY = 2048 self.instance.set_fail_on('increase_memory_size') # increased only in instance config self.instance.clear_calls('box_cfg') set_box_cfg(self.instance, **{param_name: SMALL_MEMORY}) res = call_manage_instance( control_sock=self.console_sock, config={ param_name: INSTANCE_BIG_MEMORY, } ) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('box_cfg') self.assertEqual(len(calls), 1) self.assertIn({param_name: INSTANCE_BIG_MEMORY}, calls) # increased only in app config self.instance.clear_calls('box_cfg') set_box_cfg(self.instance, **{param_name: SMALL_MEMORY}) res = call_manage_instance( control_sock=self.console_sock, cartridge_defaults={ param_name: APP_BIG_MEMORY, } ) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('box_cfg') self.assertEqual(len(calls), 1) self.assertIn({param_name: APP_BIG_MEMORY}, calls) # increased in both app and instance config self.instance.clear_calls('box_cfg') set_box_cfg(self.instance, **{param_name: SMALL_MEMORY}) res = call_manage_instance( control_sock=self.console_sock, config={ param_name: INSTANCE_BIG_MEMORY, }, cartridge_defaults={ param_name: APP_BIG_MEMORY, } ) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('box_cfg') self.assertEqual(len(calls), 1) self.assertIn({param_name: INSTANCE_BIG_MEMORY}, calls) def test_box_cfg_is_function(self): BIG_MEMTX_MEMORY = 1024 self.instance.clear_calls('box_cfg') self.instance.set_box_cfg_function() res = call_manage_instance( control_sock=self.console_sock, config={ 'memtx_memory': BIG_MEMTX_MEMORY, } ) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('box_cfg') self.assertEqual(len(calls), 0) # test non-dynamic param changed @parameterized.expand([ ['string', 'custom_proc_title', 'old-proc-title', 'new-proc-title', 'new-app-proc-title'], ['number', 'checkpoint_interval', 3600, 1800, 900], ['boolean', 'read_only', False, True, True], ]) def test_dynamic_params(self, _, param_name, old_value, new_instance_value, new_app_value): # changed only in instance config self.instance.clear_calls('box_cfg') set_box_cfg(self.instance, **{param_name: old_value}) res = call_manage_instance( control_sock=self.console_sock, config={ param_name: new_instance_value, } ) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('box_cfg') self.assertEqual(len(calls), 1) self.assertIn({param_name: new_instance_value}, calls) # changed only in app config self.instance.clear_calls('box_cfg') set_box_cfg(self.instance, **{param_name: old_value}) res = call_manage_instance( control_sock=self.console_sock, cartridge_defaults={ param_name: new_app_value, } ) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('box_cfg') self.assertEqual(len(calls), 1) self.assertIn({param_name: new_app_value}, calls) # changed in both app and instance config self.instance.clear_calls('box_cfg') set_box_cfg(self.instance, **{param_name: old_value}) res = call_manage_instance( control_sock=self.console_sock, config={ param_name: new_instance_value, }, cartridge_defaults={ param_name: new_app_value, } ) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('box_cfg') self.assertEqual(len(calls), 1) self.assertIn({param_name: new_instance_value}, calls) # specified in instance config, isn't changed self.instance.clear_calls('box_cfg') set_box_cfg(self.instance, **{param_name: old_value}) res = call_manage_instance( control_sock=self.console_sock, config={ param_name: old_value, } ) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('box_cfg') self.assertEqual(len(calls), 1) self.assertIn({param_name: old_value}, calls) # specified in app config, isn't changed self.instance.clear_calls('box_cfg') set_box_cfg(self.instance, **{param_name: old_value}) res = call_manage_instance( control_sock=self.console_sock, cartridge_defaults={ param_name: old_value, } ) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('box_cfg') self.assertEqual(len(calls), 1) self.assertIn({param_name: old_value}, calls) def tearDown(self): self.instance.stop()
class TestAuth(unittest.TestCase): def setUp(self): self.cookie = 'secret' self.console_sock = './tmp/x.sock' self.instance = Instance(self.console_sock, self.cookie) self.instance.start() def test_empty(self): res = call_manage_auth(self.console_sock) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) def test_edit_params(self): current_auth = { 'enabled': False, 'cookie_max_age': 100, 'cookie_renew_age': 10, } new_values = { 'enabled': True, 'cookie_max_age': 200, 'cookie_renew_age': 20, } self.instance.set_variable('auth_params', current_auth) for p in ['enabled', 'cookie_max_age', 'cookie_renew_age']: # call with current value (res.changed is False) auth_patch = {p: current_auth[p]} self.instance.clear_calls('auth_set_params') res = call_manage_auth(self.console_sock, **auth_patch) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('auth_set_params') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], auth_patch) # call with a new value (res.changed is True) auth_patch = {p: new_values[p]} self.instance.clear_calls('auth_set_params') res = call_manage_auth(self.console_sock, **auth_patch) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('auth_set_params') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], auth_patch) # fail on auth_set_params self.instance.set_fail_on('auth_set_params') self.instance.set_variable('auth_params', {}) res = call_manage_auth(self.console_sock, enabled=True) self.assertFalse(res.success) self.assertIn('cartridge err', res.msg) def test_user_functions_implemented(self): USER = { 'username': '******', 'password': '******', } # no one operation is implemented self.instance.set_variable('webui_auth_params', {}) res = call_manage_auth(self.console_sock, users=[USER]) self.assertFalse(res.success) self.assertIn('backend must implement all user management functions', res.msg) # check that all operations are required required_operations = [ 'implements_list_users', 'implements_remove_user', 'implements_add_user', 'implements_edit_user', 'implements_get_user', 'implements_check_password', ] for missed_op in required_operations: self.instance.set_variable('webui_auth_params', { op: True for op in required_operations if op != missed_op }) res = call_manage_auth(self.console_sock, users=[USER]) self.assertFalse(res.success) self.assertIn('backend must implement all user management functions', res.msg) def test_add_user(self): # all required operations are implemented set_user_functions_implemented(self.instance) USER1 = { 'username': '******', 'email': '*****@*****.**', 'fullname': 'Elizaveta Dokshina', } USER2 = { 'username': '******', 'email': '*****@*****.**', 'fullname': 'The Princess', } # add a new user self.instance.set_variable('users', [USER1]) self.instance.clear_calls('auth_add_user') self.instance.clear_calls('auth_edit_user') self.instance.clear_calls('auth_remove_user') res = call_manage_auth(self.console_sock, users=[USER1, USER2]) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('auth_add_user') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], USER2) calls = self.instance.get_calls('auth_edit_user') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], USER1) calls = self.instance.get_calls('auth_remove_user') self.assertEqual(len(calls), 0) # add existed user self.instance.set_variable('users', [USER1, USER2]) self.instance.clear_calls('auth_add_user') self.instance.clear_calls('auth_edit_user') self.instance.clear_calls('auth_remove_user') res = call_manage_auth(self.console_sock, users=[USER1, USER2]) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('auth_add_user') self.assertEqual(len(calls), 0) calls = self.instance.get_calls('auth_edit_user') self.assertEqual(len(calls), 2) self.assertIn(USER1, calls) self.assertIn(USER2, calls) calls = self.instance.get_calls('auth_remove_user') self.assertEqual(len(calls), 0) # fail on auth_add_user self.instance.set_fail_on('auth_add_user') self.instance.set_variable('users', []) res = call_manage_auth(self.console_sock, users=[USER1]) self.assertFalse(res.success) self.assertIn('cartridge err', res.msg) def test_edit_user(self): # all required operations are implemented set_user_functions_implemented(self.instance) USER = { 'username': '******', 'email': '*****@*****.**', 'fullname': 'Elizaveta Dokshina', } new_params = { 'password': '******', 'email': '*****@*****.**', 'fullname': 'The Princess', } for param, value in new_params.items(): self.instance.set_variable('users', [USER]) self.instance.clear_calls('auth_add_user') self.instance.clear_calls('auth_edit_user') self.instance.clear_calls('auth_remove_user') user_patch = { 'username': USER['username'], param: value, } res = call_manage_auth(self.console_sock, users=[user_patch]) self.assertTrue(res.success, msg=res.msg) if param != 'password': self.assertTrue(res.changed) else: self.assertFalse(res.changed) calls = self.instance.get_calls('auth_add_user') self.assertEqual(len(calls), 0) calls = self.instance.get_calls('auth_edit_user') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], user_patch) calls = self.instance.get_calls('auth_remove_user') self.assertEqual(len(calls), 0) # fail on auth_edit_user self.instance.set_fail_on('auth_edit_user') self.instance.set_variable('users', [USER]) user_patch = { 'username': USER['username'], 'password': '******', } res = call_manage_auth(self.console_sock, users=[user_patch]) self.assertFalse(res.success) self.assertIn('cartridge err', res.msg) def test_delete_user(self): # all required operations are implemented set_user_functions_implemented(self.instance) USER1 = { 'username': '******', 'email': '*****@*****.**', 'fullname': 'Elizaveta Dokshina', } USER2 = { 'username': '******', 'email': '*****@*****.**', 'fullname': 'The Princess', } # delete existed user self.instance.set_variable('users', [USER1, USER2]) self.instance.clear_calls('auth_add_user') self.instance.clear_calls('auth_edit_user') self.instance.clear_calls('auth_remove_user') deleted_user2 = USER2.copy() deleted_user2['deleted'] = True res = call_manage_auth(self.console_sock, users=[USER1, deleted_user2]) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('auth_add_user') self.assertEqual(len(calls), 0) calls = self.instance.get_calls('auth_edit_user') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], USER1) calls = self.instance.get_calls('auth_remove_user') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], USER2['username']) # delete non-existed user self.instance.set_variable('users', [USER1]) self.instance.clear_calls('auth_add_user') self.instance.clear_calls('auth_edit_user') self.instance.clear_calls('auth_remove_user') deleted_user2 = USER2.copy() deleted_user2['deleted'] = True res = call_manage_auth(self.console_sock, users=[USER1, deleted_user2]) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('auth_add_user') self.assertEqual(len(calls), 0) calls = self.instance.get_calls('auth_edit_user') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], USER1) calls = self.instance.get_calls('auth_remove_user') self.assertEqual(len(calls), 0) # fail on auth_remove_user self.instance.set_fail_on('auth_remove_user') self.instance.set_variable('users', [USER1]) deleted_user1 = USER1.copy() deleted_user1['deleted'] = True res = call_manage_auth(self.console_sock, users=[deleted_user1]) self.assertFalse(res.success) self.assertIn('cartridge err', res.msg) def test_empty_users(self): # all required operations are implemented set_user_functions_implemented(self.instance) USER = { 'username': '******', 'email': '*****@*****.**', 'fullname': 'Elizaveta Dokshina', } # delete existed user self.instance.set_variable('users', [USER]) self.instance.clear_calls('auth_add_user') self.instance.clear_calls('auth_edit_user') self.instance.clear_calls('auth_remove_user') res = call_manage_auth(self.console_sock, users=[]) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('auth_add_user') self.assertEqual(len(calls), 0) calls = self.instance.get_calls('auth_edit_user') self.assertEqual(len(calls), 0) calls = self.instance.get_calls('auth_remove_user') self.assertEqual(len(calls), 0) def tearDown(self): self.instance.stop()
class TestExpelInstance(unittest.TestCase): def setUp(self): self.cookie = 'secret' self.console_sock = './tmp/x.sock' self.instance = Instance(self.console_sock, self.cookie) self.instance.start() def test_non_existent_instance(self): self.instance.clear_calls('edit_topology') res = call_expel_intstance(self.console_sock, 'non-existent-instance') self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('edit_topology') self.assertEqual(len(calls), 0) def test_unjoined_instance(self): ALIAS = 'instance' self.instance.add_unjoined_server(alias=ALIAS, uri='{}-uri'.format(ALIAS)) self.instance.clear_calls('edit_topology') res = call_expel_intstance(self.console_sock, ALIAS) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('edit_topology') self.assertEqual(len(calls), 0) def test_instance_from_replicaset(self): add_replicaset( self.instance, alias='r1', roles=['role-1'], servers=['r1-master', 'r1-replica'], ) self.instance.clear_calls('edit_topology') res = call_expel_intstance(self.console_sock, 'r1-master') self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) # check `edit_topology` call calls = self.instance.get_calls('edit_topology') self.assertEqual(len(calls), 1) self.assertIn('servers', calls[0]) self.assertEqual(len(calls[0]['servers']), 1) s_params = calls[0]['servers'][0] self.assertEqual(s_params, { 'uuid': 'r1-master-uuid', 'expelled': True, }) # call again (res.changed should be false) # in fact, bacause server is expelled from topology self.instance.clear_calls('edit_topology') res = call_expel_intstance(self.console_sock, 'r1-master') self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('edit_topology') self.assertEqual(len(calls), 0) def test_fail_on_edit_topology(self): add_replicaset( self.instance, alias='r1', roles=['role-1'], servers=['r1-master', 'r1-replica'], ) self.instance.clear_calls('edit_topology') self.instance.set_fail_on('edit_topology') res = call_expel_intstance(self.console_sock, 'r1-master') self.assertFalse(res.success) self.assertIn('Failed to expel instance', res.msg) def tearDown(self): self.instance.stop()
class TestFailover(unittest.TestCase): def setUp(self): self.cookie = 'secret' self.console_sock = './tmp/x.sock' self.instance = Instance(self.console_sock, self.cookie) self.instance.start() def test_enable_failover_old_cartridge(self): self.instance.set_cartridge_version('1.2.0') # failover disabled -> enable eventual self.instance.set_variable('failover', False) self.instance.clear_calls('manage_failover') res = call_manage_failover(self.console_sock, mode='eventual') self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('manage_failover') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], 'enable') # failover enabled -> enable eventual self.instance.set_variable('failover', True) self.instance.clear_calls('manage_failover') res = call_manage_failover(self.console_sock, mode='eventual') self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('manage_failover') self.assertEqual(len(calls), 0) # failover disabled -> enable stateful self.instance.set_variable('failover', False) self.instance.clear_calls('manage_failover') res = call_manage_failover(self.console_sock, mode='stateful') self.assertFalse(res.success) self.assertIn('Stateful failover is supported since cartridge 2', res.msg) def test_disable_failover_old_cartridge(self): self.instance.set_cartridge_version('1.2.0') # failover enabled -> disable self.instance.set_variable('failover', True) self.instance.clear_calls('manage_failover') res = call_manage_failover(self.console_sock, mode='disabled') self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('manage_failover') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], 'disable') # failover disabled -> disable self.instance.set_variable('failover', False) self.instance.clear_calls('manage_failover') res = call_manage_failover(self.console_sock, mode='disabled') self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('manage_failover') self.assertEqual(len(calls), 0) def test_fail_on_manage_failover_old_cartridge(self): self.instance.set_cartridge_version('1.2.0') # enable eventual failover self.instance.set_variable('failover', False) self.instance.clear_calls('manage_failover') self.instance.set_fail_on('manage_failover') res = call_manage_failover(self.console_sock, mode='eventual') self.assertFalse(res.success) self.assertIn('Failed admin_enable_failover', res.msg) self.assertIn('cartridge err', res.msg) # disable failover self.instance.set_variable('failover', True) self.instance.clear_calls('manage_failover') self.instance.set_fail_on('manage_failover') res = call_manage_failover(self.console_sock, mode='disabled') self.assertFalse(res.success) self.assertIn('Failed admin_disable_failover', res.msg) self.assertIn('cartridge err', res.msg) def test_enable_eventual_failover(self): self.instance.set_cartridge_version('2.1.0') # failover disabled self.instance.set_variable('failover_params', {'mode': 'disabled'}) self.instance.clear_calls('failover_set_params') res = call_manage_failover(self.console_sock, mode='eventual') self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], {'mode': 'eventual'}) # failover enabled self.instance.set_variable('failover_params', {'mode': 'eventual'}) self.instance.clear_calls('failover_set_params') res = call_manage_failover(self.console_sock, mode='eventual') self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], {'mode': 'eventual'}) def test_disable_eventual_failover(self): self.instance.set_cartridge_version('2.1.0') # failover enabled self.instance.set_variable('failover_params', {'mode': 'eventual'}) self.instance.clear_calls('failover_set_params') res = call_manage_failover(self.console_sock, mode='disabled') self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], {'mode': 'disabled'}) # failover disabled self.instance.set_variable('failover_params', {'mode': 'disabled'}) self.instance.clear_calls('failover_set_params') res = call_manage_failover(self.console_sock, mode='disabled') self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], {'mode': 'disabled'}) def test_stateful_failover_with_stateboard(self): self.instance.set_cartridge_version('2.1.0') STATEBOARD_PARAMS = { 'uri': 'localhost:3310', 'password': '******', } # failover disabled self.instance.set_variable('failover_params', {'mode': 'disabled'}) self.instance.clear_calls('failover_set_params') res = call_manage_failover(self.console_sock, mode='stateful', state_provider='stateboard', stateboard_params=STATEBOARD_PARAMS) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual( calls[0], { 'mode': 'stateful', 'state_provider': 'tarantool', 'tarantool_params': STATEBOARD_PARAMS, }) # stateful failover enabled - params aren't changed self.instance.set_variable( 'failover_params', { 'mode': 'stateful', 'state_provider': 'tarantool', 'tarantool_params': STATEBOARD_PARAMS, }) self.instance.clear_calls('failover_set_params') res = call_manage_failover(self.console_sock, mode='stateful', state_provider='stateboard', stateboard_params=STATEBOARD_PARAMS) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual( calls[0], { 'mode': 'stateful', 'state_provider': 'tarantool', 'tarantool_params': STATEBOARD_PARAMS, }) for p in ['uri', 'password']: # stateful failover enabled - one param is changed self.instance.set_variable( 'failover_params', { 'mode': 'stateful', 'state_provider': 'tarantool', 'tarantool_params': STATEBOARD_PARAMS, }) self.instance.clear_calls('failover_set_params') new_params = STATEBOARD_PARAMS.copy() new_params[p] = 'other-string-value' res = call_manage_failover(self.console_sock, mode='stateful', state_provider='stateboard', stateboard_params=new_params) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual( calls[0], { 'mode': 'stateful', 'state_provider': 'tarantool', 'tarantool_params': new_params, }) def test_stateful_failover_with_etcd2(self): self.instance.set_cartridge_version('2.1.0') ETCD2_PARAMS = { 'prefix': '/', 'lock_delay': 30, 'username': '******', 'password': '******', 'endpoints': ['localhost:2379', 'localhost:2380'] } # failover disabled self.instance.set_variable('failover_params', {'mode': 'disabled'}) self.instance.clear_calls('failover_set_params') res = call_manage_failover(self.console_sock, mode='stateful', state_provider='etcd2', etcd2_params=ETCD2_PARAMS) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual( calls[0], { 'mode': 'stateful', 'state_provider': 'etcd2', 'etcd2_params': ETCD2_PARAMS, }) # failover disabled self.instance.set_variable('failover_params', {'mode': 'disabled'}) self.instance.clear_calls('failover_set_params') res = call_manage_failover(self.console_sock, mode='stateful', state_provider='etcd2', etcd2_params=None) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual(calls[0], { 'mode': 'stateful', 'state_provider': 'etcd2', 'etcd2_params': [], }) # stateful failover enabled - params aren't changed self.instance.set_variable( 'failover_params', { 'mode': 'stateful', 'state_provider': 'etcd2', 'etcd2_params': ETCD2_PARAMS, }) self.instance.clear_calls('failover_set_params') res = call_manage_failover(self.console_sock, mode='stateful', state_provider='etcd2', etcd2_params=ETCD2_PARAMS) self.assertTrue(res.success, msg=res.msg) self.assertFalse(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual( calls[0], { 'mode': 'stateful', 'state_provider': 'etcd2', 'etcd2_params': ETCD2_PARAMS, }) for p in ['prefix', 'lock_delay', 'username', 'password', 'endpoints']: # stateful failover enabled - one param is changed self.instance.set_variable( 'failover_params', { 'mode': 'stateful', 'state_provider': 'etcd2', 'etcd2_params': ETCD2_PARAMS, }) self.instance.clear_calls('failover_set_params') new_params = ETCD2_PARAMS.copy() if p in ['prefix', 'username', 'password']: new_params[p] = 'other-string-value' elif p in ['lock_delay']: new_params[p] = new_params[p] + 15 elif p in ['endpoints']: new_params[p].append('localhost:2381') res = call_manage_failover(self.console_sock, mode='stateful', state_provider='etcd2', etcd2_params=new_params) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual( calls[0], { 'mode': 'stateful', 'state_provider': 'etcd2', 'etcd2_params': new_params, }) def test_stateful_failover_mixed(self): self.instance.set_cartridge_version('2.1.0') STATEBOARD_PARAMS = { 'uri': 'localhost:3310', 'password': '******', } ETCD2_PARAMS = { 'prefix': '/', 'lock_delay': 30, 'username': '******', 'password': '******', 'endpoints': ['localhost:2379', 'localhost:2380'] } # failover disabled -> enable stateboard self.instance.set_variable('failover_params', {'mode': 'disabled'}) self.instance.clear_calls('failover_set_params') res = call_manage_failover(self.console_sock, mode='stateful', state_provider='stateboard', etcd2_params=ETCD2_PARAMS, stateboard_params=STATEBOARD_PARAMS) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual( calls[0], { 'mode': 'stateful', 'state_provider': 'tarantool', 'tarantool_params': STATEBOARD_PARAMS, }) # failover disabled -> enable etcd2 self.instance.set_variable('failover_params', {'mode': 'disabled'}) self.instance.clear_calls('failover_set_params') res = call_manage_failover(self.console_sock, mode='stateful', state_provider='etcd2', etcd2_params=ETCD2_PARAMS, stateboard_params=STATEBOARD_PARAMS) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual( calls[0], { 'mode': 'stateful', 'state_provider': 'etcd2', 'etcd2_params': ETCD2_PARAMS, }) # stateboard state provider enabled -> switch to etcd2 self.instance.set_variable( 'failover_params', { 'mode': 'stateful', 'state_provider': 'tarantool', 'tarantool_params': STATEBOARD_PARAMS, }) self.instance.clear_calls('failover_set_params') res = call_manage_failover(self.console_sock, mode='stateful', state_provider='etcd2', etcd2_params=ETCD2_PARAMS, stateboard_params=STATEBOARD_PARAMS) self.assertTrue(res.success, msg=res.msg) self.assertTrue(res.changed) calls = self.instance.get_calls('failover_set_params') self.assertEqual(len(calls), 1) self.assertEqual( calls[0], { 'mode': 'stateful', 'state_provider': 'etcd2', 'etcd2_params': ETCD2_PARAMS, }) def tearDown(self): self.instance.stop()