from datetime import datetime as dt
from datetime import timezone
import pytest
from conftest import DB, Response
from hircine.db.models import Namespace
@pytest.fixture
def query_namespace(execute_id):
query = """
query namespace($id: Int!) {
namespace(id: $id) {
__typename
... on Namespace {
id
name
sortName
}
... on Error {
message
}
... on IDNotFoundError {
id
}
}
}
"""
return execute_id(query)
@pytest.fixture
def query_namespaces(execute):
query = """
query namespaces {
namespaces {
__typename
count
edges {
id
name
}
}
}
"""
return execute(query)
@pytest.fixture
def add_namespace(execute_add):
mutation = """
mutation addNamespace($input: AddNamespaceInput!) {
addNamespace(input: $input) {
__typename
... on AddSuccess {
id
}
... on Error {
message
}
... on InvalidParameterError {
parameter
}
... on IDNotFoundError {
id
}
}
}
"""
return execute_add(mutation)
@pytest.fixture
def update_namespaces(execute_update):
mutation = """
mutation updateNamespaces($ids: [Int!]!, $input: UpdateNamespaceInput!) {
updateNamespaces(ids: $ids, input: $input) {
__typename
... on Success {
message
}
... on Error {
message
}
... on IDNotFoundError {
id
}
... on InvalidParameterError {
parameter
}
}
}
""" # noqa: E501
return execute_update(mutation)
@pytest.fixture
def delete_namespaces(execute_delete):
mutation = """
mutation deleteNamespaces($ids: [Int!]!) {
deleteNamespaces(ids: $ids) {
__typename
... on Success {
message
}
... on Error {
message
}
... on IDNotFoundError {
id
}
}
}
"""
return execute_delete(mutation)
@pytest.mark.anyio
async def test_query_namespace(query_namespace, gen_namespace):
namespace = await DB.add(next(gen_namespace))
response = Response(await query_namespace(namespace.id))
response.assert_is("Namespace")
assert response.id == namespace.id
assert response.name == namespace.name
assert response.sortName == namespace.sort_name
@pytest.mark.anyio
async def test_query_namespace_fails_not_found(query_namespace):
response = Response(await query_namespace(1))
response.assert_is("IDNotFoundError")
assert response.id == 1
assert response.message == "Namespace ID not found: '1'"
@pytest.mark.anyio
async def test_query_namespaces(query_namespaces, gen_namespace):
namespaces = await DB.add_all(*gen_namespace)
response = Response(await query_namespaces())
response.assert_is("NamespaceFilterResult")
assert response.count == len(namespaces)
assert isinstance((response.edges), list)
assert len(response.edges) == len(namespaces)
edges = iter(response.edges)
for namespace in sorted(namespaces, key=lambda a: a.name):
edge = next(edges)
assert edge["id"] == namespace.id
assert edge["name"] == namespace.name
@pytest.mark.anyio
async def test_add_namespace(add_namespace):
response = Response(await add_namespace({"name": "added", "sortName": "foo"}))
response.assert_is("AddSuccess")
namespace = await DB.get(Namespace, response.id)
assert namespace is not None
assert namespace.name == "added"
assert namespace.sort_name == "foo"
@pytest.mark.anyio
async def test_add_namespace_fails_empty_parameter(add_namespace):
response = Response(await add_namespace({"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_namespace_fails_exists(add_namespace, gen_namespace):
namespace = await DB.add(next(gen_namespace))
response = Response(await add_namespace({"name": namespace.name}))
response.assert_is("NameExistsError")
assert response.message == "Another Namespace with this name exists"
@pytest.mark.anyio
async def test_delete_namespace(delete_namespaces, gen_namespace):
namespace = await DB.add(next(gen_namespace))
id = namespace.id
response = Response(await delete_namespaces(id))
response.assert_is("DeleteSuccess")
namespace = await DB.get(Namespace, id)
assert namespace is None
@pytest.mark.anyio
async def test_delete_namespace_not_found(delete_namespaces):
response = Response(await delete_namespaces(1))
response.assert_is("IDNotFoundError")
assert response.id == 1
assert response.message == "Namespace ID not found: '1'"
@pytest.mark.anyio
async def test_update_namespace(update_namespaces, gen_namespace):
namespace = await DB.add(next(gen_namespace))
input = {"name": "updated", "sortName": "foo"}
response = Response(await update_namespaces(namespace.id, input))
response.assert_is("UpdateSuccess")
namespace = await DB.get(Namespace, namespace.id)
assert namespace is not None
assert namespace.name == "updated"
assert namespace.sort_name == "foo"
@pytest.mark.anyio
async def test_update_namespace_fails_exists(update_namespaces, gen_namespace):
first = await DB.add(next(gen_namespace))
second = await DB.add(next(gen_namespace))
response = Response(await update_namespaces(second.id, {"name": first.name}))
response.assert_is("NameExistsError")
assert response.message == "Another Namespace with this name exists"
@pytest.mark.anyio
async def test_update_namespace_fails_not_found(update_namespaces):
response = Response(await update_namespaces(1, {"name": "updated"}))
response.assert_is("IDNotFoundError")
assert response.id == 1
assert response.message == "Namespace ID not found: '1'"
@pytest.mark.anyio
async def test_update_namespaces_cannot_bulk_edit_name(
update_namespaces, gen_namespace
):
first = await DB.add(next(gen_namespace))
second = await DB.add(next(gen_namespace))
response = Response(
await update_namespaces([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_namespace_fails_empty_parameter(
update_namespaces, gen_namespace, empty
):
namespace = await DB.add(next(gen_namespace))
response = Response(await update_namespaces(namespace.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_namespace_changes_updated_at(update_namespaces):
original_namespace = Namespace(name="namespace")
original_namespace.updated_at = dt(2023, 1, 1, tzinfo=timezone.utc)
original_namespace = await DB.add(original_namespace)
response = Response(
await update_namespaces(original_namespace.id, {"name": "updated"})
)
response.assert_is("UpdateSuccess")
namespace = await DB.get(Namespace, original_namespace.id)
assert namespace.updated_at > original_namespace.updated_at