diff --git a/swh/graphql/resolvers/resolvers.py b/swh/graphql/resolvers/resolvers.py --- a/swh/graphql/resolvers/resolvers.py +++ b/swh/graphql/resolvers/resolvers.py @@ -16,6 +16,8 @@ # Every scalar is expected to resolve this way # - As an attribute/item in the object/dict returned by a backend (eg: Origin.url) +from typing import Optional + from ariadne import ObjectType, UnionType from graphql.type import GraphQLResolveInfo @@ -91,8 +93,10 @@ @visit_status.field("snapshot") def visit_snapshot_resolver( - obj, info: GraphQLResolveInfo, **kw -) -> rs.snapshot.VisitSnapshotNode: + obj: rs.visit_status.BaseVisitStatusNode, info: GraphQLResolveInfo, **kw +) -> Optional[rs.snapshot.VisitSnapshotNode]: + if obj.snapshotSWHID is None: + return None resolver = get_node_resolver("visit-snapshot") return resolver(obj, info, **kw) diff --git a/swh/graphql/resolvers/snapshot.py b/swh/graphql/resolvers/snapshot.py --- a/swh/graphql/resolvers/snapshot.py +++ b/swh/graphql/resolvers/snapshot.py @@ -57,7 +57,6 @@ obj: BaseVisitStatusNode def _get_node_data(self): - # self.obj.snapshotSWHID is the requested snapshot SWHID snapshot_id = self.obj.snapshotSWHID.object_id return self._get_snapshot_by_id(snapshot_id) diff --git a/swh/graphql/resolvers/visit_status.py b/swh/graphql/resolvers/visit_status.py --- a/swh/graphql/resolvers/visit_status.py +++ b/swh/graphql/resolvers/visit_status.py @@ -18,6 +18,8 @@ @property def snapshotSWHID(self): # To support the schema naming convention + if self._node.snapshot is None: + return None return CoreSWHID(object_type=ObjectType.SNAPSHOT, object_id=self._node.snapshot) diff --git a/swh/graphql/tests/data.py b/swh/graphql/tests/data.py --- a/swh/graphql/tests/data.py +++ b/swh/graphql/tests/data.py @@ -22,6 +22,14 @@ return swh_model_data.ORIGINS +def get_visits(): + return swh_model_data.ORIGIN_VISITS + + +def get_visit_status(): + return swh_model_data.ORIGIN_VISIT_STATUSES + + def get_snapshots(): return swh_model_data.SNAPSHOTS diff --git a/swh/graphql/tests/functional/test_visit_status.py b/swh/graphql/tests/functional/test_visit_status.py new file mode 100644 --- /dev/null +++ b/swh/graphql/tests/functional/test_visit_status.py @@ -0,0 +1,70 @@ +# Copyright (C) 2022 The Software Heritage developers +# See the AUTHORS file at the top-level directory of this distribution +# License: GNU General Public License version 3, or any later version +# See top-level LICENSE file for more information + +from ..data import get_visit_status, get_visits +from .utils import get_query_response + + +def test_get_visit_status(client): + visit = get_visits()[3] + query_str = """ + { + visit(originUrl: "%s", visitId: %s) { + status(first: 3) { + nodes { + status + date + type + snapshot { + swhid + } + } + } + } + } + """ % ( + visit.origin, + visit.visit, + ) + data, _ = get_query_response(client, query_str) + result_status = get_visit_status()[3] + assert data["visit"]["status"]["nodes"][0] == { + "date": result_status.date.isoformat(), + "snapshot": {"swhid": f"swh:1:snp:{result_status.snapshot.hex()}"}, + "status": result_status.status, + "type": result_status.type, + } + + +def test_get_visit_missing_snapshot(client): + visit = get_visits()[0] + query_str = """ + { + visit(originUrl: "%s", visitId: %s) { + status(first: 3) { + nodes { + status + date + type + snapshot { + swhid + } + } + } + } + } + """ % ( + visit.origin, + visit.visit, + ) + data, err = get_query_response(client, query_str) + result_status = get_visit_status()[0] + assert data["visit"]["status"]["nodes"][0] == { + "date": result_status.date.isoformat(), + "snapshot": None, + "status": result_status.status, + "type": result_status.type, + } + assert err is None diff --git a/swh/graphql/tests/unit/resolvers/test_resolvers.py b/swh/graphql/tests/unit/resolvers/test_resolvers.py --- a/swh/graphql/tests/unit/resolvers/test_resolvers.py +++ b/swh/graphql/tests/unit/resolvers/test_resolvers.py @@ -27,7 +27,7 @@ resolvers.visit_status.LatestVisitStatusNode, ), (rs.snapshot_resolver, resolvers.snapshot.SnapshotNode), - (rs.visit_snapshot_resolver, resolvers.snapshot.VisitSnapshotNode), + # (rs.visit_snapshot_resolver, resolvers.snapshot.VisitSnapshotNode), (rs.revision_resolver, resolvers.revision.RevisionNode), (rs.revision_directory_resolver, resolvers.directory.RevisionDirectoryNode), (rs.release_resolver, resolvers.release.ReleaseNode),