def setUp(self): # Sets up the root user, toggles auth u = auth.EtcdUser(self.client, 'root') u.password = '******' u.write() self.client = etcd_gevent.Client(port=6001, username='******', password='******') self.unauth_client = etcd_gevent.Client(port=6001) a = auth.Auth(self.client) a.active = True
def test_allow_reconnect(self): """ Fails if allow_reconnect is false and a list of hosts is given""" with self.assertRaises(etcd_gevent.EtcdException): etcd_gevent.Client(host=(('localhost', 4001), ('localhost', 4002)), ) # This doesn't raise an exception client = etcd_gevent.Client( host=(('localhost', 4001), ('localhost', 4002)), allow_reconnect=True, use_proxies=True, )
def test_discover(self): """Tests discovery.""" answers = [] for i in range(1, 3): r = mock.create_autospec(dns.rdtypes.IN.SRV.SRV) r.port = 2379 try: method = dns.name.from_unicode except AttributeError: method = dns.name.from_text r.target = method(u'etcd{}.example.com'.format(i)) answers.append(r) dns.resolver.query = mock.create_autospec(dns.resolver.query, return_value=answers) self.machines = etcd_gevent.Client.machines etcd_gevent.Client.machines = mock.create_autospec( etcd_gevent.Client.machines, return_value=[u'https://etcd2.example.com:2379']) c = etcd_gevent.Client(srv_domain="example.com", allow_reconnect=True, protocol="https") etcd_gevent.Client.machines = self.machines self.assertEquals(c.host, u'etcd1.example.com') self.assertEquals(c.port, 2379) self.assertEquals(c._machines_cache, [u'https://etcd2.example.com:2379'])
def test_set(self): """ Can set a value """ client = etcd_gevent.Client() client.api_execute = mock.Mock(return_value=FakeHTTPResponse( 201, '{"action":"SET",' '"node": {' '"key":"/testkey",' '"value":"test",' '"newKey":true,' '"expiration":"2013-09-14T00:56:59.316195568+02:00",' '"ttl":19,"modifiedIndex":183}}')) result = client.set('/testkey', 'test', ttl=19) self.assertEquals( etcd_gevent.EtcdResult( **{ u'action': u'SET', 'node': { u'expiration': u'2013-09-14T00:56:59.316195568+02:00', u'modifiedIndex': 183, u'key': u'/testkey', u'newKey': True, u'ttl': 19, u'value': u'test' } }), result)
def test_put(self): """ http put request """ client = etcd_gevent.Client() response = FakeHTTPResponse(status=200, data='arbitrary json data') client.http.request = mock.Mock(return_value=response) result = client.api_execute('/v2/keys/testkey', client._MPUT) self.assertEquals('arbitrary json data'.encode('utf-8'), result.data)
def test_get_error_invalid(self): """ http get error request invalid """ client = etcd_gevent.Client() response = FakeHTTPResponse(status=400, data='{){){)*garbage*') client.http.request = mock.Mock(return_value=response) self.assertRaises(etcd_gevent.EtcdException, client.api_execute, '/v2/keys/testkey', client._MGET)
def test_test_and_set(self): """ Can test and set a value """ client = etcd_gevent.Client() client.api_execute = mock.Mock(return_value=FakeHTTPResponse( 200, '{"action":"SET",' '"node": {' '"key":"/testkey",' '"prevValue":"test",' '"value":"newvalue",' '"expiration":"2013-09-14T02:09:44.24390976+02:00",' '"ttl":49,"modifiedIndex":203}}')) result = client.test_and_set('/testkey', 'newvalue', 'test', ttl=19) self.assertEquals( etcd_gevent.EtcdResult( **{ u'action': u'SET', u'node': { u'expiration': u'2013-09-14T02:09:44.24390976+02:00', u'modifiedIndex': 203, u'key': u'/testkey', u'prevValue': u'test', u'ttl': 49, u'value': u'newvalue' } }), result)
def test_read(self): u = auth.EtcdUser(self.client, 'root') # Reading an existing user succeeds try: u.read() except Exception: self.fail("reading the root user raised an exception") # roles for said user are fetched self.assertEquals(u.roles, set(['root'])) # The user is correctly rendered out self.assertEquals(u._to_net(), [{'user': '******', 'password': None, 'roles': ['root']}]) # An inexistent user raises the appropriate exception u = auth.EtcdUser(self.client, 'user.does.not.exist') self.assertRaises(etcd_gevent.EtcdKeyNotFound, u.read) # Reading with an unauthenticated client raises an exception u = auth.EtcdUser(self.unauth_client, 'root') self.assertRaises(etcd_gevent.EtcdInsufficientPermissions, u.read) # Generic errors are caught c = etcd_gevent.Client(port=9999) u = auth.EtcdUser(c, 'root') self.assertRaises(etcd_gevent.EtcdException, u.read)
def test_index_watch(self): """ Can watch values from index """ client = etcd_gevent.Client() client.api_execute = mock.Mock(return_value=FakeHTTPResponse( 200, '{"action":"SET",' '"node": {' '"key":"/testkey",' '"value":"test",' '"newKey":true,' '"expiration":"2013-09-14T01:35:07.623681365+02:00",' '"ttl":19,' '"modifiedIndex":180}}')) result = client.watch('/testkey', index=180) self.assertEquals( etcd_gevent.EtcdResult( **{ u'action': u'SET', u'node': { u'expiration': u'2013-09-14T01:35:07.623681365+02:00', u'modifiedIndex': 180, u'key': u'/testkey', u'newKey': True, u'ttl': 19, u'value': u'test' } }), result)
def test_reconnect_not_allowed(self): """ INTEGRATION: fail on server kill if not allow_reconnect """ self.processHelper.stop() self.processHelper.run(number=3) self.client = etcd_gevent.Client(port=6001, allow_reconnect=False) self.processHelper.kill_one(0) self.assertRaises(etcd_gevent.EtcdConnectionFailed, self.client.get, '/test_set')
def test_get_set_unauthenticated(self): """ INTEGRATION: set/get a new value unauthenticated (http->https) """ client = etcd_gevent.Client(port=6001) # See above for the reason of this change self.assertRaises(etcd_gevent.EtcdException, client.set, '/test_set', 'test-key') self.assertRaises(etcd_gevent.EtcdException, client.get, '/test_set')
def test_get_set_authenticated(self): """ INTEGRATION: set/get a new value authenticated """ client = etcd_gevent.Client(port=6001, protocol='https', ca_cert=self.ca_cert_path) set_result = client.set('/test_set', 'test-key') get_result = client.get('/test_set')
def test_get_set_unauthenticated_with_ca(self): """ INTEGRATION: try unauthenticated with validation (https->https)""" client = etcd_gevent.Client(protocol='https', port=6001, ca_cert=self.ca2_cert_path) self.assertRaises(etcd_gevent.EtcdConnectionFailed, client.set, '/test-set', 'test-key') self.assertRaises(etcd_gevent.EtcdConnectionFailed, client.get, '/test-set')
def setUpClass(cls): program = cls._get_exe() cls.directory = tempfile.mkdtemp(prefix='etcd-gevent') cls.processHelper = helpers.EtcdProcessHelper( cls.directory, proc_name=program, port_range_start=6001, internal_port_range_start=8001) cls.processHelper.run(number=cls.cl_size) cls.client = etcd_gevent.Client(port=6001)
def test_get_error_request_invalid(self): """ http get error request invalid """ client = etcd_gevent.Client() response = FakeHTTPResponse(status=400, data='{)*garbage') client.http.request = mock.Mock(return_value=response) try: client.api_execute('/v2/keys/testkey', client._MGET) self.fail() except etcd_gevent.EtcdException as e: self.assertEqual(str(e), "Bad response : {)*garbage")
def test_in(self): """ Can check if key is in client """ client = etcd_gevent.Client() client.api_execute = mock.Mock(return_value=FakeHTTPResponse( 200, '{"action":"GET",' '"node": {' '"key":"/testkey",' '"value":"test",' '"modifiedIndex":190}}')) result = '/testkey' in client self.assertEquals(True, result)
def test_get_set_unauthenticated(self): """ INTEGRATION: set/get a new value unauthenticated (http->https) """ client = etcd_gevent.Client(port=6001) # Since python 3 raises a MaxRetryError here, this gets caught in # different code blocks in python 2 and python 3, thus messages are # different. Python 3 does the right thing(TM), for the record self.assertRaises(etcd_gevent.EtcdException, client.set, '/test_set', 'test-key') self.assertRaises(etcd_gevent.EtcdException, client.get, '/test_set')
def test_write_and_delete(self): # Create an user u = auth.EtcdUser(self.client, 'test_user') u.roles.add('guest') u.roles.add('root') # directly from my suitcase u.password = '******' try: u.write() except: self.fail("creating a user doesn't work") # Password gets wiped self.assertEquals(u.password, None) u.read() # Verify we can log in as this user and access the auth (it has the # root role) cl = etcd_gevent.Client(port=6001, username='******', password='******') ul = auth.EtcdUser(cl, 'root') try: ul.read() except etcd_gevent.EtcdInsufficientPermissions: self.fail("Reading auth with the new user is not possible") self.assertEquals(u.name, "test_user") self.assertEquals(u.roles, set(['guest', 'root'])) # set roles as a list, it works! u.roles = ['guest', 'test_group'] # We need this or the new API will return an internal error r = auth.EtcdRole(self.client, 'test_group') r.acls = {'*': 'R', '/test/*': 'RW'} r.write() try: u.write() except: self.fail("updating a user you previously created fails") u.read() self.assertIn('test_group', u.roles) # Unauthorized access is properly handled ua = auth.EtcdUser(self.unauth_client, 'test_user') self.assertRaises(etcd_gevent.EtcdInsufficientPermissions, ua.write) # now let's test deletion du = auth.EtcdUser(self.client, 'user.does.not.exist') self.assertRaises(etcd_gevent.EtcdKeyNotFound, du.delete) # Delete test_user u.delete() self.assertRaises(etcd_gevent.EtcdKeyNotFound, u.read) # Permissions are properly handled self.assertRaises(etcd_gevent.EtcdInsufficientPermissions, ua.delete)
def test_get_error(self): """ http get error request 101""" client = etcd_gevent.Client() response = FakeHTTPResponse(status=400, data='{"message": "message",' ' "cause": "cause",' ' "errorCode": 100}') client.http.request = mock.Mock(return_value=response) try: client.api_execute('/v2/keys/testkey', client._MGET) assert False except etcd_gevent.EtcdKeyNotFound as e: self.assertEquals(str(e), 'message : cause')
def test_set_not_file_error(self): """ http post error request 102 """ client = etcd_gevent.Client() response = FakeHTTPResponse( status=400, data='{"message": "message", "cause": "cause", "errorCode": 102}') client.http.request = mock.Mock(return_value=response) payload = {'value': 'value', 'prevValue': 'oldValue', 'ttl': '60'} try: client.api_execute('/v2/keys/testkey', client._MPUT, payload) self.fail() except etcd_gevent.EtcdNotFile as e: self.assertEquals('message : cause', str(e))
def test_get_error_unknown(self): """ http get error request unknown """ client = etcd_gevent.Client() response = FakeHTTPResponse(status=400, data='{"message": "message",' ' "cause": "cause",' ' "errorCode": 42}') client.http.request = mock.Mock(return_value=response) try: client.api_execute('/v2/keys/testkey', client._MGET) self.fail() except etcd_gevent.EtcdException as e: self.assertEqual(str(e), "message : cause")
def test_reconnect(self): """ INTEGRATION: get key after the server we're connected fails. """ self.processHelper.stop() self.processHelper.run(number=3) self.client = etcd_gevent.Client(port=6001, allow_reconnect=True) set_result = self.client.set('/test_set', 'test-key1') get_result = self.client.get('/test_set') self.assertEquals('test-key1', get_result.value) self.processHelper.kill_one(0) get_result = self.client.get('/test_set') self.assertEquals('test-key1', get_result.value)
def test_use_proxies(self, mocker): """Do not overwrite the machines cache when using proxies""" mocker.return_value = ['https://10.0.0.2:4001', 'https://10.0.0.3:4001', 'https://10.0.0.4:4001'] c = etcd_gevent.Client( host=(('localhost', 4001), ('localproxy', 4001)), protocol='https', allow_reconnect=True, use_proxies=True ) self.assertEquals(c._machines_cache, ['https://localproxy:4001']) self.assertEquals(c._base_uri, 'https://localhost:4001') self.assertNotIn(c.base_uri, c._machines_cache) c = etcd_gevent.Client( host=(('localhost', 4001), ('10.0.0.2', 4001)), protocol='https', allow_reconnect=True, use_proxies=False ) self.assertIn('https://10.0.0.3:4001', c._machines_cache) self.assertNotIn(c.base_uri, c._machines_cache)
def test_reconnet_fails(self): """ INTEGRATION: fails to reconnect if no available machines """ self.processHelper.stop() # Start with three instances (0, 1, 2) self.processHelper.run(number=3) # Connect to instance 0 self.client = etcd_gevent.Client(port=6001, allow_reconnect=True) set_result = self.client.set('/test_set', 'test-key1') get_result = self.client.get('/test_set') self.assertEquals('test-key1', get_result.value) self.processHelper.kill_one(2) self.processHelper.kill_one(1) self.processHelper.kill_one(0) self.assertRaises(etcd_gevent.EtcdException, self.client.get, '/test_set')
def test_eternal_watch(self): """ Can watch values from generator """ client = etcd_gevent.Client() client.api_execute = mock.Mock(return_value=FakeHTTPResponse( 200, '{"action":"SET",' '"node": {' '"key":"/testkey",' '"value":"test",' '"newKey":true,' '"expiration":"2013-09-14T01:35:07.623681365+02:00",' '"ttl":19,' '"modifiedIndex":180}}')) for result in range(1, 5): result = next(client.eternal_watch('/testkey', index=180)) yield self.check_watch, result
def test_test_and_test_failure(self): """ Exception will be raised if prevValue != value in test_set """ client = etcd_gevent.Client() client.api_execute = mock.Mock(side_effect=ValueError( 'The given PrevValue is not equal' ' to the value of the key : TestAndSet: 1!=3')) try: result = client.test_and_set('/testkey', 'newvalue', 'test', ttl=19) except ValueError as e: #from ipdb import set_trace; set_trace() self.assertEquals( 'The given PrevValue is not equal' ' to the value of the key : TestAndSet: 1!=3', str(e))
def test_reconnect_with_several_hosts_passed(self): """ INTEGRATION: receive several hosts at connection setup. """ self.processHelper.stop() self.processHelper.run(number=3) self.client = etcd_gevent.Client( host=( ('127.0.0.1', 6004), ('127.0.0.1', 6001)), allow_reconnect=True) set_result = self.client.set('/test_set', 'test-key1') get_result = self.client.get('/test_set') self.assertEquals('test-key1', get_result.value) self.processHelper.kill_one(0) get_result = self.client.get('/test_set') self.assertEquals('test-key1', get_result.value)
def test_get_set_authenticated(self): """ INTEGRATION: connecting to server with mutual auth """ # This gives an unexplicable ssl error, as connecting to the same # Etcd cluster where this fails with the exact same code this # doesn't fail client = etcd_gevent.Client(port=6001, protocol='https', cert=self.client_all_cert, ca_cert=self.ca_cert_path) set_result = client.set('/test_set', 'test-key') self.assertEquals(u'set', set_result.action.lower()) self.assertEquals(u'/test_set', set_result.key) self.assertEquals(u'test-key', set_result.value) get_result = client.get('/test_set') self.assertEquals('get', get_result.action.lower()) self.assertEquals('/test_set', get_result.key) self.assertEquals('test-key', get_result.value)
def test_get(self): """ Can get a value """ client = etcd_gevent.Client() client.api_execute = mock.Mock(return_value=FakeHTTPResponse( 200, '{"action":"GET",' '"node": {' '"key":"/testkey",' '"value":"test",' '"modifiedIndex":190}}')) result = client.get('/testkey') self.assertEquals( etcd_gevent.EtcdResult( **{ u'action': u'GET', u'node': { u'modifiedIndex': 190, u'key': u'/testkey', u'value': u'test' } }), result)
def test_delete(self): """ Can delete a value """ client = etcd_gevent.Client() client.api_execute = mock.Mock(return_value=FakeHTTPResponse( 200, '{"action":"DELETE",' '"node": {' '"key":"/testkey",' '"prevValue":"test",' '"expiration":"2013-09-14T01:06:35.5242587+02:00",' '"modifiedIndex":189}}')) result = client.delete('/testkey') self.assertEquals( etcd_gevent.EtcdResult( **{ u'action': u'DELETE', u'node': { u'expiration': u'2013-09-14T01:06:35.5242587+02:00', u'modifiedIndex': 189, u'key': u'/testkey', u'prevValue': u'test' } }), result)