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,9 +57,15 @@ 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) + if self.obj.snapshotSWHID is not None: + snapshot_id = self.obj.snapshotSWHID.object_id + return self._get_snapshot_by_id(snapshot_id) + return None + + def _handle_node_errors(self): + # snapshot can be none for some visit status + # don't raise a missing object error in this case + pass class TargetSnapshotNode(BaseSnapshotNode): 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,73 @@ +# 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 len(err) == 1 + assert ( + "Cannot return null for non-nullable field Snapshot.swhid" in err[0]["message"] + )