def test_create_table_no_range(self): self.storage_mocker.StubOutWithMock(storage, 'create_table') storage.create_table(IgnoreArg(), IgnoreArg(), IgnoreArg()).AndReturn( models.TableMeta( models.TableSchema( { 'hash': models.ATTRIBUTE_TYPE_NUMBER, 'indexed_field': models.ATTRIBUTE_TYPE_STRING }, ['hash'], {"index_name": models.IndexDefinition('indexed_field')}), models.TableMeta.TABLE_STATUS_ACTIVE)) self.storage_mocker.ReplayAll() Table.create("test", schema=[ fields.HashKey('hash', data_type=schema_types.NUMBER), ], throughput={ 'read': 20, 'write': 10, }, indexes=[ fields.KeysOnlyIndex( 'index_name', parts=[ fields.RangeKey('indexed_field', data_type=schema_types.STRING) ]) ], connection=self.DYNAMODB_CON) self.storage_mocker.VerifyAll()
def test_describe_table(self): self.storage_mocker.StubOutWithMock(storage, 'describe_table') storage.describe_table(IgnoreArg(), 'test_table').AndReturn( models.TableMeta( models.TableSchema( { 'city1': models.ATTRIBUTE_TYPE_STRING, 'id': models.ATTRIBUTE_TYPE_STRING, 'name': models.ATTRIBUTE_TYPE_STRING }, ['id', 'name'], {'index_name': models.IndexDefinition('city1')}), models.TableMeta.TABLE_STATUS_ACTIVE)) self.storage_mocker.ReplayAll() table = Table('test_table', connection=self.DYNAMODB_CON) table_description = table.describe() self.storage_mocker.VerifyAll() self.assertEquals('test_table', table_description['Table']['TableName']) self.assertItemsEqual([{ "AttributeName": "city1", "AttributeType": "S" }, { "AttributeName": "id", "AttributeType": "S" }, { "AttributeName": "name", "AttributeType": "S" }], table_description['Table']['AttributeDefinitions'])
def parse_local_secondary_index(cls, local_secondary_index_json): key_attrs_for_projection = cls.parse_key_schema( local_secondary_index_json.get(Props.KEY_SCHEMA, {}) ) hash_key = key_attrs_for_projection[0] try: range_key = key_attrs_for_projection[1] except IndexError: raise exception.AWSValidationException( "Range key in index wasn't specified" ) index_name = local_secondary_index_json[Props.INDEX_NAME] projection_type = local_secondary_index_json.get( Props.PROJECTION_TYPE, Values.PROJECTION_TYPE_INCLUDE ) if projection_type == Values.PROJECTION_TYPE_ALL: projected_attrs = None elif projection_type == Values.PROJECTION_TYPE_KEYS_ONLY: projected_attrs = frozenset() else: projected_attrs = local_secondary_index_json.get( Props.NON_KEY_ATTRIBUTES, None ) return index_name, models.IndexDefinition(hash_key, range_key, projected_attrs)
def test_delete_table(self): self.storage_mocker.StubOutWithMock(storage, 'delete_table') self.storage_mocker.StubOutWithMock(storage, 'describe_table') storage.delete_table(mox.IgnoreArg(), 'test_table') storage.describe_table(mox.IgnoreArg(), 'test_table').AndReturn( models.TableMeta( '00000000-0000-0000-0000-000000000000', models.TableSchema( { 'city1': models.AttributeType('S'), 'id': models.AttributeType('S'), 'name': models.AttributeType('S') }, ['id', 'name'], {'index_name': models.IndexDefinition('id', 'city1')} ), models.TableMeta.TABLE_STATUS_ACTIVE, None ) ) self.storage_mocker.ReplayAll() table = ddb_table.Table( 'test_table', connection=self.DYNAMODB_CON ) self.assertTrue(table.delete()) self.storage_mocker.VerifyAll()
def test_create_table(self): self.storage_mocker.StubOutWithMock(storage, 'create_table') storage.create_table( mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg() ).AndReturn( models.TableMeta( '00000000-0000-0000-0000-000000000000', models.TableSchema( { 'hash': models.AttributeType('N'), 'range': models.AttributeType('S'), 'indexed_field': models.AttributeType('S') }, ['hash', 'range'], { "index_name": models.IndexDefinition('hash', 'indexed_field') } ), models.TableMeta.TABLE_STATUS_ACTIVE, None ) ) self.storage_mocker.ReplayAll() ddb_table.Table.create( "test", schema=[ fields.HashKey('hash', data_type=schema_types.NUMBER), fields.RangeKey('range', data_type=schema_types.STRING) ], throughput={ 'read': 20, 'write': 10, }, indexes=[ fields.KeysOnlyIndex( 'index_name', parts=[ fields.HashKey('hash', data_type=schema_types.NUMBER), fields.RangeKey('indexed_field', data_type=schema_types.STRING) ] ) ], connection=self.DYNAMODB_CON ) self.storage_mocker.VerifyAll()
def parse_local_secondary_index(cls, local_secondary_index_json): key_attrs_json = local_secondary_index_json.pop(Props.KEY_SCHEMA, None) validation.validate_list(key_attrs_json, Props.KEY_SCHEMA) key_attrs_for_projection = cls.parse_key_schema(key_attrs_json) hash_key = key_attrs_for_projection[0] try: range_key = key_attrs_for_projection[1] except IndexError: raise exception.ValidationError( _("Range key in index wasn't specified")) index_name = local_secondary_index_json.pop(Props.INDEX_NAME, None) validation.validate_index_name(index_name) projection_json = local_secondary_index_json.pop( Props.PROJECTION, None) validation.validate_object(projection_json, Props.PROJECTION) validation.validate_unexpected_props(local_secondary_index_json, "local_secondary_index") projection_type = projection_json.pop(Props.PROJECTION_TYPE, Values.PROJECTION_TYPE_INCLUDE) if projection_type == Values.PROJECTION_TYPE_ALL: projected_attrs = None elif projection_type == Values.PROJECTION_TYPE_KEYS_ONLY: projected_attrs = tuple() elif projection_type == Values.PROJECTION_TYPE_INCLUDE: projected_attrs = projection_json.pop(Props.NON_KEY_ATTRIBUTES, None) else: raise exception.ValidationError( _("Only '%(pt_all)', '%(pt_ko)' of '%(pt_incl)' projection " "types are allowed, but '%(projection_type)s' is found"), pt_all=Values.PROJECTION_TYPE_ALL, pt_ko=Values.PROJECTION_TYPE_KEYS_ONLY, pt_incl=Values.PROJECTION_TYPE_INCLUDE, projection_type=projection_type) validation.validate_unexpected_props(projection_json, Props.PROJECTION) return index_name, models.IndexDefinition(hash_key, range_key, projected_attrs)
def test_delete_table(self): self.storage_mocker.StubOutWithMock(storage, 'delete_table') self.storage_mocker.StubOutWithMock(storage, 'describe_table') storage.delete_table(IgnoreArg(), 'test_table') storage.describe_table(IgnoreArg(), 'test_table').AndReturn( models.TableMeta( models.TableSchema( { 'city1': models.ATTRIBUTE_TYPE_STRING, 'id': models.ATTRIBUTE_TYPE_STRING, 'name': models.ATTRIBUTE_TYPE_STRING }, ['id', 'name'], {'index_name': models.IndexDefinition('city1')}), models.TableMeta.TABLE_STATUS_ACTIVE)) self.storage_mocker.ReplayAll() table = Table('test_table', connection=self.DYNAMODB_CON) self.assertTrue(table.delete()) self.storage_mocker.VerifyAll()
def test_describe_table(self, mock_describe_table): attr_map = { 'ForumName': models.AttributeType('S'), 'Subject': models.AttributeType('S'), 'LastPostDateTime': models.AttributeType('S') } key_attrs = ['ForumName', 'Subject'] index_map = { 'LastPostIndex': models.IndexDefinition('ForumName', 'LastPostDateTime') } table_meta = models.TableMeta( '00000000-0000-0000-0000-000000000000', models.TableSchema(attr_map, key_attrs, index_map), models.TableMeta.TABLE_STATUS_ACTIVE, 123) mock_describe_table.return_value = table_meta headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' } conn = httplib.HTTPConnection('localhost:8080') url = '/v1/data/default_tenant/tables/Thread' table_url = ('http://localhost:8080/v1/data/default_tenant' '/tables/Thread') expected_response = { 'table': { 'attribute_definitions': [{ 'attribute_name': 'Subject', 'attribute_type': 'S' }, { 'attribute_name': 'LastPostDateTime', 'attribute_type': 'S' }, { 'attribute_name': 'ForumName', 'attribute_type': 'S' }], 'creation_date_time': 123, 'item_count': 0, 'key_schema': [{ 'attribute_name': 'ForumName', 'key_type': 'HASH' }, { 'attribute_name': 'Subject', 'key_type': 'RANGE' }], 'local_secondary_indexes': [{ 'index_name': 'LastPostIndex', 'index_size_bytes': 0, 'item_count': 0, 'key_schema': [{ 'attribute_name': 'ForumName', 'key_type': 'HASH' }, { 'attribute_name': 'LastPostDateTime', 'key_type': 'RANGE' }], 'projection': { 'projection_type': 'ALL' } }], 'table_id': '00000000-0000-0000-0000-000000000000', 'table_name': 'Thread', 'table_size_bytes': 0, 'table_status': 'ACTIVE', 'links': [{ 'href': table_url, 'rel': 'self' }, { 'href': table_url, 'rel': 'bookmark' }] } } conn.request("GET", url, headers=headers) response = conn.getresponse() self.assertTrue(mock_describe_table.called) json_response = response.read() response_payload = json.loads(json_response) self.assertEqual(expected_response, response_payload)
def test_create_table(self, mock_create_table): mock_create_table.return_value = models.TableMeta( '00000000-0000-0000-0000-000000000000', models.TableSchema(attribute_type_map={ "ForumName": models.AttributeType('S'), "Subject": models.AttributeType('S'), "LastPostDateTime": models.AttributeType('S') }, key_attributes=["ForumName", "Subject"], index_def_map={ "LastPostIndex": models.IndexDefinition( "ForumName", "LastPostDateTime") }), models.TableMeta.TABLE_STATUS_ACTIVE, 123) conn = httplib.HTTPConnection('localhost:8080') body = """ { "attribute_definitions": [ { "attribute_name": "ForumName", "attribute_type": "S" }, { "attribute_name": "Subject", "attribute_type": "S" }, { "attribute_name": "LastPostDateTime", "attribute_type": "S" } ], "table_name": "Thread", "key_schema": [ { "attribute_name": "ForumName", "key_type": "HASH" }, { "attribute_name": "Subject", "key_type": "RANGE" } ], "local_secondary_indexes": [ { "index_name": "LastPostIndex", "key_schema": [ { "attribute_name": "ForumName", "key_type": "HASH" }, { "attribute_name": "LastPostDateTime", "key_type": "RANGE" } ], "projection": { "projection_type": "KEYS_ONLY" } } ] } """ expected_response = { 'table_description': { 'attribute_definitions': [{ 'attribute_name': 'Subject', 'attribute_type': 'S' }, { 'attribute_name': 'LastPostDateTime', 'attribute_type': 'S' }, { 'attribute_name': 'ForumName', 'attribute_type': 'S' }], 'creation_date_time': 123, 'item_count': 0, 'key_schema': [{ 'attribute_name': 'ForumName', 'key_type': 'HASH' }, { 'attribute_name': 'Subject', 'key_type': 'RANGE' }], 'local_secondary_indexes': [{ 'index_name': 'LastPostIndex', 'index_size_bytes': 0, 'item_count': 0, 'key_schema': [{ 'attribute_name': 'ForumName', 'key_type': 'HASH' }, { 'attribute_name': 'LastPostDateTime', 'key_type': 'RANGE' }], 'projection': { 'projection_type': 'ALL' } }], 'table_id': '00000000-0000-0000-0000-000000000000', 'table_name': 'Thread', 'table_size_bytes': 0, 'table_status': 'ACTIVE', 'links': [{ 'href': self.table_url, 'rel': 'self' }, { 'href': self.table_url, 'rel': 'bookmark' }] } } conn.request("POST", self.url, headers=self.headers, body=body) response = conn.getresponse() self.assertTrue(mock_create_table.called) json_response = response.read() response_payload = json.loads(json_response) self.assertEqual(expected_response, response_payload)
def test_create_table_duplicate(self): self.storage_mocker.StubOutWithMock(storage, 'create_table') storage.create_table(IgnoreArg(), IgnoreArg(), IgnoreArg()).AndReturn( models.TableMeta( models.TableSchema( { 'hash': models.ATTRIBUTE_TYPE_NUMBER, 'range': models.ATTRIBUTE_TYPE_STRING, 'indexed_field': models.ATTRIBUTE_TYPE_STRING }, ['hash', 'range'], {"index_name": models.IndexDefinition('indexed_field')}), models.TableMeta.TABLE_STATUS_ACTIVE)) storage.create_table(IgnoreArg(), IgnoreArg(), IgnoreArg()).AndRaise(TableAlreadyExistsException) self.storage_mocker.ReplayAll() Table.create("test", schema=[ fields.HashKey('hash', data_type=schema_types.NUMBER), fields.RangeKey('range', data_type=schema_types.STRING) ], throughput={ 'read': 20, 'write': 10, }, indexes=[ fields.KeysOnlyIndex( 'index_name', parts=[ fields.RangeKey('indexed_field', data_type=schema_types.STRING) ]) ], connection=self.DYNAMODB_CON) try: Table.create("test", schema=[ fields.HashKey('hash', data_type=schema_types.NUMBER), fields.RangeKey('range', data_type=schema_types.STRING) ], throughput={ 'read': 20, 'write': 10, }, indexes=[ fields.KeysOnlyIndex( 'index_name', parts=[ fields.RangeKey( 'indexed_field', data_type=schema_types.STRING) ]) ], connection=self.DYNAMODB_CON) self.fail() except JSONResponseError as e: self.assertEqual('ResourceInUseException', e.error_code) self.storage_mocker.VerifyAll() except Exception as e: self.fail()
def test_create_table_duplicate(self): self.storage_mocker.StubOutWithMock(storage, 'create_table') storage.create_table( mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg() ).AndReturn( models.TableMeta( '00000000-0000-0000-0000-000000000000', models.TableSchema( { 'hash': models.AttributeType('N'), 'range': models.AttributeType('S'), 'indexed_field': models.AttributeType('S') }, ['hash', 'range'], { "index_name": models.IndexDefinition('hash', 'indexed_field') } ), models.TableMeta.TABLE_STATUS_ACTIVE, None ) ) storage.create_table( mox.IgnoreArg(), mox.IgnoreArg(), mox.IgnoreArg() ).AndRaise(exception.TableAlreadyExistsException) self.storage_mocker.ReplayAll() ddb_table.Table.create( "test", schema=[ fields.HashKey('hash', data_type=schema_types.NUMBER), fields.RangeKey('range', data_type=schema_types.STRING) ], throughput={ 'read': 20, 'write': 10, }, indexes=[ fields.KeysOnlyIndex( 'index_name', parts=[ fields.HashKey('hash', data_type=schema_types.NUMBER), fields.RangeKey('indexed_field', data_type=schema_types.STRING) ] ) ], connection=self.DYNAMODB_CON ) try: ddb_table.Table.create( "test", schema=[ fields.HashKey('hash', data_type=schema_types.NUMBER), fields.RangeKey('range', data_type=schema_types.STRING) ], throughput={ 'read': 20, 'write': 10, }, indexes=[ fields.KeysOnlyIndex( 'index_name', parts=[ fields.HashKey('hash', data_type=schema_types.NUMBER), fields.RangeKey('indexed_field', data_type=schema_types.STRING) ] ) ], connection=self.DYNAMODB_CON ) self.fail() except boto_exc.JSONResponseError as e: self.assertEqual('ResourceInUseException', e.error_code) self.assertEqual('Table already exists: test', e.body['message']) self.storage_mocker.VerifyAll() except Exception as e: self.fail()