示例#1
0
async def test_vertex_collection_management(db, graph, bad_graph):
    # Test create valid "from" vertex collection
    fvcol_name = generate_col_name()
    assert not await graph.has_vertex_collection(fvcol_name)
    assert not await db.has_collection(fvcol_name)

    fvcol = await graph.create_vertex_collection(fvcol_name)
    assert await graph.has_vertex_collection(fvcol_name)
    assert await db.has_collection(fvcol_name)
    assert fvcol.name == fvcol_name
    assert fvcol.graph == graph.name
    assert fvcol_name in repr(fvcol)
    assert fvcol_name in await graph.vertex_collections()
    assert fvcol_name in await extract('name', await db.collections())

    # Test create duplicate vertex collection
    with assert_raises(VertexCollectionCreateError) as err:
        await graph.create_vertex_collection(fvcol_name)
    assert err.value.error_code == 1938
    assert fvcol_name in await graph.vertex_collections()
    assert fvcol_name in await extract('name', await db.collections())

    # Test create valid "to" vertex collection
    tvcol_name = generate_col_name()
    assert not await graph.has_vertex_collection(tvcol_name)
    assert not await db.has_collection(tvcol_name)

    tvcol = await graph.create_vertex_collection(tvcol_name)
    assert await graph.has_vertex_collection(tvcol_name)
    assert await db.has_collection(tvcol_name)
    assert tvcol_name == tvcol_name
    assert tvcol.graph == graph.name
    assert tvcol_name in repr(tvcol)
    assert tvcol_name in await graph.vertex_collections()
    assert tvcol_name in await extract('name', await db.collections())

    # Test list vertex collection via bad database
    with assert_raises(VertexCollectionListError) as err:
        await bad_graph.vertex_collections()
    assert err.value.error_code in {11, 1228}

    # Test delete missing vertex collection
    with assert_raises(VertexCollectionDeleteError) as err:
        await graph.delete_vertex_collection(generate_col_name())
    assert err.value.error_code in {1926, 1928}

    # Test delete "to" vertex collection with purge option
    assert await graph.delete_vertex_collection(tvcol_name, purge=True) is True
    assert tvcol_name not in await graph.vertex_collections()
    assert fvcol_name in await extract('name', await db.collections())
    assert tvcol_name not in await extract('name', await db.collections())
    assert not await graph.has_vertex_collection(tvcol_name)

    # Test delete "from" vertex collection without purge option
    assert await graph.delete_vertex_collection(fvcol_name, purge=False) is True
    assert fvcol_name not in await graph.vertex_collections()
    assert fvcol_name in await extract('name', await db.collections())
    assert not await graph.has_vertex_collection(fvcol_name)
示例#2
0
async def test_create_graph_with_edge_definition(db):
    new_graph_name = generate_graph_name()
    new_ecol_name = generate_col_name()
    fvcol_name = generate_col_name()
    tvcol_name = generate_col_name()
    ovcol_name = generate_col_name()

    edge_definition = {
        'edge_collection': new_ecol_name,
        'from_vertex_collections': [fvcol_name],
        'to_vertex_collections': [tvcol_name]
    }
    new_graph = await db.create_graph(
        new_graph_name,
        edge_definitions=[edge_definition],
        orphan_collections=[ovcol_name]
    )
    assert edge_definition in await new_graph.edge_definitions()
示例#3
0
async def db(sys_db, client):
    tst_db = await client.db(global_data.get('tst_db_name'),
                             global_data.get('username'),
                             global_data.get('password'))

    # Create a standard collection for testing.
    col_name = generate_col_name()
    tst_col = await tst_db.create_collection(col_name, edge=False)
    await tst_col.add_skiplist_index(['val'])
    await tst_col.add_fulltext_index(['text'])
    geo_index = await tst_col.add_geo_index(['loc'])

    # Create a legacy edge collection for testing.
    icol_name = generate_col_name()
    await tst_db.create_collection(icol_name, edge=True)

    # Create test vertex & edge collections and graph.
    graph_name = generate_graph_name()
    ecol_name = generate_col_name()
    fvcol_name = generate_col_name()
    tvcol_name = generate_col_name()
    tst_graph = await tst_db.create_graph(graph_name)
    await tst_graph.create_vertex_collection(fvcol_name)
    await tst_graph.create_vertex_collection(tvcol_name)
    await tst_graph.create_edge_definition(
        edge_collection=ecol_name,
        from_vertex_collections=[fvcol_name],
        to_vertex_collections=[tvcol_name])

    global_data.update({
        'geo_index': geo_index,
        'col_name': col_name,
        'icol_name': icol_name,
        'graph_name': graph_name,
        'ecol_name': ecol_name,
        'fvcol_name': fvcol_name,
        'tvcol_name': tvcol_name
    })

    return tst_db
示例#4
0
async def test_collection_management(db, bad_db, cluster):
    # Test create collection
    col_name = generate_col_name()
    assert await db.has_collection(col_name) is False

    col = await db.create_collection(name=col_name,
                                     sync=True,
                                     compact=False,
                                     journal_size=7774208,
                                     system=False,
                                     volatile=False,
                                     key_generator='traditional',
                                     user_keys=False,
                                     key_increment=9,
                                     key_offset=100,
                                     edge=True,
                                     shard_count=2,
                                     shard_fields=['test_attr'],
                                     index_bucket_count=10,
                                     replication_factor=1,
                                     shard_like='',
                                     sync_replication=False,
                                     enforce_replication_factor=False,
                                     sharding_strategy='community-compat',
                                     smart_join_attribute='test',
                                     write_concern=1)
    assert await db.has_collection(col_name) is True

    properties = await col.properties()
    assert 'key_options' in properties
    assert properties['name'] == col_name
    assert properties['sync'] is True
    assert properties['system'] is False

    # Test create duplicate collection
    with assert_raises(CollectionCreateError) as err:
        await db.create_collection(col_name)
    assert err.value.error_code == 1207

    # Test list collections
    assert all(entry['name'].startswith('test_collection')
               or entry['name'].startswith('_')
               for entry in await db.collections())

    # Test list collections with bad database
    with assert_raises(CollectionListError) as err:
        await bad_db.collections()
    assert err.value.error_code in {11, 1228}

    # Test get collection object
    test_col = db.collection(col.name)
    assert isinstance(test_col, StandardCollection)
    assert test_col.name == col.name

    test_col = db[col.name]
    assert isinstance(test_col, StandardCollection)
    assert test_col.name == col.name

    # Test delete collection
    assert await db.delete_collection(col_name, system=False) is True
    assert col_name not in await extract('name', await db.collections())

    # Test drop missing collection
    with assert_raises(CollectionDeleteError) as err:
        await db.delete_collection(col_name)
    assert err.value.error_code == 1203
    assert await db.delete_collection(col_name, ignore_missing=True) is False

    if not cluster:
        # Test rename collection
        new_name = generate_col_name()
        col = await db.create_collection(new_name)
        assert await col.rename(new_name) is True
        assert col.name == new_name
        assert repr(col) == '<StandardCollection {}>'.format(new_name)

        # Try again (the operation should be idempotent)
        assert await col.rename(new_name) is True
        assert col.name == new_name
        assert repr(col) == '<StandardCollection {}>'.format(new_name)

        # Test rename with bad collection
        with assert_raises(CollectionRenameError) as err:
            await bad_db.collection(new_name).rename(new_name)
        assert err.value.error_code in {11, 1228}
示例#5
0
async def test_vertex_edges(db, bad_db):
    graph_name = generate_graph_name()
    vcol_name = generate_col_name()
    ecol_name = generate_col_name()

    # Prepare test documents
    anna = {'_id': '{}/anna'.format(vcol_name)}
    dave = {'_id': '{}/dave'.format(vcol_name)}
    josh = {'_id': '{}/josh'.format(vcol_name)}
    mary = {'_id': '{}/mary'.format(vcol_name)}
    tony = {'_id': '{}/tony'.format(vcol_name)}

    # Create test graph, vertex and edge collections
    school = await db.create_graph(graph_name)

    vcol = await school.create_vertex_collection(vcol_name)
    ecol = await school.create_edge_definition(
        edge_collection=ecol_name,
        from_vertex_collections=[vcol_name],
        to_vertex_collections=[vcol_name]
    )
    # Insert test vertices into the graph
    await vcol.insert(anna)
    await vcol.insert(dave)
    await vcol.insert(josh)
    await vcol.insert(mary)
    await vcol.insert(tony)

    # Insert test edges into the graph
    await ecol.link(anna, dave)
    await ecol.link(josh, dave)
    await ecol.link(mary, dave)
    await ecol.link(tony, dave)
    await ecol.link(dave, anna)

    # Test edges with default direction (both)
    result = await ecol.edges(dave)
    assert 'stats' in result
    assert 'filtered' in result['stats']
    assert 'scanned_index' in result['stats']
    assert len(result['edges']) == 5

    result = await ecol.edges(anna)
    assert len(result['edges']) == 2

    # Test edges with direction set to "in"
    result = await ecol.edges(dave, direction='in')
    assert len(result['edges']) == 4

    result = await ecol.edges(anna, direction='in')
    assert len(result['edges']) == 1

    # Test edges with direction set to "out"
    result = await ecol.edges(dave, direction='out')
    assert len(result['edges']) == 1

    result = await ecol.edges(anna, direction='out')
    assert len(result['edges']) == 1

    bad_graph = bad_db.graph(graph_name)
    with assert_raises(EdgeListError) as err:
        await bad_graph.edge_collection(ecol_name).edges(dave)
    assert err.value.error_code in {11, 1228}
示例#6
0
async def test_graph_management(db, bad_db):
    # Test create graph
    graph_name = generate_graph_name()
    assert await db.has_graph(graph_name) is False

    graph = await db.create_graph(graph_name)
    assert await db.has_graph(graph_name) is True
    assert graph.name == graph_name
    assert graph.db_name == db.name

    # Test create duplicate graph
    with assert_raises(GraphCreateError) as err:
        await db.create_graph(graph_name)
    assert err.value.error_code == 1925

    # Test get graph
    result = db.graph(graph_name)
    assert result.name == graph.name
    assert result.db_name == graph.db_name

    # Test get graphs
    result = await db.graphs()
    for entry in result:
        assert 'revision' in entry
        assert 'edge_definitions' in entry
        assert 'orphan_collections' in entry
    assert graph_name in await extract('name', await db.graphs())

    # Test get graphs with bad database
    with assert_raises(GraphListError) as err:
        await bad_db.graphs()
    assert err.value.error_code in {11, 1228}

    # Test delete graph
    assert await db.delete_graph(graph_name) is True
    assert graph_name not in await extract('name', await db.graphs())

    # Test delete missing graph
    with assert_raises(GraphDeleteError) as err:
        await db.delete_graph(graph_name)
    assert err.value.error_code == 1924
    assert await db.delete_graph(graph_name, ignore_missing=True) is False

    # Create a graph with vertex and edge collections and delete the graph
    graph = await db.create_graph(graph_name)
    ecol_name = generate_col_name()
    fvcol_name = generate_col_name()
    tvcol_name = generate_col_name()

    await graph.create_vertex_collection(fvcol_name)
    await graph.create_vertex_collection(tvcol_name)
    await graph.create_edge_definition(
        edge_collection=ecol_name,
        from_vertex_collections=[fvcol_name],
        to_vertex_collections=[tvcol_name]
    )
    collections = await extract('name', await db.collections())
    assert fvcol_name in collections
    assert tvcol_name in collections
    assert ecol_name in collections

    await db.delete_graph(graph_name)
    collections = await extract('name', await db.collections())
    assert fvcol_name in collections
    assert tvcol_name in collections
    assert ecol_name in collections

    # Create a graph with vertex and edge collections and delete all
    graph = await db.create_graph(graph_name)
    await graph.create_edge_definition(
        edge_collection=ecol_name,
        from_vertex_collections=[fvcol_name],
        to_vertex_collections=[tvcol_name]
    )
    await db.delete_graph(graph_name, drop_collections=True)
    collections = await extract('name', await db.collections())
    assert fvcol_name not in collections
    assert tvcol_name not in collections
    assert ecol_name not in collections
示例#7
0
async def test_edge_management(ecol, bad_ecol, edocs, fvcol, fvdocs, tvcol, tvdocs):
    for vertex in fvdocs:
        await fvcol.insert(vertex)
    for vertex in tvdocs:
        await tvcol.insert(vertex)

    edge = edocs[0]
    key = edge['_key']

    # Test insert edge with no key
    no_key_edge = {'_from': edge['_from'], '_to': edge['_to']}
    result = await ecol.insert(no_key_edge)
    assert await ecol.has(result['_key'])
    assert await ecol.count() == 1
    await empty_collection(ecol)

    # Test insert edge with return_new set to True
    result = await ecol.insert(no_key_edge, return_new=True)
    assert 'new' in result
    assert await ecol.has(result['edge']['_key'])
    assert await ecol.count() == 1
    await empty_collection(ecol)

    # Test insert vertex with ID
    edge_id = ecol.name + '/' + 'foo'
    await ecol.insert({
        '_id': edge_id,
        '_from': edge['_from'],
        '_to': edge['_to']
    })
    assert await ecol.has('foo')
    assert await ecol.has(edge_id)
    assert await ecol.count() == 1
    await empty_collection(ecol)

    with assert_raises(DocumentParseError) as err:
        await ecol.insert({
            '_id': generate_col_name() + '/' + 'foo',
            '_from': edge['_from'],
            '_to': edge['_to']
        })
    assert 'bad collection name' in err.value.message

    # Test insert first valid edge
    result = await ecol.insert(edge)
    assert result['_key'] == key
    assert '_rev' in result
    assert await ecol.has(edge) and await ecol.has(key)
    assert await ecol.count() == 1
    assert (await ecol.get(key))['_from'] == edge['_from']
    assert (await ecol.get(key))['_to'] == edge['_to']

    # Test insert duplicate edge
    with assert_raises(DocumentInsertError) as err:
        assert await ecol.insert(edge)
    assert err.value.error_code in {1202, 1210, 1906}
    assert await ecol.count() == 1

    edge = edocs[1]
    key = edge['_key']

    # Test insert second valid edge with silent set to True
    assert await ecol.insert(edge, sync=True, silent=True) is True
    assert await ecol.has(edge) and await ecol.has(key)
    assert await ecol.count() == 2
    assert (await ecol.get(key))['_from'] == edge['_from']
    assert (await ecol.get(key))['_to'] == edge['_to']

    # Test insert third valid edge using link method
    from_vertex = await fvcol.get(fvdocs[2])
    to_vertex = await tvcol.get(tvdocs[2])
    result = await ecol.link(from_vertex, to_vertex, sync=False)
    assert await ecol.has(result['_key'])
    assert await ecol.count() == 3

    # Test insert fourth valid edge using link method
    from_vertex = await fvcol.get(fvdocs[2])
    to_vertex = await tvcol.get(tvdocs[0])
    assert await ecol.link(
        from_vertex['_id'],
        to_vertex['_id'],
        {'_id': ecol.name + '/foo'},
        sync=True,
        silent=True
    ) is True
    assert await ecol.has('foo')
    assert await ecol.count() == 4

    with assert_raises(DocumentParseError) as err:
        assert await ecol.link({}, {})
    assert err.value.message == 'field "_id" required'

    # Test get missing vertex
    bad_document_key = generate_doc_key()
    if ecol.context != 'transaction':
        assert await ecol.get(bad_document_key) is None

    # Test get existing edge by body with "_key" field
    result = await ecol.get({'_key': key})
    assert await clean_doc(result) == edge

    # Test get existing edge by body with "_id" field
    result = await ecol.get({'_id': ecol.name + '/' + key})
    assert await clean_doc(result) == edge

    # Test get existing edge by key
    result = await ecol.get(key)
    assert await clean_doc(result) == edge

    # Test get existing edge by ID
    result = await ecol.get(ecol.name + '/' + key)
    assert await clean_doc(result) == edge

    # Test get existing edge with bad revision
    old_rev = result['_rev']
    with assert_raises(DocumentRevisionError) as err:
        await ecol.get(key, rev=old_rev + '1')
    assert err.value.error_code in {1903, 1200}

    # Test get existing edge with bad database
    with assert_raises(DocumentGetError) as err:
        await bad_ecol.get(key)
    assert err.value.error_code in {11, 1228}

    # Test update edge with a single field change
    assert 'foo' not in await ecol.get(key)
    result = await ecol.update({'_key': key, 'foo': 100})
    assert result['_key'] == key
    assert (await ecol.get(key))['foo'] == 100

    # Test update edge with return_old and return_new set to True
    result = await ecol.update(
        {'_key': key, 'foo': 100},
        return_old=True,
        return_new=True
    )
    assert 'old' in result
    assert 'new' in result
    assert 'edge' in result
    old_rev = (await ecol.get(key))['_rev']

    # Test update edge with multiple field changes
    result = await ecol.update({'_key': key, 'foo': 200, 'bar': 300})
    assert result['_key'] == key
    assert result['_old_rev'] == old_rev
    assert (await ecol.get(key))['foo'] == 200
    assert (await ecol.get(key))['bar'] == 300
    old_rev = result['_rev']

    # Test update edge with correct revision
    result = await ecol.update({'_key': key, '_rev': old_rev, 'bar': 400})
    assert result['_key'] == key
    assert result['_old_rev'] == old_rev
    assert (await ecol.get(key))['foo'] == 200
    assert (await ecol.get(key))['bar'] == 400
    old_rev = result['_rev']

    if ecol.context != 'transaction':
        # Test update edge with bad revision
        new_rev = old_rev + '1'
        with assert_raises(DocumentRevisionError, DocumentUpdateError):
            await ecol.update({'_key': key, '_rev': new_rev, 'bar': 500})
        assert (await ecol.get(key))['foo'] == 200
        assert (await ecol.get(key))['bar'] == 400

    # Test update edge in missing edge collection
    with assert_raises(DocumentUpdateError) as err:
        await bad_ecol.update({'_key': key, 'bar': 500})
    assert err.value.error_code in {11, 1228}
    assert (await ecol.get(key))['foo'] == 200
    assert (await ecol.get(key))['bar'] == 400

    # Test update edge with sync option
    result = await ecol.update({'_key': key, 'bar': 500}, sync=True)
    assert result['_key'] == key
    assert result['_old_rev'] == old_rev
    assert (await ecol.get(key))['foo'] == 200
    assert (await ecol.get(key))['bar'] == 500
    old_rev = result['_rev']

    # Test update edge with silent option
    assert await ecol.update({'_key': key, 'bar': 600}, silent=True) is True
    assert (await ecol.get(key))['foo'] == 200
    assert (await ecol.get(key))['bar'] == 600
    assert (await ecol.get(key))['_rev'] != old_rev
    old_rev = (await ecol.get(key))['_rev']

    # Test update edge without keep_none option
    result = await ecol.update({'_key': key, 'bar': None}, keep_none=True)
    assert result['_key'] == key
    assert result['_old_rev'] == old_rev
    assert (await ecol.get(key))['foo'] == 200
    assert (await ecol.get(key))['bar'] is None
    old_rev = result['_rev']

    # Test update edge with keep_none option
    result = await ecol.update({'_key': key, 'foo': None}, keep_none=False)
    assert result['_key'] == key
    assert result['_old_rev'] == old_rev
    assert 'foo' not in await ecol.get(key)
    assert (await ecol.get(key))['bar'] is None

    # Test replace edge with a single field change
    edge['foo'] = 100
    result = await ecol.replace(edge)
    assert result['_key'] == key
    assert (await ecol.get(key))['foo'] == 100

    # Test replace edge with return_old and return_new set to True
    result = await ecol.replace(edge, return_old=True, return_new=True)
    assert 'old' in result
    assert 'new' in result
    assert 'edge' in result
    old_rev = (await ecol.get(key))['_rev']

    # Test replace edge with silent set to True
    edge['bar'] = 200
    assert await ecol.replace(edge, silent=True) is True
    assert (await ecol.get(key))['foo'] == 100
    assert (await ecol.get(key))['bar'] == 200
    assert (await ecol.get(key))['_rev'] != old_rev
    old_rev = (await ecol.get(key))['_rev']

    # Test replace edge with multiple field changes
    edge['foo'] = 200
    edge['bar'] = 300
    result = await ecol.replace(edge)
    assert result['_key'] == key
    assert result['_old_rev'] == old_rev
    assert (await ecol.get(key))['foo'] == 200
    assert (await ecol.get(key))['bar'] == 300
    old_rev = result['_rev']

    # Test replace edge with correct revision
    edge['foo'] = 300
    edge['bar'] = 400
    edge['_rev'] = old_rev
    result = await ecol.replace(edge)
    assert result['_key'] == key
    assert result['_old_rev'] == old_rev
    assert (await ecol.get(key))['foo'] == 300
    assert (await ecol.get(key))['bar'] == 400
    old_rev = result['_rev']

    edge['bar'] = 500
    if ecol.context != 'transaction':
        # Test replace edge with bad revision
        edge['_rev'] = old_rev + key
        with assert_raises(DocumentRevisionError, DocumentReplaceError) as err:
            await ecol.replace(edge)
        assert err.value.error_code in {1200, 1903}
        assert (await ecol.get(key))['foo'] == 300
        assert (await ecol.get(key))['bar'] == 400

    # Test replace edge with bad database
    with assert_raises(DocumentReplaceError) as err:
        await bad_ecol.replace(edge)
    assert err.value.error_code in {11, 1228}
    assert (await ecol.get(key))['foo'] == 300
    assert (await ecol.get(key))['bar'] == 400

    # Test replace edge with sync option
    result = await ecol.replace(edge, sync=True, check_rev=False)
    assert result['_key'] == key
    assert result['_old_rev'] == old_rev
    assert (await ecol.get(key))['foo'] == 300
    assert (await ecol.get(key))['bar'] == 500

    # Test delete edge with bad revision
    if ecol.context != 'transaction':
        old_rev = (await ecol.get(key))['_rev']
        edge['_rev'] = old_rev + '1'
        with assert_raises(DocumentRevisionError, DocumentDeleteError) as err:
            await ecol.delete(edge, check_rev=True)
        assert err.value.error_code in {1200, 1903}
        edge['_rev'] = old_rev
        assert await ecol.has(edge)

    # Test delete missing edge
    with assert_raises(DocumentDeleteError) as err:
        await ecol.delete(bad_document_key, ignore_missing=False)
    assert err.value.error_code == 1202
    if ecol.context != 'transaction':
        assert not await ecol.delete(bad_document_key, ignore_missing=True)

    # Test delete existing edge with sync set to True
    assert await ecol.delete(edge, sync=True, check_rev=False) is True
    if ecol.context != 'transaction':
        assert await ecol.get(edge) is None
    assert not await ecol.has(edge)

    # Test delete existing edge with return_old set to True
    await ecol.insert(edge)
    result = await ecol.delete(edge, return_old=True, check_rev=False)
    assert 'old' in result
    assert not await ecol.has(edge)
    await empty_collection(ecol)
示例#8
0
async def test_vertex_management(fvcol, bad_fvcol, fvdocs):
    # Test insert vertex with no key
    result = await fvcol.insert({})
    assert await fvcol.has(result['_key'])
    assert await fvcol.count() == 1
    await empty_collection(fvcol)

    # Test insert vertex with ID
    vertex_id = fvcol.name + '/' + 'foo'
    await fvcol.insert({'_id': vertex_id})
    assert await fvcol.has('foo')
    assert await fvcol.has(vertex_id)
    assert await fvcol.count() == 1
    await empty_collection(fvcol)

    # Test insert vertex with return_new set to True
    result = await fvcol.insert({'_id': vertex_id}, return_new=True)
    assert 'new' in result
    assert 'vertex' in result
    assert await fvcol.count() == 1
    await empty_collection(fvcol)

    with assert_raises(DocumentParseError) as err:
        await fvcol.insert({'_id': generate_col_name() + '/' + 'foo'})
    assert 'bad collection name' in err.value.message

    vertex = fvdocs[0]
    key = vertex['_key']

    # Test insert first valid vertex
    result = await fvcol.insert(vertex, sync=True)
    assert result['_key'] == key
    assert '_rev' in result
    assert await fvcol.has(vertex) and await fvcol.has(key)
    assert await fvcol.count() == 1
    assert (await fvcol.get(key))['val'] == vertex['val']

    # Test insert duplicate vertex
    with assert_raises(DocumentInsertError) as err:
        await fvcol.insert(vertex)
    assert err.value.error_code in {1202, 1210}
    assert await fvcol.count() == 1

    vertex = fvdocs[1]
    key = vertex['_key']

    # Test insert second valid vertex
    result = await fvcol.insert(vertex)
    assert result['_key'] == key
    assert '_rev' in result
    assert await fvcol.has(vertex) and await fvcol.has(key)
    assert await fvcol.count() == 2
    assert (await fvcol.get(key))['val'] == vertex['val']

    vertex = fvdocs[2]
    key = vertex['_key']

    # Test insert third valid vertex with silent set to True
    assert await fvcol.insert(vertex, silent=True) is True
    assert await fvcol.count() == 3
    assert (await fvcol.get(key))['val'] == vertex['val']

    # Test get missing vertex
    if fvcol.context != 'transaction':
        assert await fvcol.get(generate_doc_key()) is None

    # Test get existing edge by body with "_key" field
    result = await fvcol.get({'_key': key})
    assert await clean_doc(result) == vertex

    # Test get existing edge by body with "_id" field
    result = await fvcol.get({'_id': fvcol.name + '/' + key})
    assert await clean_doc(result) == vertex

    # Test get existing vertex by key
    result = await fvcol.get(key)
    assert await clean_doc(result) == vertex

    # Test get existing vertex by ID
    result = await fvcol.get(fvcol.name + '/' + key)
    assert await clean_doc(result) == vertex

    # Test get existing vertex with bad revision
    old_rev = result['_rev']
    with assert_raises(DocumentRevisionError) as err:
        await fvcol.get(key, rev=old_rev + '1', check_rev=True)
    assert err.value.error_code in {1903, 1200}

    # Test get existing vertex with bad database
    with assert_raises(DocumentGetError) as err:
        await bad_fvcol.get(key)
    assert err.value.error_code in {11, 1228}

    # Test update vertex with a single field change
    assert 'foo' not in await fvcol.get(key)
    result = await fvcol.update({'_key': key, 'foo': 100})
    assert result['_key'] == key
    assert (await fvcol.get(key))['foo'] == 100
    old_rev = (await fvcol.get(key))['_rev']

    # Test update vertex with return_new and return_old set to True
    result = await fvcol.update(
        {'_key': key, 'foo': 100},
        return_old=True,
        return_new=True
    )
    assert 'old' in result
    assert 'new' in result
    assert 'vertex' in result

    # Test update vertex with silent set to True
    assert 'bar' not in await fvcol.get(vertex)
    assert await fvcol.update({'_key': key, 'bar': 200}, silent=True) is True
    assert (await fvcol.get(vertex))['bar'] == 200
    assert (await fvcol.get(vertex))['_rev'] != old_rev
    old_rev = (await fvcol.get(key))['_rev']

    # Test update vertex with multiple field changes
    result = await fvcol.update({'_key': key, 'foo': 200, 'bar': 300})
    assert result['_key'] == key
    assert result['_old_rev'] == old_rev
    assert (await fvcol.get(key))['foo'] == 200
    assert (await fvcol.get(key))['bar'] == 300
    old_rev = result['_rev']

    # Test update vertex with correct revision
    result = await fvcol.update({'_key': key, '_rev': old_rev, 'bar': 400})
    assert result['_key'] == key
    assert result['_old_rev'] == old_rev
    assert (await fvcol.get(key))['foo'] == 200
    assert (await fvcol.get(key))['bar'] == 400
    old_rev = result['_rev']

    # Test update vertex with bad revision
    if fvcol.context != 'transaction':
        new_rev = old_rev + '1'
        with assert_raises(DocumentRevisionError) as err:
            await fvcol.update({'_key': key, '_rev': new_rev, 'bar': 500})
        assert err.value.error_code in {1200, 1903}
        assert (await fvcol.get(key))['foo'] == 200
        assert (await fvcol.get(key))['bar'] == 400

    # Test update vertex in missing vertex collection
    with assert_raises(DocumentUpdateError) as err:
        await bad_fvcol.update({'_key': key, 'bar': 500})
    assert err.value.error_code in {11, 1228}
    assert (await fvcol.get(key))['foo'] == 200
    assert (await fvcol.get(key))['bar'] == 400

    # Test update vertex with sync set to True
    result = await fvcol.update({'_key': key, 'bar': 500}, sync=True)
    assert result['_key'] == key
    assert result['_old_rev'] == old_rev
    assert (await fvcol.get(key))['foo'] == 200
    assert (await fvcol.get(key))['bar'] == 500
    old_rev = result['_rev']

    # Test update vertex with keep_none set to True
    result = await fvcol.update({'_key': key, 'bar': None}, keep_none=True)
    assert result['_key'] == key
    assert result['_old_rev'] == old_rev
    assert (await fvcol.get(key))['foo'] == 200
    assert (await fvcol.get(key))['bar'] is None
    old_rev = result['_rev']

    # Test update vertex with keep_none set to False
    result = await fvcol.update({'_key': key, 'foo': None}, keep_none=False)
    assert result['_key'] == key
    assert result['_old_rev'] == old_rev
    assert 'foo' not in (await fvcol.get(key))
    assert (await fvcol.get(key))['bar'] is None

    # Test replace vertex with a single field change
    result = await fvcol.replace({'_key': key, 'baz': 100})
    assert result['_key'] == key
    assert 'foo' not in await fvcol.get(key)
    assert 'bar' not in await fvcol.get(key)
    assert (await fvcol.get(key))['baz'] == 100
    old_rev = result['_rev']

    # Test replace vertex with return_new and return_old set to True
    result = await fvcol.replace(
        {'_key': key, 'baz': 100},
        return_old=True,
        return_new=True
    )
    assert 'old' in result
    assert 'new' in result
    assert 'vertex' in result

    # Test replace vertex with silent set to True
    assert await fvcol.replace({'_key': key, 'bar': 200}, silent=True) is True
    assert 'foo' not in await fvcol.get(key)
    assert 'baz' not in await fvcol.get(vertex)
    assert (await fvcol.get(vertex))['bar'] == 200
    assert await fvcol.count() == 3
    assert (await fvcol.get(vertex))['_rev'] != old_rev
    old_rev = (await fvcol.get(vertex))['_rev']

    # Test replace vertex with multiple field changes
    vertex = {'_key': key, 'foo': 200, 'bar': 300}
    result = await fvcol.replace(vertex)
    assert result['_key'] == key
    assert result['_old_rev'] == old_rev
    assert await clean_doc(await fvcol.get(key)) == vertex
    old_rev = result['_rev']

    # Test replace vertex with correct revision
    vertex = {'_key': key, '_rev': old_rev, 'bar': 500}
    result = await fvcol.replace(vertex)
    assert result['_key'] == key
    assert result['_old_rev'] == old_rev
    assert await clean_doc(await fvcol.get(key)) == await clean_doc(vertex)
    old_rev = result['_rev']

    # Test replace vertex with bad revision
    if fvcol.context != 'transaction':
        new_rev = old_rev + '10'
        vertex = {'_key': key, '_rev': new_rev, 'bar': 600}
        with assert_raises(DocumentRevisionError, DocumentReplaceError) as err:
            await fvcol.replace(vertex)
        assert err.value.error_code in {1200, 1903}
        assert (await fvcol.get(key))['bar'] == 500
        assert 'foo' not in await fvcol.get(key)

    # Test replace vertex with bad database
    with assert_raises(DocumentReplaceError) as err:
        await bad_fvcol.replace({'_key': key, 'bar': 600})
    assert err.value.error_code in {11, 1228}
    assert (await fvcol.get(key))['bar'] == 500
    assert 'foo' not in await fvcol.get(key)

    # Test replace vertex with sync set to True
    vertex = {'_key': key, 'bar': 400, 'foo': 200}
    result = await fvcol.replace(vertex, sync=True)
    assert result['_key'] == key
    assert result['_old_rev'] == old_rev
    assert (await fvcol.get(key))['foo'] == 200
    assert (await fvcol.get(key))['bar'] == 400

    # Test delete vertex with bad revision
    if fvcol.context != 'transaction':
        old_rev = (await fvcol.get(key))['_rev']
        vertex['_rev'] = old_rev + '1'
        with assert_raises(DocumentRevisionError, DocumentDeleteError) as err:
            await fvcol.delete(vertex, check_rev=True)
        assert err.value.error_code in {1200, 1903}
        vertex['_rev'] = old_rev
        assert await fvcol.has(vertex)

    # Test delete missing vertex
    bad_key = generate_doc_key()
    with assert_raises(DocumentDeleteError) as err:
        await fvcol.delete(bad_key, ignore_missing=False)
    assert err.value.error_code == 1202
    if fvcol.context != 'transaction':
        assert await fvcol.delete(bad_key, ignore_missing=True) is False

    # Test delete existing vertex with sync set to True
    assert await fvcol.delete(vertex, sync=True, check_rev=False) is True
    if fvcol.context != 'transaction':
        assert await fvcol.get(vertex) is None
    assert not await fvcol.has(vertex)
    assert await fvcol.count() == 2

    # Test delete existing vertex with return_old set to True
    vertex = fvdocs[1]
    result = await fvcol.delete(vertex, return_old=True)
    assert 'old' in result
    assert await fvcol.count() == 1
    await empty_collection(fvcol)
示例#9
0
async def test_edge_definition_management(db, graph, bad_graph):
    ecol_name = generate_col_name()
    assert not await graph.has_edge_definition(ecol_name)
    assert not await graph.has_edge_collection(ecol_name)
    assert not await db.has_collection(ecol_name)

    # Test create edge definition with existing vertex collections
    fvcol_name = generate_col_name()
    tvcol_name = generate_col_name()
    ecol_name = generate_col_name()
    ecol = await graph.create_edge_definition(
        edge_collection=ecol_name,
        from_vertex_collections=[fvcol_name],
        to_vertex_collections=[tvcol_name]
    )
    assert ecol.name == ecol_name
    assert ecol.graph == graph.name
    assert repr(ecol) == '<EdgeCollection {}>'.format(ecol.name)
    assert {
        'edge_collection': ecol_name,
        'from_vertex_collections': [fvcol_name],
        'to_vertex_collections': [tvcol_name]
    } in await graph.edge_definitions()
    assert ecol_name in await extract('name', await db.collections())

    vertex_collections = await graph.vertex_collections()
    assert fvcol_name in vertex_collections
    assert tvcol_name in vertex_collections

    # Test create duplicate edge definition
    with assert_raises(EdgeDefinitionCreateError) as err:
        await graph.create_edge_definition(
            edge_collection=ecol_name,
            from_vertex_collections=[fvcol_name],
            to_vertex_collections=[tvcol_name]
        )
    assert err.value.error_code == 1920

    # Test create edge definition with missing vertex collection
    bad_vcol_name = generate_col_name()
    ecol_name = generate_col_name()
    ecol = await graph.create_edge_definition(
        edge_collection=ecol_name,
        from_vertex_collections=[bad_vcol_name],
        to_vertex_collections=[bad_vcol_name]
    )
    assert await graph.has_edge_definition(ecol_name)
    assert await graph.has_edge_collection(ecol_name)
    assert ecol.name == ecol_name
    assert {
        'edge_collection': ecol_name,
        'from_vertex_collections': [bad_vcol_name],
        'to_vertex_collections': [bad_vcol_name]
    } in await graph.edge_definitions()
    assert bad_vcol_name in await graph.vertex_collections()
    assert bad_vcol_name in await extract('name', await db.collections())
    assert bad_vcol_name in await extract('name', await db.collections())

    # Test list edge definition with bad database
    with assert_raises(EdgeDefinitionListError) as err:
        await bad_graph.edge_definitions()
    assert err.value.error_code in {11, 1228}

    # Test replace edge definition (happy path)
    ecol = await graph.replace_edge_definition(
        edge_collection=ecol_name,
        from_vertex_collections=[tvcol_name],
        to_vertex_collections=[fvcol_name]
    )
    assert isinstance(ecol, EdgeCollection)
    assert ecol.name == ecol_name
    assert {
        'edge_collection': ecol_name,
        'from_vertex_collections': [tvcol_name],
        'to_vertex_collections': [fvcol_name]
    } in await graph.edge_definitions()

    # Test replace missing edge definition
    bad_ecol_name = generate_col_name()
    with assert_raises(EdgeDefinitionReplaceError):
        await graph.replace_edge_definition(
            edge_collection=bad_ecol_name,
            from_vertex_collections=[],
            to_vertex_collections=[fvcol_name]
        )

    # Test delete missing edge definition
    with assert_raises(EdgeDefinitionDeleteError) as err:
        await graph.delete_edge_definition(bad_ecol_name)
    assert err.value.error_code == 1930

    # Test delete existing edge definition with purge
    assert await graph.delete_edge_definition(ecol_name, purge=True) is True
    assert ecol_name not in \
        await extract('edge_collection', await graph.edge_definitions())
    assert not await graph.has_edge_definition(ecol_name)
    assert not await graph.has_edge_collection(ecol_name)
    assert ecol_name not in await extract('name', await db.collections())
示例#10
0
async def test_traverse(db):
    # Create test graph, vertex and edge collections
    school = await db.create_graph(generate_graph_name())
    profs = await school.create_vertex_collection(generate_col_name())
    classes = await school.create_vertex_collection(generate_col_name())
    teaches = await school.create_edge_definition(
        edge_collection=generate_col_name(),
        from_vertex_collections=[profs.name],
        to_vertex_collections=[classes.name]
    )
    # Insert test vertices into the graph
    await profs.insert({'_key': 'anna', 'name': 'Professor Anna'})
    await profs.insert({'_key': 'andy', 'name': 'Professor Andy'})
    await classes.insert({'_key': 'CSC101', 'name': 'Introduction to CS'})
    await classes.insert({'_key': 'MAT223', 'name': 'Linear Algebra'})
    await classes.insert({'_key': 'STA201', 'name': 'Statistics'})
    await classes.insert({'_key': 'MAT101', 'name': 'Calculus I'})
    await classes.insert({'_key': 'MAT102', 'name': 'Calculus II'})

    # Insert test edges into the graph
    await teaches.insert({
        '_from': '{}/anna'.format(profs.name),
        '_to': '{}/CSC101'.format(classes.name)
    })
    await teaches.insert({
        '_from': '{}/anna'.format(profs.name),
        '_to': '{}/STA201'.format(classes.name)
    })
    await teaches.insert({
        '_from': '{}/anna'.format(profs.name),
        '_to': '{}/MAT223'.format(classes.name)
    })
    await teaches.insert({
        '_from': '{}/andy'.format(profs.name),
        '_to': '{}/MAT101'.format(classes.name)
    })
    await teaches.insert({
        '_from': '{}/andy'.format(profs.name),
        '_to': '{}/MAT102'.format(classes.name)
    })
    await teaches.insert({
        '_from': '{}/andy'.format(profs.name),
        '_to': '{}/MAT223'.format(classes.name)
    })

    # Traverse the graph with default settings
    result = await school.traverse('{}/anna'.format(profs.name))
    visited = await extract('_key', result['vertices'])
    assert visited == ['CSC101', 'MAT223', 'STA201', 'anna']

    for path in result['paths']:
        for vertex in path['vertices']:
            assert set(vertex) == {'_id', '_key', '_rev', 'name'}
        for edge in path['edges']:
            assert set(edge) == {'_id', '_key', '_rev', '_to', '_from'}

    result = await school.traverse('{}/andy'.format(profs.name))
    visited = await extract('_key', result['vertices'])
    assert visited == ['MAT101', 'MAT102', 'MAT223', 'andy']

    # Traverse the graph with an invalid start vertex
    with assert_raises(GraphTraverseError):
        await school.traverse('invalid')

    with assert_raises(GraphTraverseError):
        bad_col_name = generate_col_name()
        await school.traverse('{}/hanna'.format(bad_col_name))

    with assert_raises(GraphTraverseError):
        await school.traverse('{}/anderson'.format(profs.name))

    # Travers the graph with max iteration of 0
    with assert_raises(GraphTraverseError):
        await school.traverse('{}/andy'.format(profs.name), max_iter=0)

    # Traverse the graph with max depth of 0
    result = await school.traverse('{}/andy'.format(profs.name), max_depth=0)
    assert await extract('_key', result['vertices']) == ['andy']

    result = await school.traverse('{}/anna'.format(profs.name), max_depth=0)
    assert await extract('_key', result['vertices']) == ['anna']

    # Traverse the graph with min depth of 2
    result = await school.traverse('{}/andy'.format(profs.name), min_depth=2)
    assert await extract('_key', result['vertices']) == []

    result = await school.traverse('{}/anna'.format(profs.name), min_depth=2)
    assert await extract('_key', result['vertices']) == []

    # Traverse the graph with DFS and BFS
    result = await school.traverse(
        {'_id': '{}/anna'.format(profs.name)},
        strategy='dfs',
        direction='any',
    )
    dfs_vertices = await extract('_key', result['vertices'])

    result = await school.traverse(
        {'_id': '{}/anna'.format(profs.name)},
        strategy='bfs',
        direction='any'
    )
    bfs_vertices = await extract('_key', result['vertices'])

    assert sorted(dfs_vertices) == sorted(bfs_vertices)

    # Traverse the graph with filter function
    result = await school.traverse(
        {'_id': '{}/andy'.format(profs.name)},
        filter_func='if (vertex._key == "MAT101") {return "exclude";} return;'
    )
    assert await extract('_key', result['vertices']) == ['MAT102', 'MAT223', 'andy']

    # Traverse the graph with global uniqueness (should be same as before)
    result = await school.traverse(
        {'_id': '{}/andy'.format(profs.name)},
        vertex_uniqueness='global',
        edge_uniqueness='global',
        filter_func='if (vertex._key == "MAT101") {return "exclude";} return;'
    )
    assert await extract('_key', result['vertices']) == ['MAT102', 'MAT223', 'andy']

    with assert_raises(DocumentParseError) as err:
        await school.traverse({})
    assert err.value.message == 'field "_id" required'
async def test_permission_management(client, sys_db, bad_db, cluster):
    if cluster:
        pytest.skip('Not tested in a cluster setup')

    username = generate_username()
    password = generate_string()
    db_name = generate_db_name()
    col_name_1 = generate_col_name()
    col_name_2 = generate_col_name()

    await sys_db.create_database(name=db_name,
                                 users=[{
                                     'username': username,
                                     'password': password,
                                     'active': True
                                 }])
    db = await client.db(db_name, username, password)
    assert isinstance(await sys_db.permissions(username), dict)

    # Test list permissions with bad database
    with assert_raises(PermissionListError) as err:
        await bad_db.permissions(username)
    assert err.value.error_code in {11, 1228}

    # Test get permission with bad database
    with assert_raises(PermissionGetError) as err:
        await bad_db.permission(username, db_name)
    assert err.value.error_code in {11, 1228}

    # The user should not have read and write permissions
    assert await sys_db.permission(username, db_name) == 'rw'
    assert await sys_db.permission(username, db_name, col_name_1) == 'rw'

    # Test update permission (database level) with bad database
    with assert_raises(PermissionUpdateError):
        await bad_db.update_permission(username, 'ro', db_name)
    assert await sys_db.permission(username, db_name) == 'rw'

    # Test update permission (database level) to read only and verify access
    assert await sys_db.update_permission(username, 'ro', db_name) is True
    assert await sys_db.permission(username, db_name) == 'ro'
    with assert_raises(CollectionCreateError) as err:
        await db.create_collection(col_name_2)
    assert err.value.http_code == 403
    assert col_name_1 not in await extract('name', await db.collections())
    assert col_name_2 not in await extract('name', await db.collections())

    # Test reset permission (database level) with bad database
    with assert_raises(PermissionResetError) as err:
        await bad_db.reset_permission(username, db_name)
    assert err.value.error_code in {11, 1228}
    assert await sys_db.permission(username, db_name) == 'ro'

    # Test reset permission (database level) and verify access
    assert await sys_db.reset_permission(username, db_name) is True
    assert await sys_db.permission(username, db_name) == 'none'
    with assert_raises(CollectionCreateError) as err:
        await db.create_collection(col_name_1)
    assert err.value.http_code == 401
    with assert_raises(CollectionListError) as err:
        await db.collections()
    assert err.value.http_code == 401

    # Test update permission (database level) and verify access
    assert await sys_db.update_permission(username, 'rw', db_name) is True
    assert await sys_db.permission(username, db_name, col_name_2) == 'rw'
    assert await db.create_collection(col_name_1) is not None
    assert await db.create_collection(col_name_2) is not None
    assert col_name_1 in await extract('name', await db.collections())
    assert col_name_2 in await extract('name', await db.collections())

    col_1 = await db.collection(col_name_1)
    col_2 = await db.collection(col_name_2)

    # Verify that user has read and write access to both collections
    assert isinstance(await col_1.properties(), dict)
    assert isinstance(await col_1.insert({}), dict)
    assert isinstance(await col_2.properties(), dict)
    assert isinstance(await col_2.insert({}), dict)

    # Test update permission (collection level) to read only and verify access
    assert await sys_db.update_permission(username, 'ro', db_name, col_name_1)
    assert await sys_db.permission(username, db_name, col_name_1) == 'ro'
    assert isinstance(await col_1.properties(), dict)
    with assert_raises(DocumentInsertError) as err:
        await col_1.insert({})
    assert err.value.http_code == 403
    assert isinstance(await col_2.properties(), dict)
    assert isinstance(await col_2.insert({}), dict)

    # Test update permission (collection level) to none and verify access
    assert await sys_db.update_permission(username, 'none', db_name,
                                          col_name_1)
    assert await sys_db.permission(username, db_name, col_name_1) == 'none'
    with assert_raises(CollectionPropertiesError) as err:
        await col_1.properties()
    assert err.value.http_code == 403
    with assert_raises(DocumentInsertError) as err:
        await col_1.insert({})
    assert err.value.http_code == 403
    assert isinstance(await col_2.properties(), dict)
    assert isinstance(await col_2.insert({}), dict)

    # Test reset permission (collection level)
    assert await sys_db.reset_permission(username, db_name, col_name_1) is True
    assert await sys_db.permission(username, db_name, col_name_1) == 'rw'
    assert isinstance(await col_1.properties(), dict)
    assert isinstance(await col_1.insert({}), dict)
    assert isinstance(await col_2.properties(), dict)
    assert isinstance(await col_2.insert({}), dict)