From eb1bb8fbbc3f50b0a2999f96a65301ac67ec57fa Mon Sep 17 00:00:00 2001 From: Aravinth Manivannan Date: Sun, 1 Oct 2023 19:58:49 +0530 Subject: [PATCH] feat: test object for context, id resolution, and MUST params --- features/environment.py | 40 ++++++++++++++++++ features/object.feature | 16 +++++++ features/steps/object.py | 90 ++++++++++++++++++++++++++++++++++++++++ requirements.txt | 14 +++++++ 4 files changed, 160 insertions(+) create mode 100644 features/environment.py create mode 100644 features/object.feature create mode 100644 features/steps/object.py create mode 100644 requirements.txt diff --git a/features/environment.py b/features/environment.py new file mode 100644 index 0000000..619d648 --- /dev/null +++ b/features/environment.py @@ -0,0 +1,40 @@ +from behave import * + +from common.logger import upload_logs_to_ftest + + +def before_all(context): + context.success = [] + context.failure = {} + + +def after_all(context): + max_score = 3 + score = 0 + + score = len(context.success) + print("\n\n===============") + if score == max_score: + print("All tests passed") + elif score > 0: + print(f"Partial success. {score} out of {max_score} tests passed") + + print("Summary:\n") + + logs = "" + + if context.success: + print(f"Successful tests:\n") + for s in context.success: + log = f"[OK] {s}\n" + print(log) + logs += log + + if "failure" in context: + print(f"\n\nFailed tests:\n") + for _, (test, error) in enumerate(context.failure.items()): + log = f"[FAIL] {test} failed with error:\n{error}\n-----\n" + print(log) + logs += log + + upload_logs_to_ftest(score == max_score, logs) diff --git a/features/object.feature b/features/object.feature new file mode 100644 index 0000000..888f746 --- /dev/null +++ b/features/object.feature @@ -0,0 +1,16 @@ +#Feature: showing off behave +# +# Scenario: run a simple test +# Given we have behave installed +# When we implement a test +# Then behave will test it for us! + +Feature: ActivityPub Object + ActivityPub Object as defined in https://www.w3.org/TR/activitypub/#obj-id + + Scenario: + Given A Fediverse server + When Receiving or querying an object + Then the response must contain an 'id' and a 'type' parameter + And The 'id' must resolve to the same object + And context must be ActivityPub diff --git a/features/steps/object.py b/features/steps/object.py new file mode 100644 index 0000000..1a08109 --- /dev/null +++ b/features/steps/object.py @@ -0,0 +1,90 @@ +# SPDX-FileCopyrightText: 2023 Aravinth Manivannan +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +import os +from urllib.parse import urlparse, urlunparse + +import requests +from behave import * + +from common.env import FTEST_USER +from common import logger +from common.webfinger import get_webfinger +from common.obj import get_ap_obj + + +@given("A Fediverse server") +def get_fediverse_actor(context): + webfinger = get_webfinger() + actor_url = None + for link in webfinger["links"]: + if "type" in link: + if all( + [link["rel"] == "self", link["type"] == "application/activity+json"] + ): + actor_url = link["href"] + + assert actor_url is not None + logger.info(f"Actor URL {actor_url}") + context.actor_url = actor_url + + +@when("Receiving or querying an object") +def check_actor_exists(context): + name = "check_actor_exists" + try: + actor = get_ap_obj(context.actor_url) + assert actor is not None + except Exception as e: + logger.error(e) + context.failure[name] = e + raise e + + context.success.append(name) + context.actor = actor + + +@then("the response must contain an 'id' and a 'type' parameter") +def verify_obj_attrs(context): + name = "verify_obj_attrs" + actor = context.actor + try: + assert "id" in actor, "'id' attribute present in object'" + assert "type" in actor, "'type' attribute present in object'" + except Exception as e: + logger.error(e) + context.failure[name] = e + raise e + + context.success.append(name) + + +@then("The 'id' must resolve to the same object") +def verify_id_resolves(context): + name = "verify_id_resolves" + actor = context.actor + try: + assert get_ap_obj(actor["id"]) == actor, "'id' URL resolves to same object" + except Exception as e: + logger.error(e) + context.failure[name] = e + raise e + + +@then("context must be ActivityPub") +def ctx_is_ap(context): + name = "ctx_is_ap" + + obj_ctx = context.actor["@context"] + activitypub_present = False + for ctx in obj_ctx: + if ctx == "https://www.w3.org/ns/activitystreams": + activitypub_present = True + break + try: + assert activitypub_present is True, "ActivityPub context is included" + except Exception as e: + logger.error(e) + context.failure[name] = e + raise e diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..6ef5421 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,14 @@ +attrs==23.1.0 +behave==1.2.6 +certifi==2023.7.22 +charset-normalizer==3.3.0 +idna==3.4 +jsonschema==4.19.1 +jsonschema-specifications==2023.7.1 +parse==1.19.1 +parse-type==0.6.2 +referencing==0.30.2 +requests==2.31.0 +rpds-py==0.10.3 +six==1.16.0 +urllib3==2.0.5