from datetime import datetime as dt
from datetime import timezone
import pytest
from conftest import DB, Response
from hircine.db.models import Circle
@pytest.fixture
def query_circle(execute_id):
query = """
query circle($id: Int!) {
circle(id: $id) {
__typename
... on Circle {
id
name
}
... on Error {
message
}
... on IDNotFoundError {
id
}
}
}
"""
return execute_id(query)
@pytest.fixture
def query_circles(execute):
query = """
query circles {
circles {
__typename
count
edges {
id
name
}
}
}
"""
return execute(query)
@pytest.fixture
def add_circle(execute_add):
mutation = """
mutation addCircle($input: AddCircleInput!) {
addCircle(input: $input) {
__typename
... on AddSuccess {
id
}
... on Error {
message
}
... on InvalidParameterError {
parameter
}
}
}
"""
return execute_add(mutation)
@pytest.fixture
def update_circles(execute_update):
mutation = """
mutation updateCircles($ids: [Int!]!, $input: UpdateCircleInput!) {
updateCircles(ids: $ids, input: $input) {
__typename
... on Success {
message
}
... on IDNotFoundError {
id
}
... on Error {
message
}
... on InvalidParameterError {
parameter
}
}
}
""" # noqa: E501
return execute_update(mutation)
@pytest.fixture
def delete_circles(execute_delete):
mutation = """
mutation deleteCircles($ids: [Int!]!) {
deleteCircles(ids: $ids) {
__typename
... on Success {
message
}
... on Error {
message
}
... on IDNotFoundError {
id
}
}
}
"""
return execute_delete(mutation)
@pytest.mark.anyio
async def test_query_circle(query_circle, gen_circle):
circle = await DB.add(next(gen_circle))
response = Response(await query_circle(circle.id))
response.assert_is("Circle")
assert response.id == circle.id
assert response.name == circle.name
@pytest.mark.anyio
async def test_query_circle_fails_not_found(query_circle):
response = Response(await query_circle(1))
response.assert_is("IDNotFoundError")
assert response.id == 1
assert response.message == "Circle ID not found: '1'"
@pytest.mark.anyio
async def test_query_circles(query_circles, gen_circle):
circles = await DB.add_all(*gen_circle)
response = Response(await query_circles())
response.assert_is("CircleFilterResult")
assert response.count == len(circles)
assert isinstance((response.edges), list)
assert len(response.edges) == len(circles)
edges = iter(response.edges)
for circle in sorted(circles, key=lambda a: a.name):
edge = next(edges)
assert edge["id"] == circle.id
assert edge["name"] == circle.name
@pytest.mark.anyio
async def test_add_circle(add_circle):
response = Response(await add_circle({"name": "added circle"}))
response.assert_is("AddSuccess")
circle = await DB.get(Circle, response.id)
assert circle is not None
assert circle.name == "added circle"
@pytest.mark.anyio
async def test_add_circle_fails_empty_parameter(add_circle):
response = Response(await add_circle({"name": ""}))
response.assert_is("InvalidParameterError")
assert response.parameter == "name"
assert response.message == "Invalid parameter 'name': cannot be empty"
@pytest.mark.anyio
async def test_add_circle_fails_exists(add_circle, gen_circle):
circle = await DB.add(next(gen_circle))
response = Response(await add_circle({"name": circle.name}))
response.assert_is("NameExistsError")
assert response.message == "Another Circle with this name exists"
@pytest.mark.anyio
async def test_delete_circle(delete_circles, gen_circle):
circle = await DB.add(next(gen_circle))
id = circle.id
response = Response(await delete_circles(id))
response.assert_is("DeleteSuccess")
circle = await DB.get(Circle, id)
assert circle is None
@pytest.mark.anyio
async def test_delete_circle_not_found(delete_circles):
response = Response(await delete_circles(1))
response.assert_is("IDNotFoundError")
assert response.id == 1
assert response.message == "Circle ID not found: '1'"
@pytest.mark.anyio
async def test_update_circle(update_circles, gen_circle):
circle = await DB.add(next(gen_circle))
input = {"name": "updated circle"}
response = Response(await update_circles(circle.id, input))
response.assert_is("UpdateSuccess")
circle = await DB.get(Circle, circle.id)
assert circle is not None
assert circle.name == "updated circle"
@pytest.mark.anyio
async def test_update_circle_fails_exists(update_circles, gen_circle):
first = await DB.add(next(gen_circle))
second = await DB.add(next(gen_circle))
response = Response(await update_circles(second.id, {"name": first.name}))
response.assert_is("NameExistsError")
assert response.message == "Another Circle with this name exists"
@pytest.mark.anyio
async def test_update_circle_fails_not_found(update_circles):
response = Response(await update_circles(1, {"name": "updated circle"}))
response.assert_is("IDNotFoundError")
assert response.id == 1
assert response.message == "Circle ID not found: '1'"
@pytest.mark.anyio
async def test_update_circles_cannot_bulk_edit_name(update_circles, gen_circle):
first = await DB.add(next(gen_circle))
second = await DB.add(next(gen_circle))
response = Response(await update_circles([first.id, second.id], {"name": "unique"}))
response.assert_is("InvalidParameterError")
@pytest.mark.parametrize(
"empty",
[
None,
"",
],
ids=[
"none",
"empty string",
],
)
@pytest.mark.anyio
async def test_update_circle_fails_empty_parameter(update_circles, gen_circle, empty):
circle = await DB.add(next(gen_circle))
response = Response(await update_circles(circle.id, {"name": empty}))
response.assert_is("InvalidParameterError")
assert response.parameter == "name"
assert response.message == "Invalid parameter 'name': cannot be empty"
@pytest.mark.anyio
async def test_update_circle_changes_updated_at(update_circles):
original_circle = Circle(name="circle")
original_circle.updated_at = dt(2023, 1, 1, tzinfo=timezone.utc)
original_circle = await DB.add(original_circle)
response = Response(await update_circles(original_circle.id, {"name": "updated"}))
response.assert_is("UpdateSuccess")
circle = await DB.get(Circle, original_circle.id)
assert circle.updated_at > original_circle.updated_at