Page MenuHomeSoftware Heritage

Add functional tests for visit object
ClosedPublic

Authored by jayeshv on May 19 2022, 11:20 AM.

Diff Detail

Repository
rDGQL GraphQL API
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

Build is green

Patch application report for D7862 (id=28382)

Rebasing onto 783a4d3081...

Current branch diff-target is up to date.
Changes applied before test
commit 2510a606cf3c68a1102ffbdac12328e17c17153e
Author: Jayesh Velayudhan <jayesh@softwareheritage.org>
Date:   Thu May 19 11:19:01 2022 +0200

    Add functional tests for visit object

See https://jenkins.softwareheritage.org/job/DGQL/job/tests-on-diff/21/ for more details.

Build is green

Patch application report for D7862 (id=28387)

Rebasing onto d5010fd75f...

Current branch diff-target is up to date.
Changes applied before test
commit 0711013ee2c234533cfc3b108f487e71566b491d
Author: Jayesh Velayudhan <jayesh@softwareheritage.org>
Date:   Thu May 19 11:19:01 2022 +0200

    Add functional tests for visit object

See https://jenkins.softwareheritage.org/job/DGQL/job/tests-on-diff/24/ for more details.

I think it would be better to avoid hardcoding test inputs and expected values in graphql responses.

You should rely on pytest parameters and fixtures instead.

Also as @vlorentz said on IRC, you can test for dict equality as pytest will produce nice diff when they are not equal.

Quickly hacking on your code made me produce this:

diff --git a/swh/graphql/resolvers/visit.py b/swh/graphql/resolvers/visit.py
index a2222d1..1e7ab0f 100644
--- a/swh/graphql/resolvers/visit.py
+++ b/swh/graphql/resolvers/visit.py
@@ -14,7 +14,7 @@ class BaseVisitNode(BaseNode):
     @property
     def id(self):
         # FIXME, use a better id
-        return utils.b64encode(f"{self.origin}-{str(self.visit)}")
+        return utils.visit_id(self.origin, self.visit)
 
     @property
     def visitId(self):  # To support the schema naming convention
diff --git a/swh/graphql/tests/conftest.py b/swh/graphql/tests/conftest.py
index a1e21d2..bf4a8da 100644
--- a/swh/graphql/tests/conftest.py
+++ b/swh/graphql/tests/conftest.py
@@ -3,7 +3,6 @@
 # License: GNU General Public License version 3, or any later version
 # See top-level LICENSE file for more information
 
-
 from ariadne import graphql_sync
 from flask import Flask, jsonify, request
 import pytest
@@ -12,7 +11,7 @@ from swh.graphql import server as app_server
 from swh.graphql.app import schema
 from swh.storage import get_storage as get_swhstorage
 
-from .data import populate_dummy_data
+from .data import populate_dummy_data, get_origins
 
 
 @pytest.fixture
@@ -22,6 +21,7 @@ def storage():
     app_server.storage = storage
     # populate the in-memory storage
     populate_dummy_data(storage)
+    return storage
 
 
 @pytest.fixture
diff --git a/swh/graphql/tests/functional/test_visit_node.py b/swh/graphql/tests/functional/test_visit_node.py
index a5fef47..291baff 100644
--- a/swh/graphql/tests/functional/test_visit_node.py
+++ b/swh/graphql/tests/functional/test_visit_node.py
@@ -3,15 +3,22 @@
 # License: GNU General Public License version 3, or any later version
 # See top-level LICENSE file for more information
 
+import pytest
+
 from datetime import datetime
 
+from swh.graphql.utils import utils
+from swh.model.swhids import CoreSWHID, ObjectType
+
 from .utils import get_query_response
+from ..data import get_origins
 
 
-def test_get_visit(client):
+@pytest.mark.parametrize("origin", get_origins())
+def test_get_visit(client, storage, origin):
     query_str = """
     {
-      visit(originUrl: "http://example.com/forge1", visitId: 1) {
+      visit(originUrl: "%s", visitId: %s) {
         id
         date
         type
@@ -31,23 +38,36 @@ def test_get_visit(client):
       }
     }
     """
-    data, _ = get_query_response(client, query_str)
-    visit = data["visit"]
-    assert visit["type"] == "git"
-    assert datetime.fromisoformat(visit["date"]).year == datetime.now().year
-    assert visit["id"] == "aHR0cDovL2V4YW1wbGUuY29tL2ZvcmdlMS0x"
-    assert len(visit["status"]) == 1
 
-    assert visit["latestStatus"]["status"] == "full"
-    assert visit["latestStatus"]["type"] == "git"
-    assert (
-        datetime.fromisoformat(visit["latestStatus"]["date"]).year
-        == datetime.now().year
-    )
-    assert (
-        visit["latestStatus"]["snapshot"]["swhid"]
-        == "swh:1:snp:1a8893e6a86f444e8be8e7bda6cb34fb1735a00e"
-    )
+    visits_and_statuses = storage.origin_visit_get_with_statuses(origin.url).results
+
+    for visit, statuses in map(
+        lambda vws: (vws.visit, vws.statuses), visits_and_statuses
+    ):
+
+        data, _ = get_query_response(client, query_str % (origin.url, visit.visit))
+
+        assert data["visit"] == {
+            "id": utils.visit_id(origin.url, visit.visit),
+            "type": visit.type,
+            "date": visit.date.isoformat(),
+            "latestStatus": {
+                "date": statuses[-1].date.isoformat(),
+                "type": statuses[-1].type,
+                "status": statuses[-1].status,
+                "snapshot": {
+                    "swhid": str(
+                        CoreSWHID(
+                            object_type=ObjectType.SNAPSHOT,
+                            object_id=statuses[-1].snapshot,
+                        )
+                    )
+                }
+                if statuses[-1].snapshot
+                else None,
+            },
+            "status": {"nodes": [{"status": status.status} for status in statuses]},
+        }
 
 
 def test_invalid_get_visit(client):
diff --git a/swh/graphql/utils/utils.py b/swh/graphql/utils/utils.py
index c6f4094..7dba3b3 100644
--- a/swh/graphql/utils/utils.py
+++ b/swh/graphql/utils/utils.py
@@ -52,3 +52,7 @@ def paginated(source: List, first: int, after=0) -> PagedResult:
     if len(source) > end_cursor:
         next_page_token = str(end_cursor)
     return PagedResult(results=results, next_page_token=next_page_token)
+
+
+def visit_id(origin_url: str, visit: int) -> str:
+    return b64encode(f"{origin_url}-{visit}")

This way you can extend your tests data without changing test implementation.

Addressing review comments

Build is green

Patch application report for D7862 (id=28471)

Rebasing onto 0cabd8ee94...

Current branch diff-target is up to date.
Changes applied before test
commit 209771904f78dceb3a7f35f9feedb43cf6154a89
Author: Jayesh Velayudhan <jayesh@softwareheritage.org>
Date:   Thu May 19 11:19:01 2022 +0200

    Add functional tests for the visit object

See https://jenkins.softwareheritage.org/job/DGQL/job/tests-on-diff/30/ for more details.

vlorentz added inline comments.
swh/graphql/tests/functional/test_visit_node.py
40–42

this is simpler

54–59

maybe? what do you think?

This revision is now accepted and ready to land.May 25 2022, 3:57 PM
swh/graphql/tests/functional/test_visit_node.py
54–59

much better

Build is green

Patch application report for D7862 (id=28489)

Rebasing onto 70b9fe0e3d...

Current branch diff-target is up to date.
Changes applied before test
commit 6ee8e01f522820c87b91b650d4242d152431e6ed
Author: Jayesh Velayudhan <jayesh@softwareheritage.org>
Date:   Thu May 19 11:19:01 2022 +0200

    Add functional tests for the visit object

See https://jenkins.softwareheritage.org/job/DGQL/job/tests-on-diff/33/ for more details.

This revision was automatically updated to reflect the committed changes.