def test_error(self): """Test a regular server error raises the right exception.""" error_request = 'error://unknown error' error_caller_id = vtgate_client.CallerID(principal=error_request) # Begin test with self.assertRaisesRegexp(dbexceptions.DatabaseError, 'forced error'): self.conn.begin(error_caller_id) # Commit test with self.assertRaisesRegexp(dbexceptions.DatabaseError, 'forced error'): self.conn.begin(error_caller_id) # Rollback test with self.assertRaisesRegexp(dbexceptions.DatabaseError, 'forced error'): self.conn.begin(error_caller_id) # GetSrvKeyspace test with self.assertRaisesRegexp(dbexceptions.DatabaseError, 'forced error'): self.conn.get_srv_keyspace(error_request)
class TestEcho(TestPythonClientBase): """Send queries to the server, check the returned result matches.""" echo_prefix = 'echo://' query = 'test query with bind variables: %(int)s %(float)s %(bytes)s' query_echo = 'test query with bind variables: :int :float :bytes' keyspace = 'test_keyspace' shards = ['-80', '80-'] shards_echo = '[-80 80-]' keyspace_ids = ['\x01\x02\x03\x04', '\x05\x06\x07\x08'] keyspace_ids_echo = '[[1 2 3 4] [5 6 7 8]]' # FIXME(alainjobart) using a map for the entities makes it impossible to # guarantee the order of the entities in the query. It is really an API # problem here? For this test, however, I'll just use a single value for now entity_keyspace_ids = { 123: '\x01\x02\x03', # 2.0: '\x04\x05\x06', # '\x01\x02\x03': '\x07\x08\x09', } # entity_keyspace_ids_echo = ('[type:INT64 value:"123" ' # 'keyspace_id:"\\001\\002\\003" ' # 'type:FLOAT64 value:"2" ' # 'keyspace_id:"\\004\\005\\006" ' # 'type:VARBINARY value:"\\001\\002\\003" ' # 'keyspace_id:"\\007\\010\\t" ]') entity_keyspace_ids_echo = ('[type:INT64 value:"123" ' 'keyspace_id:"\\001\\002\\003" ]') key_ranges = [keyrange.KeyRange('01020304-05060708')] key_ranges_echo = '[start:"\\001\\002\\003\\004" end:"\\005\\006\\007\\010" ]' tablet_type = 'replica' tablet_type_echo = 'REPLICA' bind_variables = { 'int': 123, 'float': 2.1, 'bytes': '\x01\x02\x03', } bind_variables_echo = 'map[bytes:[1 2 3] float:2.1 int:123]' bind_variables_p3_echo = ( 'map[bytes:type:VARBINARY value:"\\001\\002\\003" ' 'float:type:FLOAT64 value:"2.1" ' 'int:type:INT64 value:"123" ]') caller_id = vtgate_client.CallerID(principal='test_principal', component='test_component', subcomponent='test_subcomponent') caller_id_echo = ('principal:"test_principal" component:"test_component"' ' subcomponent:"test_subcomponent" ') def test_echo_execute(self): # Execute cursor = self.conn.cursor(tablet_type=self.tablet_type, keyspace=None) cursor.set_effective_caller_id(self.caller_id) cursor.execute(self.echo_prefix + self.query, self.bind_variables) self._check_echo( cursor, { 'callerId': self.caller_id_echo, # FIXME(alainjobart) change this to query_echo once v3 understand binds 'query': self.echo_prefix + self.query, 'bindVars': self.bind_variables_echo, 'tabletType': self.tablet_type_echo, }) cursor.close() # ExecuteShards cursor = self.conn.cursor(tablet_type=self.tablet_type, keyspace=self.keyspace, shards=self.shards) cursor.set_effective_caller_id(self.caller_id) cursor.execute(self.echo_prefix + self.query, self.bind_variables) self._check_echo( cursor, { 'callerId': self.caller_id_echo, 'query': self.echo_prefix + self.query_echo, 'keyspace': self.keyspace, 'shards': self.shards_echo, 'bindVars': self.bind_variables_echo, 'tabletType': self.tablet_type_echo, }) cursor.close() # ExecuteKeyspaceIds cursor = self.conn.cursor(tablet_type=self.tablet_type, keyspace=self.keyspace, keyspace_ids=self.keyspace_ids) cursor.set_effective_caller_id(self.caller_id) cursor.execute(self.echo_prefix + self.query, self.bind_variables) self._check_echo( cursor, { 'callerId': self.caller_id_echo, 'query': self.echo_prefix + self.query_echo, 'keyspace': self.keyspace, 'keyspaceIds': self.keyspace_ids_echo, 'bindVars': self.bind_variables_echo, 'tabletType': self.tablet_type_echo, }) cursor.close() # ExecuteKeyRanges cursor = self.conn.cursor(tablet_type=self.tablet_type, keyspace=self.keyspace, keyranges=self.key_ranges) cursor.set_effective_caller_id(self.caller_id) cursor.execute(self.echo_prefix + self.query, self.bind_variables) self._check_echo( cursor, { 'callerId': self.caller_id_echo, 'query': self.echo_prefix + self.query_echo, 'keyspace': self.keyspace, 'keyRanges': self.key_ranges_echo, 'bindVars': self.bind_variables_echo, 'tabletType': self.tablet_type_echo, }) cursor.close() # ExecuteEntityIds cursor = self.conn.cursor(tablet_type=self.tablet_type, keyspace=self.keyspace) cursor.set_effective_caller_id(self.caller_id) cursor.execute(self.echo_prefix + self.query, self.bind_variables, entity_keyspace_id_map=self.entity_keyspace_ids, entity_column_name='column1') self._check_echo( cursor, { 'callerId': self.caller_id_echo, 'query': self.echo_prefix + self.query_echo, 'keyspace': self.keyspace, 'entityColumnName': 'column1', 'entityIds': self.entity_keyspace_ids_echo, 'bindVars': self.bind_variables_echo, 'tabletType': self.tablet_type_echo, }) cursor.close() # ExecuteBatchShards cursor = self.conn.cursor(tablet_type=self.tablet_type, keyspace=None, as_transaction=True) cursor.set_effective_caller_id(self.caller_id) cursor.executemany(sql=None, params_list=[ dict(sql=self.echo_prefix + self.query, bind_variables=self.bind_variables, keyspace=self.keyspace, shards=self.shards) ]) self._check_echo( cursor, { 'callerId': self.caller_id_echo, 'query': self.echo_prefix + self.query_echo, 'keyspace': self.keyspace, 'shards': self.shards_echo, 'bindVars': self.bind_variables_p3_echo, 'tabletType': self.tablet_type_echo, 'asTransaction': 'true', }) cursor.close() # ExecuteBatchKeyspaceIds cursor = self.conn.cursor(tablet_type=self.tablet_type, keyspace=None, as_transaction=True) cursor.set_effective_caller_id(self.caller_id) cursor.executemany(sql=None, params_list=[ dict(sql=self.echo_prefix + self.query, bind_variables=self.bind_variables, keyspace=self.keyspace, keyspace_ids=self.keyspace_ids) ]) self._check_echo( cursor, { 'callerId': self.caller_id_echo, 'query': self.echo_prefix + self.query_echo, 'keyspace': self.keyspace, 'keyspaceIds': self.keyspace_ids_echo, 'bindVars': self.bind_variables_p3_echo, 'tabletType': self.tablet_type_echo, 'asTransaction': 'true', }) cursor.close() def _get_echo(self, cursor): result = {} data = cursor.fetchall() for i, (n, _) in enumerate(cursor.description): result[n] = data[0][i] return result def _check_echo(self, cursor, values): got = self._get_echo(cursor) for k, v in values.iteritems(): self.assertEqual( got[k], v, 'item %s is different in result: got %s' ' expected %s' % (k, got[k], v)) # Check NULL and empty string. self.assertEqual(got['null'], None) self.assertEqual(got['emptyString'], '')
def test_effective_caller_id(self): """Test that the passed in effective_caller_id is parsed correctly. Pass a special sql query that sends the expected effective_caller_id through different vtgate interfaces. Make sure the good_effective_caller_id works, and the bad_effective_caller_id raises a DatabaseError. """ # Special query that makes vtgateclienttest match effective_caller_id. effective_caller_id_test_query = ( 'callerid://{"principal":"pr", "component":"co", "subcomponent":"su"}' ) good_effective_caller_id = vtgate_client.CallerID(principal='pr', component='co', subcomponent='su') bad_effective_caller_id = vtgate_client.CallerID( principal='pr_wrong', component='co_wrong', subcomponent='su_wrong') def check_good_and_bad_effective_caller_ids(cursor, cursor_execute_method): cursor.set_effective_caller_id(good_effective_caller_id) with self.assertRaises(dbexceptions.DatabaseError) as cm: cursor_execute_method(cursor) self.assertIn('SUCCESS:', str(cm.exception)) cursor.set_effective_caller_id(bad_effective_caller_id) with self.assertRaises(dbexceptions.DatabaseError) as cm: cursor_execute_method(cursor) self.assertNotIn('SUCCESS:', str(cm.exception)) # test Execute def cursor_execute_method(cursor): cursor.execute(effective_caller_id_test_query, {}) check_good_and_bad_effective_caller_ids(self._open_v3_cursor(), cursor_execute_method) # test ExecuteShards def cursor_execute_shards_method(cursor): cursor.execute(effective_caller_id_test_query, {}) check_good_and_bad_effective_caller_ids(self._open_shards_cursor(), cursor_execute_shards_method) # test ExecuteKeyspaceIds def cursor_execute_keyspace_ids_method(cursor): cursor.execute(effective_caller_id_test_query, {}) check_good_and_bad_effective_caller_ids( self._open_keyspace_ids_cursor(), cursor_execute_keyspace_ids_method) # test ExecuteKeyRanges def cursor_execute_key_ranges_method(cursor): cursor.execute(effective_caller_id_test_query, {}) check_good_and_bad_effective_caller_ids( self._open_keyranges_cursor(), cursor_execute_key_ranges_method) # test ExecuteEntityIds def cursor_execute_entity_ids_method(cursor): cursor.execute(effective_caller_id_test_query, {}, entity_keyspace_id_map={1: self.KEYSPACE_ID_0X80}, entity_column_name='user_id') check_good_and_bad_effective_caller_ids( self.conn.cursor(tablet_type='master', keyspace='keyspace'), cursor_execute_entity_ids_method) # test ExecuteBatchKeyspaceIds def cursor_execute_batch_keyspace_ids_method(cursor): cursor.executemany(sql=None, params_list=[ dict(sql=effective_caller_id_test_query, bind_variables={}, keyspace='keyspace', keyspace_ids=[self.KEYSPACE_ID_0X80]) ]) check_good_and_bad_effective_caller_ids( self._open_batch_cursor(), cursor_execute_batch_keyspace_ids_method) # test ExecuteBatchShards def cursor_execute_batch_shard_method(cursor): cursor.executemany(sql=None, params_list=[ dict(sql=effective_caller_id_test_query, bind_variables={}, keyspace='keyspace', shards=[keyrange_constants.SHARD_ZERO]) ]) check_good_and_bad_effective_caller_ids( self._open_batch_cursor(), cursor_execute_batch_shard_method) # test StreamExecute def cursor_stream_execute_v3_method(cursor): cursor.execute(sql=effective_caller_id_test_query, bind_variables={}) check_good_and_bad_effective_caller_ids( self._open_stream_v3_cursor(), cursor_stream_execute_v3_method) # test StreamExecuteShards def cursor_stream_execute_shards_method(cursor): cursor.execute(sql=effective_caller_id_test_query, bind_variables={}) check_good_and_bad_effective_caller_ids( self._open_stream_shards_cursor(), cursor_stream_execute_shards_method) # test StreamExecuteKeyspaceIds def cursor_stream_execute_keyspace_ids_method(cursor): cursor.execute(sql=effective_caller_id_test_query, bind_variables={}) check_good_and_bad_effective_caller_ids( self._open_stream_keyspace_ids_cursor(), cursor_stream_execute_keyspace_ids_method) # test StreamExecuteKeyRanges def cursor_stream_execute_keyranges_method(cursor): cursor.execute(sql=effective_caller_id_test_query, bind_variables={}) check_good_and_bad_effective_caller_ids( self._open_stream_keyranges_cursor(), cursor_stream_execute_keyranges_method)
class TestEcho(TestPythonClientBase): """Send queries to the server, check the returned result matches.""" echo_prefix = 'echo://' query = ( u'test query with bind variables: :int :float :bytes, unicode: ' u'\u6211\u80fd\u541e\u4e0b\u73bb\u7483\u800c\u4e0d\u50b7\u8eab\u9ad4' ).encode('utf-8') query_echo = ( u'test query with bind variables: :int :float :bytes, unicode: ' u'\u6211\u80fd\u541e\u4e0b\u73bb\u7483\u800c\u4e0d\u50b7\u8eab\u9ad4' ).encode('utf-8') keyspace = 'test_keyspace' shards = ['-80', '80-'] shards_echo = '[-80 80-]' keyspace_ids = ['\x01\x02\x03\x04', '\x05\x06\x07\x08'] keyspace_ids_echo = '[[1 2 3 4] [5 6 7 8]]' # FIXME(alainjobart) using a map for the entities makes it impossible to # guarantee the order of the entities in the query. It is really an API # problem here? For this test, however, I'll just use a single value for now entity_keyspace_ids = { 123: '\x01\x02\x03', # 2.0: '\x04\x05\x06', # '\x01\x02\x03': '\x07\x08\x09', } # entity_keyspace_ids_echo = ('[type:INT64 value:"123" ' # 'keyspace_id:"\\001\\002\\003" ' # 'type:FLOAT64 value:"2" ' # 'keyspace_id:"\\004\\005\\006" ' # 'type:VARBINARY value:"\\001\\002\\003" ' # 'keyspace_id:"\\007\\010\\t" ]') entity_keyspace_ids_echo = ('[type:INT64 value:"123" ' 'keyspace_id:"\\001\\002\\003" ]') key_ranges = [keyrange.KeyRange('01020304-05060708')] key_ranges_echo = '[start:"\\001\\002\\003\\004" end:"\\005\\006\\007\\010" ]' tablet_type = 'replica' tablet_type_echo = 'REPLICA' bind_variables = { 'int': 123, 'float': 2.1, 'bytes': '\x01\x02\x03', 'bool': True, } bind_variables_echo = ('map[bool:type:INT64 value:"1" ' 'bytes:type:VARBINARY value:"\\001\\002\\003" ' 'float:type:FLOAT64 value:"2.1" ' 'int:type:INT64 value:"123" ]') caller_id = vtgate_client.CallerID(principal='test_principal', component='test_component', subcomponent='test_subcomponent') caller_id_echo = ('principal:"test_principal" component:"test_component"' ' subcomponent:"test_subcomponent" ') event_token = query_pb2.EventToken(timestamp=123, shard=shards[0], position='test_pos') options_echo = ('include_event_token:true compare_event_token:' '<timestamp:123 shard:"-80" position:"test_pos" > ') session_echo = ('autocommit:true target_string:"@replica" ' 'options:<include_event_token:' 'true compare_event_token:<timestamp:123 shard:' '"-80" position:"test_pos" > > ') def test_echo_execute(self): """This test calls the echo method.""" # Execute cursor = self.conn.cursor(tablet_type=self.tablet_type, keyspace=None) cursor.set_effective_caller_id(self.caller_id) cursor.execute(self.echo_prefix + self.query, self.bind_variables, include_event_token=True, compare_event_token=self.event_token) self._check_echo( cursor, { 'callerId': self.caller_id_echo, # FIXME(alainjobart) change this to query_echo once v3 understand binds 'query': self.echo_prefix + self.query, 'bindVars': self.bind_variables_echo, 'session': self.session_echo, }) cursor.close() # ExecuteShards cursor = self.conn.cursor(tablet_type=self.tablet_type, keyspace=self.keyspace, shards=self.shards) cursor.set_effective_caller_id(self.caller_id) cursor.execute(self.echo_prefix + self.query, self.bind_variables, include_event_token=True, compare_event_token=self.event_token) self._check_echo( cursor, { 'callerId': self.caller_id_echo, 'query': self.echo_prefix + self.query_echo, 'keyspace': self.keyspace, 'shards': self.shards_echo, 'bindVars': self.bind_variables_echo, 'tabletType': self.tablet_type_echo, 'options': self.options_echo, 'fresher': True, 'eventToken': self.event_token, }) cursor.close() # ExecuteKeyspaceIds cursor = self.conn.cursor(tablet_type=self.tablet_type, keyspace=self.keyspace, keyspace_ids=self.keyspace_ids) cursor.set_effective_caller_id(self.caller_id) cursor.execute(self.echo_prefix + self.query, self.bind_variables, include_event_token=True, compare_event_token=self.event_token) self._check_echo( cursor, { 'callerId': self.caller_id_echo, 'query': self.echo_prefix + self.query_echo, 'keyspace': self.keyspace, 'keyspaceIds': self.keyspace_ids_echo, 'bindVars': self.bind_variables_echo, 'tabletType': self.tablet_type_echo, 'options': self.options_echo, 'fresher': True, 'eventToken': self.event_token, }) cursor.close() # ExecuteKeyRanges cursor = self.conn.cursor(tablet_type=self.tablet_type, keyspace=self.keyspace, keyranges=self.key_ranges) cursor.set_effective_caller_id(self.caller_id) cursor.execute(self.echo_prefix + self.query, self.bind_variables, include_event_token=True, compare_event_token=self.event_token) self._check_echo( cursor, { 'callerId': self.caller_id_echo, 'query': self.echo_prefix + self.query_echo, 'keyspace': self.keyspace, 'keyRanges': self.key_ranges_echo, 'bindVars': self.bind_variables_echo, 'tabletType': self.tablet_type_echo, }) cursor.close() # ExecuteEntityIds cursor = self.conn.cursor(tablet_type=self.tablet_type, keyspace=self.keyspace) cursor.set_effective_caller_id(self.caller_id) cursor.execute(self.echo_prefix + self.query, self.bind_variables, entity_keyspace_id_map=self.entity_keyspace_ids, entity_column_name='column1', include_event_token=True, compare_event_token=self.event_token) self._check_echo( cursor, { 'callerId': self.caller_id_echo, 'query': self.echo_prefix + self.query_echo, 'keyspace': self.keyspace, 'entityColumnName': 'column1', 'entityIds': self.entity_keyspace_ids_echo, 'bindVars': self.bind_variables_echo, 'tabletType': self.tablet_type_echo, 'options': self.options_echo, 'fresher': True, 'eventToken': self.event_token, }) cursor.close() # ExecuteBatchShards cursor = self.conn.cursor(tablet_type=self.tablet_type, keyspace=None, as_transaction=True) cursor.set_effective_caller_id(self.caller_id) cursor.executemany(sql=None, params_list=[ dict(sql=self.echo_prefix + self.query, bind_variables=self.bind_variables, keyspace=self.keyspace, shards=self.shards) ]) self._check_echo( cursor, { 'callerId': self.caller_id_echo, 'query': self.echo_prefix + self.query_echo, 'keyspace': self.keyspace, 'shards': self.shards_echo, 'bindVars': self.bind_variables_echo, 'tabletType': self.tablet_type_echo, 'asTransaction': 'true', }) cursor.close() # ExecuteBatchKeyspaceIds cursor = self.conn.cursor(tablet_type=self.tablet_type, keyspace=None, as_transaction=True) cursor.set_effective_caller_id(self.caller_id) cursor.executemany(sql=None, params_list=[ dict(sql=self.echo_prefix + self.query, bind_variables=self.bind_variables, keyspace=self.keyspace, keyspace_ids=self.keyspace_ids) ]) self._check_echo( cursor, { 'callerId': self.caller_id_echo, 'query': self.echo_prefix + self.query_echo, 'keyspace': self.keyspace, 'keyspaceIds': self.keyspace_ids_echo, 'bindVars': self.bind_variables_echo, 'tabletType': self.tablet_type_echo, 'asTransaction': 'true', }) cursor.close() def _get_echo(self, cursor): result = {} data = cursor.fetchall() for i, (n, _) in enumerate(cursor.description): result[n] = data[0][i] return result def _check_echo(self, cursor, values): """_check_echo makes sure the echo result is correct.""" got = self._get_echo(cursor) for k, v in values.iteritems(): if k == 'fresher': self.assertTrue(self.conn.fresher) elif k == 'eventToken': self.assertEqual( text_format.MessageToString(self.conn.event_token), text_format.MessageToString(v)) else: self.assertEqual( got[k], v, 'item %s is different in result: got %s' ' expected %s' % (k, got[k], v)) # Check NULL and empty string. self.assertEqual(got['null'], None) self.assertEqual(got['emptyString'], '')
shards=['0']) # not passing any immediate caller id should fail as using # the unsecure user "unsecure_grpc_client" cursor.set_effective_caller_id(None) try: cursor.execute('select * from vt_insert_test', {}) self.fail('Execute went through') except dbexceptions.DatabaseError, e: s = str(e) self.assertIn('table acl error', s) self.assertIn('cannot run PASS_SELECT on table', s) self.assertIn('unsecure_grpc_client', s) # 'vtgate client 1' is authorized to access vt_insert_test cursor.set_effective_caller_id(vtgate_client.CallerID( principal='vtgate client 1')) cursor.execute('select * from vt_insert_test', {}) # 'vtgate client 2' is not authorized to access vt_insert_test cursor.set_effective_caller_id(vtgate_client.CallerID( principal='vtgate client 2')) try: cursor.execute('select * from vt_insert_test', {}) self.fail('Execute went through') except dbexceptions.DatabaseError, e: s = str(e) self.assertIn('table acl error', s) self.assertIn('cannot run PASS_SELECT on table', s) conn.close()
def test_effective_caller_id(self): """Test that the passed in effective_caller_id is parsed correctly. Pass a special sql query that sends the expected effective_caller_id through different vtgate interfaces. Make sure the good_effective_caller_id works, and the bad_effective_caller_id raises a DatabaseError. """ # Special query that makes vtgateclienttest match effective_caller_id. effective_caller_id_test_query = ( 'callerid://{"principal":"pr", "component":"co", "subcomponent":"su"}' ) good_effective_caller_id = vtgate_client.CallerID(principal='pr', component='co', subcomponent='su') bad_effective_caller_id = vtgate_client.CallerID( principal='pr_wrong', component='co_wrong', subcomponent='su_wrong') def check_good_and_bad_effective_caller_ids(cursor, cursor_execute_method): cursor_execute_method(cursor, good_effective_caller_id) with self.assertRaises(dbexceptions.DatabaseError): cursor_execute_method(cursor, bad_effective_caller_id) cursor.close() def cursor_execute_keyspace_ids_method(cursor, effective_caller_id): cursor.execute(effective_caller_id_test_query, {}, effective_caller_id=effective_caller_id) check_good_and_bad_effective_caller_ids( self._open_keyspace_ids_cursor(), cursor_execute_keyspace_ids_method) def cursor_execute_key_ranges_method(cursor, effective_caller_id): cursor.execute(effective_caller_id_test_query, {}, effective_caller_id=effective_caller_id) check_good_and_bad_effective_caller_ids( self._open_keyranges_cursor(), cursor_execute_key_ranges_method) def cursor_execute_entity_ids_method(cursor, effective_caller_id): cursor.execute_entity_ids( effective_caller_id_test_query, {}, entity_keyspace_id_map={1: self.KEYSPACE_ID_0X80}, entity_column_name='user_id', effective_caller_id=effective_caller_id) check_good_and_bad_effective_caller_ids( self.conn.cursor('keyspace', 'master'), cursor_execute_entity_ids_method) def cursor_execute_batch_keyspace_ids_method(cursor, effective_caller_id): cursor.execute(sql=effective_caller_id_test_query, bind_variables={}, keyspace='keyspace', keyspace_ids=[self.KEYSPACE_ID_0X80]) cursor.flush(effective_caller_id=effective_caller_id) check_good_and_bad_effective_caller_ids( self._open_batch_cursor(), cursor_execute_batch_keyspace_ids_method) def cursor_stream_execute_keyspace_ids_method(cursor, effective_caller_id): cursor.execute(sql=effective_caller_id_test_query, bind_variables={}, effective_caller_id=effective_caller_id) check_good_and_bad_effective_caller_ids( self._open_stream_keyspace_ids_cursor(), cursor_stream_execute_keyspace_ids_method) def cursor_stream_execute_keyranges_method(cursor, effective_caller_id): cursor.execute(sql=effective_caller_id_test_query, bind_variables={}, effective_caller_id=effective_caller_id) check_good_and_bad_effective_caller_ids( self._open_stream_keyranges_cursor(), cursor_stream_execute_keyranges_method)
# not passing any immediate caller id should fail as using # the unsecure user "unsecure grpc client" cursor.set_effective_caller_id(None) try: cursor.execute('select * from vt_insert_test', {}) self.fail('Execute went through') except dbexceptions.DatabaseError, e: s = str(e) self.assertIn('table acl error', s) self.assertIn('cannot run PASS_SELECT on table', s) self.assertIn('unsecure grpc client', s) # 'vtgate client 1' is authorized to access vt_insert_test cursor.set_effective_caller_id( vtgate_client.CallerID(principal='vtgate client 1')) cursor.execute('select * from vt_insert_test', {}) # 'vtgate client 2' is not authorized to access vt_insert_test cursor.set_effective_caller_id( vtgate_client.CallerID(principal='vtgate client 2')) try: cursor.execute('select * from vt_insert_test', {}) self.fail('Execute went through') except dbexceptions.DatabaseError, e: s = str(e) self.assertIn('table acl error', s) self.assertIn('cannot run PASS_SELECT on table', s) conn.close()