Page MenuHomeSoftware Heritage

D8629.diff
No OneTemporary

D8629.diff

diff --git a/swh/graphql/tests/functional/test_branch_connection.py b/swh/graphql/tests/functional/test_branch_connection.py
--- a/swh/graphql/tests/functional/test_branch_connection.py
+++ b/swh/graphql/tests/functional/test_branch_connection.py
@@ -8,13 +8,13 @@
from . import utils
-def get_branches(client, swhid: str, first: int, **args) -> tuple:
- args["first"] = first
- params = utils.get_query_params_from_args(**args)
+def get_branches(client, **kwargs) -> tuple:
query_str = """
- {
- snapshot(swhid: "%s") {
- branches(%s) {
+ query getSnapshot($swhid: SWHID!, $first: Int!, $after: String, $types: [BranchTargetType],
+ $nameInclude: String, $excludePrefix: String) {
+ snapshot(swhid: $swhid) {
+ branches(first: $first, after: $after, types: $types, nameInclude: $nameInclude,
+ nameExcludePrefix: $excludePrefix ) {
pageInfo {
endCursor
}
@@ -53,16 +53,13 @@
}
}
}
- """ % (
- swhid,
- params,
- )
- return utils.get_query_response(client, query_str)
+ """
+ return utils.get_query_response(client, query_str, **kwargs)
def test_get_data(client):
swhid = "swh:1:snp:0e7f84ede9a254f2cd55649ad5240783f557e65f"
- data, errors = get_branches(client, swhid, 10, types="[revision]")
+ data, errors = get_branches(client, swhid=swhid, first=10, types=["revision"])
assert len(data["snapshot"]["branches"]["nodes"]) == 1
# filter 'type' will return a single revision object and is used to assert data
node = data["snapshot"]["branches"]["nodes"][0]
@@ -78,7 +75,7 @@
def test_get_branches_with_alias(client):
swhid = "swh:1:snp:0e7f84ede9a254f2cd55649ad5240783f557e65f"
- data, _ = get_branches(client, swhid, 10, types="[alias]")
+ data, _ = get_branches(client, swhid=swhid, first=10, types=["alias"])
node = data["snapshot"]["branches"]["nodes"][0]
assert node == {
"name": {"text": "target/alias"},
@@ -99,7 +96,7 @@
)
def test_get_type_filter(client, filter_type, count, target_type, swhid_pattern):
swhid = "swh:1:snp:0e7f84ede9a254f2cd55649ad5240783f557e65f"
- data, _ = get_branches(client, swhid, 10, types=f"[{filter_type}]")
+ data, _ = get_branches(client, swhid=swhid, first=10, types=[filter_type])
assert len(data["snapshot"]["branches"]["nodes"]) == count
for node in data["snapshot"]["branches"]["nodes"]:
assert node["target"]["__typename"] == target_type
@@ -109,20 +106,20 @@
@pytest.mark.parametrize(
"filter_types, count",
[
- ("revision, release", 2),
- ("revision, snapshot, release", 3),
+ (["revision", "release"], 2),
+ (["revision", "snapshot", "release"], 3),
],
)
def test_get_type_filter_multiple(client, filter_types, count):
swhid = "swh:1:snp:0e7f84ede9a254f2cd55649ad5240783f557e65f"
- data, _ = get_branches(client, swhid, 10, types=f"[{filter_types}]")
+ data, _ = get_branches(client, swhid=swhid, first=10, types=filter_types)
assert len(data["snapshot"]["branches"]["nodes"]) == count
@pytest.mark.parametrize("name", ["rel", "rev", "non-exist"])
def test_get_name_include_filter(client, name):
swhid = "swh:1:snp:0e7f84ede9a254f2cd55649ad5240783f557e65f"
- data, _ = get_branches(client, swhid, 10, nameInclude=f'"{name}"')
+ data, _ = get_branches(client, swhid=swhid, first=10, nameInclude=name)
for node in data["snapshot"]["branches"]["nodes"]:
assert name in node["name"]["text"]
@@ -130,7 +127,7 @@
@pytest.mark.parametrize("name", ["target", "target/dir"])
def test_get_name_exclude_prefix_filter(client, name):
swhid = "swh:1:snp:0e7f84ede9a254f2cd55649ad5240783f557e65f"
- data, _ = get_branches(client, swhid, 10, nameExcludePrefix=f'"{name}"')
+ data, _ = get_branches(client, swhid=swhid, first=10, excludePrefix=name)
for node in data["snapshot"]["branches"]["nodes"]:
assert not node["name"]["text"].startswith(name)
@@ -138,16 +135,16 @@
@pytest.mark.parametrize("count", [1, 2])
def test_get_first_arg(client, count):
swhid = "swh:1:snp:0e7f84ede9a254f2cd55649ad5240783f557e65f"
- data, _ = get_branches(client, swhid, first=count)
+ data, _ = get_branches(client, swhid=swhid, first=count)
assert len(data["snapshot"]["branches"]["nodes"]) == count
def test_get_after_arg(client):
swhid = "swh:1:snp:0e7f84ede9a254f2cd55649ad5240783f557e65f"
- first_data, _ = get_branches(client, swhid, first=1)
+ first_data, _ = get_branches(client, swhid=swhid, first=1)
end_cursor = first_data["snapshot"]["branches"]["pageInfo"]["endCursor"]
node_name = first_data["snapshot"]["branches"]["nodes"][0]["name"]["text"]
- second_data, _ = get_branches(client, swhid, first=3, after=f'"{end_cursor}"')
+ second_data, _ = get_branches(client, swhid=swhid, first=3, after=end_cursor)
branches = second_data["snapshot"]["branches"]
assert len(branches["nodes"]) == 3
assert branches["edges"][0]["cursor"] == end_cursor
diff --git a/swh/graphql/tests/functional/test_content.py b/swh/graphql/tests/functional/test_content.py
--- a/swh/graphql/tests/functional/test_content.py
+++ b/swh/graphql/tests/functional/test_content.py
@@ -12,8 +12,8 @@
@pytest.mark.parametrize("content", get_contents())
def test_get_content_with_swhid(client, content):
query_str = """
- {
- content(swhid: "%s") {
+ query getContent($swhid: SWHID!) {
+ content(swhid: $swhid) {
swhid
checksum {
blake2s256
@@ -38,7 +38,7 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str % content.swhid())
+ data, _ = utils.get_query_response(client, query_str, swhid=str(content.swhid()))
archive_url = "https://archive.softwareheritage.org/api/1/"
response = {
"swhid": str(content.swhid()),
@@ -63,34 +63,34 @@
@pytest.mark.parametrize("content", get_contents())
def test_get_content_with_hash(client, content):
query_str = """
- {
- contentByHash(checksums: ["blake2s256:%s", "sha1:%s", "sha1_git:%s", "sha256:%s"]) {
+ query getContent($checksums: [ContentHash]!) {
+ contentByHash(checksums: $checksums) {
swhid
}
}
"""
data, _ = utils.get_query_response(
client,
- query_str
- % (
- content.blake2s256.hex(),
- content.sha1.hex(),
- content.sha1_git.hex(),
- content.sha256.hex(),
- ),
+ query_str,
+ checksums=[
+ f"blake2s256:{content.blake2s256.hex()}",
+ f"sha1:{content.sha1.hex()}",
+ f"sha1_git:{content.sha1_git.hex()}",
+ f"sha256:{content.sha256.hex()}",
+ ],
)
assert data["contentByHash"] == {"swhid": str(content.swhid())}
def test_get_content_with_invalid_swhid(client):
query_str = """
- {
- content(swhid: "swh:1:cnt:invalid") {
+ query getContent($swhid: SWHID!) {
+ content(swhid: $swhid) {
swhid
}
}
"""
- errors = utils.get_error_response(client, query_str)
+ errors = utils.get_error_response(client, query_str, swhid="invalid")
# API will throw an error in case of an invalid SWHID
assert len(errors) == 1
assert "Input error: Invalid SWHID" in errors[0]["message"]
@@ -99,21 +99,21 @@
def test_get_content_with_invalid_hashes(client):
content = get_contents()[0]
query_str = """
- {
- contentByHash(checksums: ["blake2s256:%s", "sha1:%s", "sha1_git:%s", "sha256:%s"]) {
+ query getContent($checksums: [ContentHash]!) {
+ contentByHash(checksums: $checksums) {
swhid
}
}
"""
errors = utils.get_error_response(
client,
- query_str
- % (
+ query_str,
+ checksums=[
"invalid", # Only one hash is invalid
- content.sha1.hex(),
- content.sha1_git.hex(),
- content.sha256.hex(),
- ),
+ f"sha1:{content.sha1.hex()}",
+ f"sha1_git:{content.sha1_git.hex()}",
+ f"sha256:{content.sha256.hex()}",
+ ],
)
# API will throw an error in case of an invalid content hash
assert len(errors) == 1
@@ -123,13 +123,16 @@
def test_get_content_with_invalid_hash_algorithm(client):
content = get_contents()[0]
query_str = """
- {
- contentByHash(checksums: ["test:%s"]) {
+ query getContent($checksums: [ContentHash]!) {
+ contentByHash(checksums: $checksums) {
swhid
}
}
"""
- errors = utils.get_error_response(client, query_str % content.sha1.hex())
+ data, errors = utils.get_query_response(
+ client, query_str, checksums=[f"test:{content.sha1.hex()}"]
+ )
+ assert data is None
assert len(errors) == 1
assert "Input error: Invalid hash algorithm" in errors[0]["message"]
@@ -138,8 +141,8 @@
# SWHID of a test dir with a file entry
directory_swhid = "swh:1:dir:87b339104f7dc2a8163dec988445e3987995545f"
query_str = """
- {
- directory(swhid: "%s") {
+ query getDirectory($swhid: SWHID!) {
+ directory(swhid: $swhid) {
swhid
entries(first: 2) {
nodes {
@@ -155,7 +158,7 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str % directory_swhid)
+ data, _ = utils.get_query_response(client, query_str, swhid=directory_swhid)
content_obj = data["directory"]["entries"]["nodes"][1]["target"]
assert content_obj == {
"length": 4,
@@ -166,10 +169,15 @@
def test_get_content_with_unknown_swhid(client):
unknown_sha1 = "1" * 40
query_str = """
- {
- content(swhid: "swh:1:cnt:%s") {
+ query getDirectory($swhid: SWHID!) {
+ content(swhid: $swhid) {
swhid
}
}
"""
- utils.assert_missing_object(client, query_str % unknown_sha1, "content")
+ utils.assert_missing_object(
+ client,
+ query_str,
+ obj_type="content",
+ swhid=f"swh:1:cnt:{unknown_sha1}",
+ )
diff --git a/swh/graphql/tests/functional/test_directory.py b/swh/graphql/tests/functional/test_directory.py
--- a/swh/graphql/tests/functional/test_directory.py
+++ b/swh/graphql/tests/functional/test_directory.py
@@ -12,25 +12,25 @@
@pytest.mark.parametrize("directory", get_directories())
def test_get_directory(client, directory):
query_str = """
- {
- directory(swhid: "%s") {
+ query getDirectory($swhid: SWHID!) {
+ directory(swhid: $swhid) {
swhid
}
}
"""
- data, _ = utils.get_query_response(client, query_str % directory.swhid())
+ data, _ = utils.get_query_response(client, query_str, swhid=str(directory.swhid()))
assert data["directory"] == {"swhid": str(directory.swhid())}
def test_get_directory_with_invalid_swhid(client):
query_str = """
- {
- directory(swhid: "swh:1:dir:invalid") {
+ query getDirectory($swhid: SWHID!) {
+ directory(swhid: $swhid) {
swhid
}
}
"""
- errors = utils.get_error_response(client, query_str)
+ errors = utils.get_error_response(client, query_str, swhid="swh:1:dir:invalid")
# API will throw an error in case of an invalid SWHID
assert len(errors) == 1
assert "Input error: Invalid SWHID" in errors[0]["message"]
@@ -38,8 +38,8 @@
def test_get_revision_directory(client):
query_str = """
- {
- revision(swhid: "swh:1:rev:66c7c1cd9673275037140f2abff7b7b11fc9439c") {
+ query getRevision($swhid: SWHID!) {
+ revision(swhid: $swhid) {
swhid
directory {
swhid
@@ -47,7 +47,11 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str)
+ data, _ = utils.get_query_response(
+ client,
+ query_str,
+ swhid="swh:1:rev:66c7c1cd9673275037140f2abff7b7b11fc9439c",
+ )
assert data["revision"]["directory"] == {
"swhid": "swh:1:dir:0101010101010101010101010101010101010101"
}
@@ -57,8 +61,8 @@
# TargetDirectoryNode is returned from snapshotbranch, release
# and directory entry nodes. Release node is used for testing here
query_str = """
- {
- release(swhid: "swh:1:rel:ee4d20e80af850cc0f417d25dc5073792c5010d2") {
+ query getRelease($swhid: SWHID!) {
+ release(swhid: $swhid) {
swhid
target {
...on Directory {
@@ -68,7 +72,11 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str)
+ data, _ = utils.get_query_response(
+ client,
+ query_str,
+ swhid="swh:1:rel:ee4d20e80af850cc0f417d25dc5073792c5010d2",
+ )
assert data["release"]["target"] == {
"swhid": "swh:1:dir:0505050505050505050505050505050505050505"
}
@@ -77,10 +85,15 @@
def test_get_directory_with_unknown_swhid(client):
unknown_sha1 = "1" * 40
query_str = """
- {
- directory(swhid: "swh:1:dir:%s") {
+ query getDirectory($swhid: SWHID!) {
+ directory(swhid: $swhid) {
swhid
}
}
"""
- utils.assert_missing_object(client, query_str % unknown_sha1, "directory")
+ utils.assert_missing_object(
+ client,
+ query_str,
+ obj_type="directory",
+ swhid=f"swh:1:dir:{unknown_sha1}",
+ )
diff --git a/swh/graphql/tests/functional/test_directory_entry.py b/swh/graphql/tests/functional/test_directory_entry.py
--- a/swh/graphql/tests/functional/test_directory_entry.py
+++ b/swh/graphql/tests/functional/test_directory_entry.py
@@ -21,8 +21,8 @@
directory = get_directories()[0]
path = "missing"
query_str = """
- {
- directoryEntry(directorySwhid: "%s", path: "%s") {
+ query getDirEntry($swhid: SWHID!, $path: String!) {
+ directoryEntry(directorySwhid: $swhid, path: $path) {
name {
text
}
@@ -34,11 +34,14 @@
}
}
}
- """ % (
- directory.swhid(),
- path,
+ """
+ utils.assert_missing_object(
+ client,
+ query_str,
+ "directoryEntry",
+ swhid=str(directory.swhid()),
+ path=path,
)
- utils.assert_missing_object(client, query_str, "directoryEntry")
@pytest.mark.parametrize(
@@ -47,8 +50,8 @@
def test_get_directory_entry(client, directory):
storage = server.get_storage()
query_str = """
- {
- directoryEntry(directorySwhid: "%s", path: "%s") {
+ query getDirEntry($swhid: SWHID!, $path: String!) {
+ directoryEntry(directorySwhid: $swhid, path: $path) {
name {
text
}
@@ -68,13 +71,11 @@
}
"""
for entry in storage.directory_ls(directory.id, recursive=True):
- query = query_str % (
- directory.swhid(),
- entry["name"].decode(),
- )
data, _ = utils.get_query_response(
client,
- query,
+ query_str,
+ swhid=str(directory.swhid()),
+ path=entry["name"].decode(),
)
swhid = None
if entry["type"] == "file" and entry["sha1_git"] is not None:
@@ -99,8 +100,8 @@
@pytest.mark.parametrize("directory", get_directories())
def test_get_directory_entry_connection(client, directory):
query_str = """
- {
- directory(swhid: "%s") {
+ query getDirectory($swhid: SWHID!) {
+ directory(swhid: $swhid) {
swhid
entries {
nodes {
@@ -113,7 +114,7 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str % directory.swhid())
+ data, _ = utils.get_query_response(client, query_str, swhid=str(directory.swhid()))
directory_entries = data["directory"]["entries"]["nodes"]
assert len(directory_entries) == len(directory.entries)
output = [
@@ -130,10 +131,10 @@
for dir_entry in storage.directory_ls(directory.id):
name_include = dir_entry["name"][:-1].decode()
query_str = """
- {
- directory(swhid: "%s") {
+ query getDirectory($swhid: SWHID!, $nameInclude: String) {
+ directory(swhid: $swhid) {
swhid
- entries(nameInclude: "%s") {
+ entries(nameInclude: $nameInclude) {
nodes {
targetType
name {
@@ -143,11 +144,13 @@
}
}
}
- """ % (
- directory.swhid(),
- name_include,
+ """
+ data, _ = utils.get_query_response(
+ client,
+ query_str,
+ swhid=str(directory.swhid()),
+ nameInclude=name_include,
)
- data, _ = utils.get_query_response(client, query_str)
for entry in data["directory"]["entries"]["nodes"]:
assert name_include in entry["name"]["text"]
assert entry["targetType"] == get_target_type(dir_entry["type"])
diff --git a/swh/graphql/tests/functional/test_origin_connection.py b/swh/graphql/tests/functional/test_origin_connection.py
--- a/swh/graphql/tests/functional/test_origin_connection.py
+++ b/swh/graphql/tests/functional/test_origin_connection.py
@@ -3,16 +3,18 @@
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information
+from typing import Optional
+
from . import utils
from ..data import get_origins
-def get_origins_from_api(client, first: int, **args) -> tuple:
- args["first"] = first
- params = utils.get_query_params_from_args(**args)
+def get_origins_from_api(
+ client, first: int, urlPattern: Optional[str] = None, **args
+) -> tuple:
query_str = """
- {
- origins(%s) {
+ query getOrigins($first: Int!, $urlPattern: String) {
+ origins(first: $first, urlPattern: $urlPattern) {
nodes {
url
}
@@ -22,24 +24,26 @@
}
}
}
- """ % (
- params,
+ """
+ return utils.get_query_response(
+ client, query_str, first=first, urlPattern=urlPattern
)
- return utils.get_query_response(client, query_str)
def test_get(client, storage):
- data, _ = get_origins_from_api(client, 10)
+ data, _ = get_origins_from_api(client, first=10)
assert len(data["origins"]["nodes"]) == len(get_origins())
def test_get_filter_by_pattern(client):
- data, _ = get_origins_from_api(client, 10, urlPattern='"somewhere.org/den"')
+ data, _ = get_origins_from_api(client, first=10, urlPattern='"somewhere.org/den"')
assert len(data["origins"]["nodes"]) == 1
def test_get_filter_by_non_existing_pattern(client):
- data, _ = get_origins_from_api(client, 10, urlPattern='"somewhere.org/den/test/"')
+ data, _ = get_origins_from_api(
+ client, first=10, urlPattern='"somewhere.org/den/test/"'
+ )
assert len(data["origins"]["nodes"]) == 0
diff --git a/swh/graphql/tests/functional/test_origin_node.py b/swh/graphql/tests/functional/test_origin_node.py
--- a/swh/graphql/tests/functional/test_origin_node.py
+++ b/swh/graphql/tests/functional/test_origin_node.py
@@ -5,27 +5,26 @@
import pytest
+from . import utils
from ..data import get_origins
-from .utils import assert_missing_object, get_query_response
def test_invalid_get(client):
query_str = """
- {
+ query getOrigin {
origin(url: "http://example.com/non-existing") {
url
}
}
"""
- assert_missing_object(client, query_str, "origin")
+ utils.assert_missing_object(client, query_str, "origin")
@pytest.mark.parametrize("origin", get_origins())
def test_get(client, storage, origin):
- query_str = (
- """
- {
- origin(url: "%s") {
+ query_str = """
+ query getOrigin($url: String!) {
+ origin(url: $url) {
url
id
visits(first: 10) {
@@ -44,10 +43,8 @@
}
}
"""
- % origin.url
- )
- response, _ = get_query_response(client, query_str)
+ response, _ = utils.get_query_response(client, query_str, url=origin.url)
data_origin = response["origin"]
storage_origin = storage.origin_get([origin.url])[0]
visits_and_statuses = storage.origin_visit_get_with_statuses(origin.url).results
@@ -61,40 +58,49 @@
def test_latest_visit_type_filter(client):
query_str = """
- {
- origin(url: "%s") {
- latestVisit(visitType: "%s") {
+ query getOrigin($url: String!, $visitType: String!) {
+ origin(url: $url) {
+ latestVisit(visitType: $visitType) {
visitId
}
}
}
"""
- data, _ = get_query_response(client, query_str % (get_origins()[0].url, "git"))
+ data, _ = utils.get_query_response(
+ client, query_str, url=get_origins()[0].url, visitType="git"
+ )
assert data["origin"] == {"latestVisit": {"visitId": 3}}
- data, _ = get_query_response(client, query_str % (get_origins()[0].url, "hg"))
+ data, _ = utils.get_query_response(
+ client, query_str, url=get_origins()[0].url, visitType="hg"
+ )
assert data["origin"] == {"latestVisit": None}
def test_latest_visit_require_snapshot_filter(client):
query_str = """
- {
- origin(url: "%s") {
- latestVisit(requireSnapshot: %s) {
+ query getOrigin($url: String!, $requireSnapshot: Boolean!) {
+ origin(url: $url) {
+ latestVisit(requireSnapshot: $requireSnapshot) {
visitId
}
}
}
"""
- data, _ = get_query_response(client, query_str % (get_origins()[1].url, "true"))
+ data, _ = utils.get_query_response(
+ client,
+ query_str,
+ url=get_origins()[1].url,
+ requireSnapshot=True,
+ )
assert data["origin"] == {"latestVisit": {"visitId": 2}}
def test_latest_visit_allowed_statuses_filter(client):
query_str = """
- {
- origin(url: "%s") {
- latestVisit(allowedStatuses: [partial]) {
+ query getOrigin($url: String!, $allowedStatuses: [VisitStatusState!]!) {
+ origin(url: $url) {
+ latestVisit(allowedStatuses: $allowedStatuses) {
visitId
statuses {
nodes {
@@ -105,7 +111,12 @@
}
}
"""
- data, _ = get_query_response(client, query_str % (get_origins()[1].url))
+ data, _ = utils.get_query_response(
+ client,
+ query_str,
+ url=get_origins()[1].url,
+ allowedStatuses=["partial"],
+ )
assert data["origin"] == {
"latestVisit": {"statuses": {"nodes": [{"status": "partial"}]}, "visitId": 2}
}
diff --git a/swh/graphql/tests/functional/test_pagination.py b/swh/graphql/tests/functional/test_pagination.py
--- a/swh/graphql/tests/functional/test_pagination.py
+++ b/swh/graphql/tests/functional/test_pagination.py
@@ -3,15 +3,15 @@
# License: GNU General Public License version 3, or any later version
# See top-level LICENSE file for more information
+from . import utils
from ..data import get_origins
-from .utils import get_query_response
# Using Origin object to run functional tests for pagination
-def get_origin_nodes(client, first=1, after=""):
+def get_origin_nodes(client, first, after=""):
query_str = """
- {
- origins(first: %s, %s) {
+ query getOrigins($first: Int!, $after: String) {
+ origins(first: $first, after: $after) {
nodes {
id
}
@@ -21,29 +21,26 @@
}
}
}
- """ % (
- first,
- after,
- )
- return get_query_response(client, query_str)
+ """
+ return utils.get_query_response(client, query_str, first=first, after=after)
def test_pagination(client):
# requesting the max number of nodes available
# endCursor must be None
- data, _ = get_origin_nodes(client, len(get_origins()))
+ data, _ = get_origin_nodes(client, first=len(get_origins()))
assert len(data["origins"]["nodes"]) == len(get_origins())
assert data["origins"]["pageInfo"] == {"hasNextPage": False, "endCursor": None}
def test_first_arg(client):
- data, _ = get_origin_nodes(client, 1)
+ data, _ = get_origin_nodes(client, first=1)
assert len(data["origins"]["nodes"]) == 1
assert data["origins"]["pageInfo"]["hasNextPage"] is True
def test_invalid_first_arg(client):
- data, errors = get_origin_nodes(client, -1)
+ data, errors = get_origin_nodes(client, first=-1)
assert data["origins"] is None
assert (len(errors)) == 2 # one error for origins and anotehr one for pageInfo
assert (
@@ -53,7 +50,7 @@
def test_too_big_first_arg(client):
- data, errors = get_origin_nodes(client, 1001) # max page size is 1000
+ data, errors = get_origin_nodes(client, first=1001) # max page size is 1000
assert data["origins"] is None
assert (len(errors)) == 2
assert (
@@ -63,16 +60,16 @@
def test_after_arg(client):
- first_data, _ = get_origin_nodes(client)
+ first_data, _ = get_origin_nodes(client, first=1)
end_cursor = first_data["origins"]["pageInfo"]["endCursor"]
# get again with endcursor as the after argument
- data, _ = get_origin_nodes(client, 1, f'after: "{end_cursor}"')
+ data, _ = get_origin_nodes(client, first=1, after=end_cursor)
assert len(data["origins"]["nodes"]) == 1
assert data["origins"]["pageInfo"] == {"hasNextPage": False, "endCursor": None}
def test_invalid_after_arg(client):
- data, errors = get_origin_nodes(client, 1, 'after: "invalid"')
+ data, errors = get_origin_nodes(client, first=1, after="invalid")
assert data["origins"] is None
assert (len(errors)) == 2
assert (
@@ -81,14 +78,13 @@
def test_edge_cursor(client):
- origins = get_origin_nodes(client)[0]["origins"]
+ origins = get_origin_nodes(client, first=1)[0]["origins"]
# end cursor here must be the item cursor for the second item
end_cursor = origins["pageInfo"]["endCursor"]
- query_str = (
- """
- {
- origins(first: 1, after: "%s") {
+ query_str = """
+ query getOrigins($first: Int!, $after: String) {
+ origins(first: $first, after: $after) {
edges {
cursor
node {
@@ -101,9 +97,7 @@
}
}
"""
- % end_cursor
- )
- data, _ = get_query_response(client, query_str)
+ data, _ = utils.get_query_response(client, query_str, first=1, after=end_cursor)
origins = data["origins"]
assert [edge["node"] for edge in origins["edges"]] == origins["nodes"]
assert origins["edges"][0]["cursor"] == end_cursor
diff --git a/swh/graphql/tests/functional/test_release_node.py b/swh/graphql/tests/functional/test_release_node.py
--- a/swh/graphql/tests/functional/test_release_node.py
+++ b/swh/graphql/tests/functional/test_release_node.py
@@ -21,10 +21,9 @@
@pytest.mark.parametrize("release", get_releases())
def test_get_release(client, release):
- query_str = (
- """
- {
- release(swhid: "%s") {
+ query_str = """
+ query getRelease($swhid: SWHID!) {
+ release(swhid: $swhid) {
swhid
name {
text
@@ -49,9 +48,7 @@
}
}
"""
- % release.swhid()
- )
- data, _ = utils.get_query_response(client, query_str)
+ data, _ = utils.get_query_response(client, query_str, swhid=str(release.swhid()))
assert data["release"] == {
"swhid": str(release.swhid()),
@@ -74,22 +71,23 @@
def test_get_release_with_invalid_swhid(client):
query_str = """
- {
- release(swhid: "swh:1:rel:invalid") {
+ query getRelease($swhid: SWHID!) {
+ release(swhid: $swhid) {
swhid
}
}
"""
- errors = utils.get_error_response(client, query_str)
+ errors = utils.get_error_response(client, query_str, swhid="swh:1:rel:invalid")
# API will throw an error in case of an invalid SWHID
assert len(errors) == 1
+ assert "Expected type 'SWHID'. Input error: Invalid SWHID" in errors[0]["message"]
@pytest.mark.parametrize("release_with_target", get_releases_with_target())
def test_get_release_targets(client, release_with_target):
query_str = """
- {
- release(swhid: "%s") {
+ query getRelease($swhid: SWHID!) {
+ release(swhid: $swhid) {
targetType
target {
...on Revision {
@@ -108,7 +106,9 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str % release_with_target.swhid())
+ data, _ = utils.get_query_response(
+ client, query_str, swhid=str(release_with_target.swhid())
+ )
if release_with_target.target_type == ObjectType.REVISION:
target_swhid = get_revisions()[0].swhid()
@@ -132,8 +132,8 @@
# ie: both swhid and message will be available in the response
swhid = get_releases_with_target()[0].swhid()
query_str = """
- {
- release(swhid: "%s") {
+ query getRelease($swhid: SWHID!) {
+ release(swhid: $swhid) {
targetType
target {
...on Revision {
@@ -155,7 +155,7 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str % swhid)
+ data, _ = utils.get_query_response(client, query_str, swhid=str(swhid))
assert data["release"] == {
"target": {
"message": {"text": "hello"},
@@ -168,10 +168,15 @@
def test_get_release_with_unknown_swhid(client):
unknown_sha1 = "1" * 40
query_str = """
- {
- release(swhid: "swh:1:rel:%s") {
+ query getRelease($swhid: SWHID!) {
+ release(swhid: $swhid) {
swhid
}
}
"""
- utils.assert_missing_object(client, query_str % unknown_sha1, "release")
+ utils.assert_missing_object(
+ client,
+ query_str,
+ obj_type="release",
+ swhid=f"swh:1:rel:{unknown_sha1}",
+ )
diff --git a/swh/graphql/tests/functional/test_revision.py b/swh/graphql/tests/functional/test_revision.py
--- a/swh/graphql/tests/functional/test_revision.py
+++ b/swh/graphql/tests/functional/test_revision.py
@@ -14,8 +14,8 @@
@pytest.mark.parametrize("revision", get_revisions())
def test_get_revision(client, revision):
query_str = """
- {
- revision(swhid: "%s") {
+ query getRevision($swhid: SWHID!) {
+ revision(swhid: $swhid) {
swhid
message {
text
@@ -50,7 +50,7 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str % revision.swhid())
+ data, _ = utils.get_query_response(client, query_str, swhid=str(revision.swhid()))
assert data["revision"] == {
"swhid": str(revision.swhid()),
"message": {"text": revision.message.decode()},
@@ -74,13 +74,13 @@
def test_get_revision_with_invalid_swhid(client):
query_str = """
- {
- revision(swhid: "swh:1:cnt:invalid") {
+ query getRevision($swhid: SWHID!) {
+ revision(swhid: $swhid) {
swhid
}
}
"""
- errors = utils.get_error_response(client, query_str)
+ errors = utils.get_error_response(client, query_str, swhid="swh:1:cnt:invalid")
# API will throw an error in case of an invalid SWHID
assert len(errors) == 1
assert "Input error: Invalid SWHID" in errors[0]["message"]
@@ -90,8 +90,8 @@
# SWHID of a snapshot with revision as target
snapshot_swhid = "swh:1:snp:9e78d7105c5e0f886487511e2a92377b4ee4c32a"
query_str = """
- {
- snapshot(swhid: "%s") {
+ query getSnapshot($swhid: SWHID!) {
+ snapshot(swhid: $swhid) {
branches(first: 1, types: [revision]) {
nodes {
targetType
@@ -105,7 +105,7 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str % snapshot_swhid)
+ data, _ = utils.get_query_response(client, query_str, swhid=snapshot_swhid)
revision_obj = data["snapshot"]["branches"]["nodes"][0]["target"]
assert revision_obj == {
"swhid": "swh:1:rev:66c7c1cd9673275037140f2abff7b7b11fc9439c"
@@ -115,8 +115,8 @@
def test_get_revision_log(client):
revision_swhid = get_revisions_with_parents()[0].swhid()
query_str = """
- {
- revision(swhid: "%s") {
+ query getRevision($swhid: SWHID!) {
+ revision(swhid: $swhid) {
swhid
revisionLog(first: 3) {
nodes {
@@ -126,7 +126,7 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str % revision_swhid)
+ data, _ = utils.get_query_response(client, query_str, swhid=str(revision_swhid))
assert data["revision"]["revisionLog"] == {
"nodes": [
{"swhid": str(revision_swhid)},
@@ -139,8 +139,8 @@
def test_get_revision_parents(client):
revision_swhid = get_revisions_with_parents()[0].swhid()
query_str = """
- {
- revision(swhid: "%s") {
+ query getRevision($swhid: SWHID!) {
+ revision(swhid: $swhid) {
swhid
parents {
nodes {
@@ -150,7 +150,7 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str % revision_swhid)
+ data, _ = utils.get_query_response(client, query_str, swhid=str(revision_swhid))
assert data["revision"]["parents"] == {
"nodes": [
@@ -163,10 +163,15 @@
def test_get_revision_with_unknown_swhid(client):
unknown_sha1 = "1" * 40
query_str = """
- {
- revision(swhid: "swh:1:rev:%s") {
+ query getRevision($swhid: SWHID!) {
+ revision(swhid: $swhid) {
swhid
}
}
"""
- utils.assert_missing_object(client, query_str % unknown_sha1, "revision")
+ utils.assert_missing_object(
+ client,
+ query_str,
+ obj_type="revision",
+ swhid=f"swh:1:rev:{unknown_sha1}",
+ )
diff --git a/swh/graphql/tests/functional/test_search.py b/swh/graphql/tests/functional/test_search.py
--- a/swh/graphql/tests/functional/test_search.py
+++ b/swh/graphql/tests/functional/test_search.py
@@ -8,8 +8,8 @@
def test_search_origins(client):
query_str = """
- {
- search(query: "fox", first: 1) {
+ query doSearch($query: String!, $first: Int!) {
+ search(query: $query, first: $first) {
nodes {
targetType
target {
@@ -28,7 +28,7 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str)
+ data, _ = utils.get_query_response(client, query_str, query="fox", first=1)
assert len(data["search"]["nodes"]) == 1
assert data == {
"search": {
@@ -48,8 +48,8 @@
def test_search_missing_url(client):
query_str = """
- {
- search(query: "missing-fox", first: 1) {
+ query doSearch($query: String!, $first: Int!) {
+ search(query: $query, first: $first) {
nodes {
targetType
}
@@ -60,5 +60,5 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str)
+ data, _ = utils.get_query_response(client, query_str, query="missing-fox", first=1)
assert len(data["search"]["nodes"]) == 0
diff --git a/swh/graphql/tests/functional/test_snapshot_node.py b/swh/graphql/tests/functional/test_snapshot_node.py
--- a/swh/graphql/tests/functional/test_snapshot_node.py
+++ b/swh/graphql/tests/functional/test_snapshot_node.py
@@ -5,15 +5,15 @@
import pytest
+from . import utils
from ..data import get_snapshots
-from .utils import assert_missing_object, get_error_response, get_query_response
@pytest.mark.parametrize("snapshot", get_snapshots())
def test_get_snapshot(client, snapshot):
query_str = """
- {
- snapshot(swhid: "%s") {
+ query getSnapshot($swhid: SWHID!) {
+ snapshot(swhid: $swhid) {
id
swhid
branches(first:5) {
@@ -27,7 +27,7 @@
}
}
"""
- data, _ = get_query_response(client, query_str % snapshot.swhid())
+ data, _ = utils.get_query_response(client, query_str, swhid=str(snapshot.swhid()))
assert data["snapshot"]["swhid"] == str(snapshot.swhid())
assert data["snapshot"]["id"] == snapshot.id.hex()
assert len(data["snapshot"]["branches"]["nodes"]) == len(snapshot.branches)
@@ -35,23 +35,28 @@
def test_get_snapshot_missing_swhid(client):
query_str = """
- {
- snapshot(swhid: "swh:1:snp:0949d7a8c96347dba09be8d79085b8207f345412") {
+ query getSnapshot($swhid: SWHID!) {
+ snapshot(swhid: $swhid) {
swhid
}
}
"""
- assert_missing_object(client, query_str, "snapshot")
+ utils.assert_missing_object(
+ client,
+ query_str,
+ obj_type="snapshot",
+ swhid="swh:1:snp:0949d7a8c96347dba09be8d79085b8207f345412",
+ )
def test_get_snapshot_invalid_swhid(client):
query_str = """
- {
- snapshot(swhid: "swh:1:snp:invalid") {
+ query getSnapshot($swhid: SWHID!) {
+ snapshot(swhid: $swhid) {
swhid
}
}
"""
- errors = get_error_response(client, query_str)
+ errors = utils.get_error_response(client, query_str, swhid="swh:1:snp:invalid")
assert len(errors) == 1
assert "Input error: Invalid SWHID" in errors[0]["message"]
diff --git a/swh/graphql/tests/functional/test_swhid_resolve.py b/swh/graphql/tests/functional/test_swhid_resolve.py
--- a/swh/graphql/tests/functional/test_swhid_resolve.py
+++ b/swh/graphql/tests/functional/test_swhid_resolve.py
@@ -17,15 +17,15 @@
def test_invalid_swhid(client):
query_str = """
- {
- resolveSwhid(swhid: "swh:1:dir:dae0d245988b472abd30a4f968b919d0019b6c7") {
+ query resolve($swhid: SWHID!) {
+ resolveSwhid(swhid: $swhid) {
nodes {
targetType
}
}
}
"""
- errors = utils.get_error_response(client, query_str)
+ errors = utils.get_error_response(client, query_str, swhid="swh:1:dir:invalid")
# API will throw an error in case of an invalid SWHID
assert len(errors) == 1
assert "Input error: Invalid SWHID" in errors[0]["message"]
@@ -43,15 +43,15 @@
)
def test_missing_swhid(client, swhid):
query_str = """
- {
- resolveSwhid(swhid: "%s") {
+ query resolve($swhid: SWHID!) {
+ resolveSwhid(swhid: $swhid) {
nodes {
targetType
}
}
}
"""
- data, _ = utils.get_query_response(client, query_str % swhid)
+ data, _ = utils.get_query_response(client, query_str, swhid=swhid)
# API will return an empty list in case of a valid, non existing SWHID
assert data == {"resolveSwhid": {"nodes": []}}
@@ -59,8 +59,8 @@
@pytest.mark.parametrize("snapshot", get_snapshots())
def test_snapshot_swhid_resolve(client, snapshot):
query_str = """
- {
- resolveSwhid(swhid: "%s") {
+ query resolve($swhid: SWHID!) {
+ resolveSwhid(swhid: $swhid) {
nodes {
targetType
target {
@@ -73,7 +73,7 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str % snapshot.swhid())
+ data, _ = utils.get_query_response(client, query_str, swhid=str(snapshot.swhid()))
assert data == {
"resolveSwhid": {
"nodes": [
@@ -92,8 +92,8 @@
@pytest.mark.parametrize("revision", get_revisions())
def test_revision_swhid_resolve(client, revision):
query_str = """
- {
- resolveSwhid(swhid: "%s") {
+ query resolve($swhid: SWHID!) {
+ resolveSwhid(swhid: $swhid) {
nodes {
targetType
target {
@@ -106,7 +106,7 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str % revision.swhid())
+ data, _ = utils.get_query_response(client, query_str, swhid=str(revision.swhid()))
assert data == {
"resolveSwhid": {
"nodes": [
@@ -125,8 +125,8 @@
@pytest.mark.parametrize("release", get_releases())
def test_release_swhid_resolve(client, release):
query_str = """
- {
- resolveSwhid(swhid: "%s") {
+ query resolve($swhid: SWHID!) {
+ resolveSwhid(swhid: $swhid) {
nodes {
targetType
target {
@@ -139,7 +139,7 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str % release.swhid())
+ data, _ = utils.get_query_response(client, query_str, swhid=str(release.swhid()))
assert data == {
"resolveSwhid": {
"nodes": [
@@ -158,8 +158,8 @@
@pytest.mark.parametrize("directory", get_directories())
def test_directory_swhid_resolve(client, directory):
query_str = """
- {
- resolveSwhid(swhid: "%s") {
+ query resolve($swhid: SWHID!) {
+ resolveSwhid(swhid: $swhid) {
nodes {
targetType
target {
@@ -172,7 +172,7 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str % directory.swhid())
+ data, _ = utils.get_query_response(client, query_str, swhid=str(directory.swhid()))
assert data == {
"resolveSwhid": {
"nodes": [
@@ -191,8 +191,8 @@
@pytest.mark.parametrize("content", get_contents())
def test_content_swhid_resolve(client, content):
query_str = """
- {
- resolveSwhid(swhid: "%s") {
+ query resolve($swhid: SWHID!) {
+ resolveSwhid(swhid: $swhid) {
nodes {
targetType
target {
@@ -205,7 +205,7 @@
}
}
"""
- data, _ = utils.get_query_response(client, query_str % content.swhid())
+ data, _ = utils.get_query_response(client, query_str, swhid=str(content.swhid()))
assert data == {
"resolveSwhid": {
"nodes": [
diff --git a/swh/graphql/tests/functional/test_visit_node.py b/swh/graphql/tests/functional/test_visit_node.py
--- a/swh/graphql/tests/functional/test_visit_node.py
+++ b/swh/graphql/tests/functional/test_visit_node.py
@@ -5,15 +5,15 @@
import pytest
+from . import utils
from ..data import get_origins
-from .utils import assert_missing_object, get_query_response
@pytest.mark.parametrize("origin", get_origins())
def test_get_visit(client, storage, origin):
query_str = """
- {
- visit(originUrl: "%s", visitId: %s) {
+ query getVisit($origin: String!, $visitId: Int!) {
+ visit(originUrl: $origin, visitId: $visitId) {
visitId
date
type
@@ -38,7 +38,9 @@
for vws in visits_and_statuses:
visit = vws.visit
statuses = vws.statuses
- data, _ = get_query_response(client, query_str % (origin.url, visit.visit))
+ data, _ = utils.get_query_response(
+ client, query_str, origin=origin.url, visitId=visit.visit
+ )
assert data["visit"] == {
"visitId": visit.visit,
"type": visit.type,
@@ -63,13 +65,13 @@
}
}
"""
- assert_missing_object(client, query_str, "visit")
+ utils.assert_missing_object(client, query_str, "visit")
def test_get_latest_visit_status_filter_by_status_return_null(client):
query_str = """
- {
- visit(originUrl: "%s", visitId: %s) {
+ query getVisit($origin: String!, $visitId: Int!) {
+ visit(originUrl: $origin, visitId: $visitId) {
visitId
date
type
@@ -78,11 +80,10 @@
}
}
}
- """ % (
- get_origins()[0].url,
- 1,
+ """
+ data, err = utils.get_query_response(
+ client, query_str, origin=get_origins()[0].url, visitId=1
)
- data, err = get_query_response(client, query_str)
assert err is None
assert data == {
"visit": {
@@ -96,8 +97,8 @@
def test_get_latest_visit_status_filter_by_type(client):
query_str = """
- {
- visit(originUrl: "%s", visitId: %s) {
+ query getVisit($origin: String!, $visitId: Int!) {
+ visit(originUrl: $origin, visitId: $visitId) {
visitId
date
type
@@ -107,11 +108,10 @@
}
}
}
- """ % (
- get_origins()[0].url,
- 1,
+ """
+ data, err = utils.get_query_response(
+ client, query_str, origin=get_origins()[0].url, visitId=1
)
- data, err = get_query_response(client, query_str)
assert err is None
assert data == {
"visit": {
@@ -128,8 +128,8 @@
def test_get_latest_visit_status_filter_by_snapshot(client):
query_str = """
- {
- visit(originUrl: "%s", visitId: %s) {
+ query getVisit($origin: String!, $visitId: Int!) {
+ visit(originUrl: $origin, visitId: $visitId) {
visitId
date
type
@@ -142,11 +142,10 @@
}
}
}
- """ % (
- get_origins()[1].url,
- 2,
+ """
+ data, err = utils.get_query_response(
+ client, query_str, origin=get_origins()[1].url, visitId=2
)
- data, err = get_query_response(client, query_str)
assert err is None
assert data == {
"visit": {
diff --git a/swh/graphql/tests/functional/test_visit_status.py b/swh/graphql/tests/functional/test_visit_status.py
--- a/swh/graphql/tests/functional/test_visit_status.py
+++ b/swh/graphql/tests/functional/test_visit_status.py
@@ -5,8 +5,8 @@
import pytest
+from . import utils
from ..data import get_origins, get_visit_status, get_visits
-from .utils import get_query_response
@pytest.mark.parametrize(
@@ -14,8 +14,8 @@
)
def test_get_visit_status(client, visit, visit_status):
query_str = """
- {
- visit(originUrl: "%s", visitId: %s) {
+ query getVisit($origin: String!, $visitId: Int!) {
+ visit(originUrl: $origin, visitId: $visitId) {
statuses(first: 3) {
nodes {
status
@@ -28,11 +28,10 @@
}
}
}
- """ % (
- visit.origin,
- visit.visit,
+ """
+ data, _ = utils.get_query_response(
+ client, query_str, origin=visit.origin, visitId=visit.visit
)
- data, _ = get_query_response(client, query_str)
assert data["visit"]["statuses"]["nodes"][0] == {
"date": visit_status.date.isoformat(),
"snapshot": {"swhid": f"swh:1:snp:{visit_status.snapshot.hex()}"}
@@ -46,8 +45,8 @@
def test_visit_status_pagination(client):
# visit status is using a different cursor, hence separate test
query_str = """
- {
- visit(originUrl: "%s", visitId: %s) {
+ query getVisit($origin: String!, $visitId: Int!) {
+ visit(originUrl: $origin, visitId: $visitId) {
statuses(first: 1) {
pageInfo {
hasNextPage
@@ -62,17 +61,16 @@
}
}
}
- """ % (
- get_origins()[0].url,
- 1,
+ """
+ data, _ = utils.get_query_response(
+ client, query_str, origin=get_origins()[0].url, visitId=1
)
- data, _ = get_query_response(client, query_str)
# request again with the endcursor
end_cursor = data["visit"]["statuses"]["pageInfo"]["endCursor"]
query_str = """
- {
- visit(originUrl: "%s", visitId: %s) {
- statuses(first: 1, after: "%s") {
+ query getVisit($origin: String!, $visitId: Int!, $after: String) {
+ visit(originUrl: $origin, visitId: $visitId) {
+ statuses(first: 1, after: $after) {
pageInfo {
hasNextPage
endCursor
@@ -86,12 +84,14 @@
}
}
}
- """ % (
- get_origins()[0].url,
- 1,
- end_cursor,
+ """
+ data, _ = utils.get_query_response(
+ client,
+ query_str,
+ origin=get_origins()[0].url,
+ visitId=1,
+ after=end_cursor,
)
- data, _ = get_query_response(client, query_str)
assert data["visit"]["statuses"] == {
"edges": [
{
diff --git a/swh/graphql/tests/functional/utils.py b/swh/graphql/tests/functional/utils.py
--- a/swh/graphql/tests/functional/utils.py
+++ b/swh/graphql/tests/functional/utils.py
@@ -6,32 +6,27 @@
import json
from typing import Dict, Tuple
+from ariadne import gql
-def get_response(client, query_str: str):
- return client.post("/", json={"query": query_str})
-
-def get_query_response(client, query_str: str) -> Tuple[Dict, Dict]:
- response = get_response(client, query_str)
+def get_query_response(client, query_str: str, **kwargs) -> Tuple[Dict, Dict]:
+ query = gql(query_str)
+ response = client.post("/", json={"query": query, "variables": kwargs})
assert response.status_code == 200, response.data
result = json.loads(response.data)
return result.get("data"), result.get("errors")
-def assert_missing_object(client, query_str: str, obj_type: str) -> None:
- data, errors = get_query_response(client, query_str)
+def assert_missing_object(client, query_str: str, obj_type: str, **kwargs) -> None:
+ data, errors = get_query_response(client, query_str, **kwargs)
assert data[obj_type] is None
assert len(errors) == 1
assert errors[0]["message"] == "Object error: Requested object is not available"
assert errors[0]["path"] == [obj_type]
-def get_error_response(client, query_str: str, error_code: int = 400) -> Dict:
- response = get_response(client, query_str)
- assert response.status_code == error_code
- return json.loads(response.data)["errors"]
-
-
-def get_query_params_from_args(**args) -> str:
- # build a GraphQL query parameters string from arguments
- return ",".join([f"{key}: {val}" for (key, val) in args.items()])
+def get_error_response(client, query_str: str, **kwargs) -> Dict:
+ data, errors = get_query_response(client, query_str, **kwargs)
+ assert data is None
+ assert len(errors) > 0
+ return errors

File Metadata

Mime Type
text/plain
Expires
Thu, Jan 30, 4:15 PM (2 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3220961

Event Timeline