Skip to content

Commit 0e72920

Browse files
committed
Test improvements
1 parent ddeabbf commit 0e72920

File tree

8 files changed

+355
-70
lines changed

8 files changed

+355
-70
lines changed

arangoasync/collection.py

+4
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ async def insert(
265265
document operations. Only applicable if **overwrite** is set to true
266266
or **overwriteMode** is set to "update" or "replace".
267267
268+
Returns:
269+
bool | dict: Document metadata (e.g. document id, key, revision) or `True`
270+
if **silent** is set to `True`.
271+
268272
References:
269273
- `create-a-document <https://docs.arangodb.com/stable/develop/http-api/documents/#create-a-document>`__
270274
""" # noqa: E501

arangoasync/database.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ async def create_collection(
391391
This will be used only for document operations.
392392
doc_deserializer (Deserializer): Custom document deserializer.
393393
This will be used only for document operations.
394-
col_type (CollectionType | None): Collection type.
394+
col_type (CollectionType | int | str | None): Collection type.
395395
write_concern (int | None): Determines how many copies of each shard are
396396
required to be in sync on the different DB-Servers.
397397
wait_for_sync (bool | None): If `True`, the data is synchronised to disk
@@ -449,6 +449,12 @@ async def create_collection(
449449
""" # noqa: E501
450450
data: Json = {"name": name}
451451
if col_type is not None:
452+
if isinstance(col_type, int):
453+
col_type = CollectionType.from_int(col_type)
454+
elif isinstance(col_type, str):
455+
col_type = CollectionType.from_str(col_type)
456+
elif not isinstance(col_type, CollectionType):
457+
raise ValueError("Invalid collection type")
452458
data["type"] = col_type.value
453459
if write_concern is not None:
454460
data["writeConcern"] = write_concern
@@ -644,7 +650,7 @@ async def create_user(
644650
"""Create a new user.
645651
646652
Args:
647-
user (UserInfo): User information.
653+
user (UserInfo | dict): User information.
648654
649655
Returns:
650656
UserInfo: New user details.
@@ -657,10 +663,13 @@ async def create_user(
657663
.. code-block:: python
658664
659665
await db.create_user(UserInfo(user="john", password="secret"))
666+
await db.create_user({user="john", password="secret"})
660667
661668
References:
662669
- `create-a-user <https://docs.arangodb.com/stable/develop/http-api/users/#create-a-user>`__
663670
""" # noqa: E501
671+
if isinstance(user, dict):
672+
user = UserInfo(**user)
664673
if not user.user:
665674
raise ValueError("Username is required.")
666675

arangoasync/typings.py

+18
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,24 @@ def from_int(value: int) -> "CollectionType":
6262
else:
6363
raise ValueError(f"Invalid collection type value: {value}")
6464

65+
@staticmethod
66+
def from_str(value: str) -> "CollectionType":
67+
"""Return a collection type from its string value.
68+
69+
Args:
70+
value (str): Collection type string value.
71+
72+
Returns:
73+
CollectionType: Collection type.
74+
"""
75+
value = value.lower()
76+
if value == "document":
77+
return CollectionType.DOCUMENT
78+
elif value == "edge":
79+
return CollectionType.EDGE
80+
else:
81+
raise ValueError(f"Invalid collection type value: {value}")
82+
6583
def __str__(self) -> str:
6684
return self.name.lower()
6785

tests/conftest.py

+26-6
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def basic_auth_root(root, password):
8585

8686

8787
@pytest.fixture
88-
def clusetr():
88+
def cluster():
8989
return global_data.cluster
9090

9191

@@ -109,6 +109,18 @@ def sys_db_name():
109109
return global_data.sys_db_name
110110

111111

112+
@pytest.fixture
113+
def docs():
114+
return [
115+
{"_key": "1", "val": 1, "text": "foo", "loc": [1, 1]},
116+
{"_key": "2", "val": 2, "text": "foo", "loc": [2, 2]},
117+
{"_key": "3", "val": 3, "text": "foo", "loc": [3, 3]},
118+
{"_key": "4", "val": 4, "text": "bar", "loc": [4, 4]},
119+
{"_key": "5", "val": 5, "text": "bar", "loc": [5, 5]},
120+
{"_key": "6", "val": 6, "text": "bar", "loc": [5, 5]},
121+
]
122+
123+
112124
@pytest.fixture(scope="session")
113125
def event_loop():
114126
loop = asyncio.new_event_loop()
@@ -146,14 +158,22 @@ async def sys_db(arango_client, sys_db_name, basic_auth_root):
146158

147159

148160
@pytest_asyncio.fixture
149-
async def test_db(arango_client, sys_db, username, password):
161+
async def db(arango_client, sys_db, username, password, cluster):
150162
tst_db_name = generate_db_name()
151163
tst_user = UserInfo(
152164
user=username,
153165
password=password,
154166
active=True,
155167
)
156-
await sys_db.create_database(tst_db_name, users=[tst_user])
168+
tst_db_kwargs = dict(name=tst_db_name, users=[tst_user])
169+
if cluster:
170+
tst_db_kwargs.update(
171+
dict(
172+
replication_factor=3,
173+
write_concern=2,
174+
)
175+
)
176+
await sys_db.create_database(**tst_db_kwargs)
157177
yield await arango_client.db(
158178
tst_db_name,
159179
auth_method="basic",
@@ -174,10 +194,10 @@ async def bad_db(arango_client):
174194

175195

176196
@pytest_asyncio.fixture
177-
async def test_doc_col(test_db):
197+
async def doc_col(db):
178198
col_name = generate_col_name()
179-
yield await test_db.create_collection(col_name)
180-
await test_db.delete_collection(col_name)
199+
yield await db.create_collection(col_name)
200+
await db.delete_collection(col_name)
181201

182202

183203
@pytest_asyncio.fixture(scope="session", autouse=True)

tests/test_database.py

+126-25
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
import pytest
22

33
from arangoasync.collection import StandardCollection
4-
from tests.helpers import generate_col_name, generate_db_name
4+
from arangoasync.exceptions import (
5+
CollectionCreateError,
6+
CollectionDeleteError,
7+
CollectionListError,
8+
DatabaseCreateError,
9+
DatabaseDeleteError,
10+
DatabaseListError,
11+
)
12+
from arangoasync.typings import CollectionType, KeyOptions, UserInfo
13+
from tests.helpers import generate_col_name, generate_db_name, generate_username
514

615

716
@pytest.mark.asyncio
@@ -11,29 +20,56 @@ async def test_database_misc_methods(sys_db):
1120

1221

1322
@pytest.mark.asyncio
14-
async def test_create_drop_database(arango_client, sys_db, basic_auth_root):
15-
# TODO also handle exceptions
16-
# TODO use more options (cluster must be enabled for that)
17-
23+
async def test_create_drop_database(
24+
arango_client,
25+
sys_db,
26+
db,
27+
basic_auth_root,
28+
password,
29+
cluster,
30+
):
1831
# Create a new database
1932
db_name = generate_db_name()
20-
assert await sys_db.create_database(db_name) is True
21-
new_db = await arango_client.db(
33+
db_kwargs = dict(
34+
name=db_name,
35+
users=[
36+
dict(username=generate_username(), password=password, active=True),
37+
UserInfo(user=generate_username(), password=password, active=True),
38+
],
39+
)
40+
if cluster:
41+
db_kwargs["replication_factor"] = 3
42+
db_kwargs["write_concern"] = 2
43+
db_kwargs["sharding"] = "flexible"
44+
45+
assert await sys_db.create_database(**db_kwargs) is True
46+
await arango_client.db(
2247
db_name, auth_method="basic", auth=basic_auth_root, verify=True
2348
)
2449
assert await sys_db.has_database(db_name) is True
2550

51+
# Try to create a database without permissions
52+
with pytest.raises(DatabaseCreateError):
53+
await db.create_database(generate_db_name())
54+
55+
# Try to create a database that already exists
56+
with pytest.raises(DatabaseCreateError):
57+
await sys_db.create_database(db_name)
58+
2659
# List available databases
2760
dbs = await sys_db.databases()
2861
assert db_name in dbs
2962
assert "_system" in dbs
3063

31-
# TODO move this to a separate test for documents
32-
col_name = generate_col_name()
33-
col = await new_db.create_collection(col_name)
34-
await col.insert({"_key": "1", "a": 1})
35-
doc = await col.get("1")
36-
assert doc["_key"] == "1"
64+
# Cannot list databases without permission
65+
with pytest.raises(DatabaseListError):
66+
await db.databases()
67+
with pytest.raises(DatabaseListError):
68+
await db.has_database(db_name)
69+
70+
# Databases can only be dropped from the system database
71+
with pytest.raises(DatabaseDeleteError):
72+
await db.delete_database(db_name)
3773

3874
# Drop the newly created database
3975
assert await sys_db.delete_database(db_name) is True
@@ -43,22 +79,87 @@ async def test_create_drop_database(arango_client, sys_db, basic_auth_root):
4379

4480

4581
@pytest.mark.asyncio
46-
async def test_create_drop_collection(test_db):
47-
# TODO also handle exceptions
48-
82+
async def test_create_drop_collection(db, bad_db, cluster):
4983
# Create a new collection
5084
col_name = generate_col_name()
51-
col = await test_db.create_collection(col_name)
85+
col = await db.create_collection(col_name)
5286
assert isinstance(col, StandardCollection)
53-
assert await test_db.has_collection(col_name)
54-
cols = await test_db.collections()
87+
assert await db.has_collection(col_name)
88+
cols = await db.collections()
5589
assert any(c.name == col_name for c in cols)
5690

91+
# Try to create a collection that already exists
92+
with pytest.raises(CollectionCreateError):
93+
await db.create_collection(col_name)
94+
95+
# Try collection methods from a non-existent db
96+
with pytest.raises(CollectionCreateError):
97+
await bad_db.create_collection(generate_col_name())
98+
with pytest.raises(CollectionListError):
99+
await bad_db.collections()
100+
with pytest.raises(CollectionListError):
101+
await bad_db.has_collection(col_name)
102+
103+
# Try to create a collection with invalid args
104+
with pytest.raises(ValueError):
105+
await db.create_collection(generate_col_name(), col_type="invalid")
106+
with pytest.raises(ValueError):
107+
await db.create_collection(generate_col_name(), col_type=db)
108+
with pytest.raises(ValueError):
109+
await db.create_collection(generate_col_name(), key_options={})
110+
57111
# Drop the newly created collection
58-
assert await test_db.delete_collection(col_name) is True
59-
assert not await test_db.has_collection(col_name)
112+
assert await db.delete_collection(col_name) is True
113+
assert not await db.has_collection(col_name)
60114
non_existent_col = generate_col_name()
61-
assert await test_db.has_collection(non_existent_col) is False
62-
assert (
63-
await test_db.delete_collection(non_existent_col, ignore_missing=True) is False
64-
)
115+
assert await db.has_collection(non_existent_col) is False
116+
assert await db.delete_collection(non_existent_col, ignore_missing=True) is False
117+
118+
# Do not ignore missing collection
119+
with pytest.raises(CollectionDeleteError):
120+
await db.delete_collection(non_existent_col)
121+
122+
# Multiple arguments in a cluster setup
123+
if cluster:
124+
schema = {
125+
"rule": {
126+
"type": "object",
127+
"properties": {
128+
"test_attr:": {"type": "string"},
129+
},
130+
"required": ["test_attr"],
131+
},
132+
"level": "moderate",
133+
"message": "Schema Validation Failed.",
134+
"type": "json",
135+
}
136+
137+
computed_values = [
138+
{
139+
"name": "foo",
140+
"expression": "RETURN 1",
141+
"computeOn": ["insert", "update", "replace"],
142+
"overwrite": True,
143+
"failOnWarning": False,
144+
"keepNull": True,
145+
}
146+
]
147+
148+
col = await db.create_collection(
149+
col_name,
150+
col_type=CollectionType.DOCUMENT,
151+
write_concern=2,
152+
wait_for_sync=True,
153+
number_of_shards=1,
154+
is_system=False,
155+
computed_values=computed_values,
156+
schema=schema,
157+
key_options=KeyOptions(
158+
allow_user_keys=True,
159+
generator_type="autoincrement",
160+
increment=5,
161+
offset=10,
162+
),
163+
)
164+
assert col.name == col_name
165+
assert await db.delete_collection(col_name) is True

tests/test_document.py

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import pytest
2+
3+
from arangoasync.exceptions import DocumentParseError
4+
from tests.helpers import generate_col_name
5+
6+
7+
@pytest.mark.asyncio
8+
async def test_document_insert(doc_col, docs):
9+
# Test insert document with no key
10+
result = await doc_col.insert({})
11+
assert await doc_col.get(result["_key"]) is not None
12+
13+
# Test insert document with ID
14+
doc_id = f"{doc_col.name}/foo"
15+
result = await doc_col.insert({"_id": doc_id})
16+
assert doc_id == result["_id"]
17+
assert result["_key"] == "foo"
18+
assert await doc_col.get("foo") is not None
19+
assert await doc_col.get(doc_id) is not None
20+
21+
with pytest.raises(DocumentParseError) as err:
22+
await doc_col.insert({"_id": f"{generate_col_name()}/foo"})
23+
assert "Bad collection name" in err.value.message
24+
25+
# Test insert with default options
26+
for doc in docs:
27+
result = await doc_col.insert(doc)
28+
assert result["_id"] == f"{doc_col.name}/{doc['_key']}"
29+
assert result["_key"] == doc["_key"]
30+
assert isinstance(result["_rev"], str)
31+
assert (await doc_col.get(doc["_key"]))["val"] == doc["val"]

0 commit comments

Comments
 (0)