def test_fetch_channel_actor_returns_channel_and_fetch_outbox( factories, r_mock, settings, mocker): obj = factories["audio.Channel"]() fetch = factories["federation.Fetch"](url=obj.actor.fid) payload = serializers.ActorSerializer(obj.actor).data fetch_collection = mocker.patch.object( tasks, "fetch_collection", return_value={"next_page": "http://outbox.url/page2"}) fetch_collection_delayed = mocker.patch.object(tasks.fetch_collection, "delay") r_mock.get(obj.fid, json=payload) tasks.fetch(fetch_id=fetch.pk) fetch.refresh_from_db() assert fetch.status == "finished" assert fetch.object == obj fetch_collection.assert_called_once_with( obj.actor.outbox_url, channel_id=obj.pk, max_pages=1, ) fetch_collection_delayed.assert_called_once_with( "http://outbox.url/page2", max_pages=settings.FEDERATION_COLLECTION_MAX_PAGES - 1, is_page=True, channel_id=obj.pk, )
def test_fetch_rel_alternate(factories, r_mock, mocker): actor = factories["federation.Actor"]() fetch = factories["federation.Fetch"](url="http://example.page") html_text = """ <html> <head> <link rel="alternate" type="application/activity+json" href="{}" /> </head> </html> """.format(actor.fid) ap_payload = serializers.ActorSerializer(actor).data init = mocker.spy(serializers.ActorSerializer, "__init__") save = mocker.spy(serializers.ActorSerializer, "save") r_mock.get(fetch.url, text=html_text) r_mock.get(actor.fid, json=ap_payload) tasks.fetch(fetch_id=fetch.pk) fetch.refresh_from_db() assert fetch.status == "finished" assert fetch.object == actor assert init.call_count == 1 assert init.call_args[0][1] == actor assert init.call_args[1]["data"] == ap_payload assert save.call_count == 1
def test_fetch_webfinger(factories, r_mock, mocker): actor = factories["federation.Actor"]() fetch = factories["federation.Fetch"]( url="webfinger://{}".format(actor.full_username)) payload = serializers.ActorSerializer(actor).data init = mocker.spy(serializers.ActorSerializer, "__init__") save = mocker.spy(serializers.ActorSerializer, "save") webfinger_payload = { "subject": "acct:{}".format(actor.full_username), "aliases": ["https://test.webfinger"], "links": [{ "rel": "self", "type": "application/activity+json", "href": actor.fid }], } webfinger_url = "https://{}/.well-known/webfinger?resource={}".format( actor.domain_id, webfinger_payload["subject"]) r_mock.get(actor.fid, json=payload) r_mock.get(webfinger_url, json=webfinger_payload) tasks.fetch(fetch_id=fetch.pk) fetch.refresh_from_db() assert fetch.status == "finished" assert fetch.object == actor assert init.call_count == 1 assert init.call_args[0][1] == actor assert init.call_args[1]["data"] == payload assert save.call_count == 1
def refetch_obj(obj, queryset): """ Given an Artist/Album/Track instance, if the instance is from a remote pod, will attempt to update local data with the latest ActivityPub representation. """ if obj.is_local: return obj now = timezone.now() limit = now - datetime.timedelta(minutes=settings.FEDERATION_OBJECT_FETCH_DELAY) last_fetch = obj.fetches.order_by("-creation_date").first() if last_fetch is not None and last_fetch.creation_date > limit: # we fetched recently, no need to do it again return obj logger.info("Refetching %s:%s at %s…", obj._meta.label, obj.pk, obj.fid) actor = actors.get_service_actor() fetch = federation_models.Fetch.objects.create(actor=actor, url=obj.fid, object=obj) try: federation_tasks.fetch(fetch_id=fetch.pk) except Exception: logger.exception( "Error while refetching %s:%s at %s…", obj._meta.label, obj.pk, obj.fid ) else: fetch.refresh_from_db() if fetch.status == "finished": obj = queryset.get(pk=obj.pk) return obj
def test_fetch_honor_instance_policy_different_url_and_id(r_mock, factories): domain = factories["moderation.InstancePolicy"]( block_all=True, for_domain=True).target_domain fid = "https://ok/test" r_mock.get(fid, json={"id": "http://{}/test".format(domain.name)}) fetch = factories["federation.Fetch"](url=fid) tasks.fetch(fetch_id=fetch.pk) fetch.refresh_from_db() assert fetch.status == "errored" assert fetch.detail["error_code"] == "blocked"
def test_fetch_honor_instance_policy_domain(factories): domain = factories["moderation.InstancePolicy"]( block_all=True, for_domain=True).target_domain fid = "https://{}/test".format(domain.name) fetch = factories["federation.Fetch"](url=fid) tasks.fetch(fetch_id=fetch.pk) fetch.refresh_from_db() assert fetch.status == "errored" assert fetch.detail["error_code"] == "blocked"
def test_fetch_errored(factories, r_mock_args, expected_error_code, r_mock): url = "https://fetch.object" fetch = factories["federation.Fetch"](url=url) r_mock.get(url, **r_mock_args) tasks.fetch(fetch_id=fetch.pk) fetch.refresh_from_db() assert fetch.status == "errored" assert fetch.detail["error_code"] == expected_error_code
def test_fetch_skipped(factories, r_mock): url = "https://fetch.object" fetch = factories["federation.Fetch"](url=url) payload = {"@context": jsonld.get_default_context(), "type": "Unhandled"} r_mock.get(url, json=payload) tasks.fetch(fetch_id=fetch.pk) fetch.refresh_from_db() assert fetch.status == "skipped" assert fetch.detail["reason"] == "unhandled_type"
def test_fetch_honor_mrf_inbox_before_http(mrf_inbox_registry, factories, mocker): apply = mocker.patch.object(mrf_inbox_registry, "apply", return_value=(None, False)) fid = "http://domain/test" fetch = factories["federation.Fetch"](url=fid) tasks.fetch(fetch_id=fetch.pk) fetch.refresh_from_db() assert fetch.status == "errored" assert fetch.detail["error_code"] == "blocked" apply.assert_called_once_with({"id": fid})
def test_fetch_honor_mrf_inbox_after_http(r_mock, mrf_inbox_registry, factories, mocker): apply = mocker.patch.object(mrf_inbox_registry, "apply", side_effect=[(True, False), (None, False)]) payload = {"id": "http://domain/test", "actor": "hello"} r_mock.get(payload["id"], json=payload) fetch = factories["federation.Fetch"](url=payload["id"]) tasks.fetch(fetch_id=fetch.pk) fetch.refresh_from_db() assert fetch.status == "errored" assert fetch.detail["error_code"] == "blocked" apply.assert_any_call({"id": payload["id"]}) apply.assert_any_call(payload)
def test_fetch_success(factories, r_mock, mocker): artist = factories["music.Artist"]() fetch = factories["federation.Fetch"](url=artist.fid) payload = serializers.ArtistSerializer(artist).data init = mocker.spy(serializers.ArtistSerializer, "__init__") save = mocker.spy(serializers.ArtistSerializer, "save") r_mock.get(artist.fid, json=payload) tasks.fetch(fetch_id=fetch.pk) fetch.refresh_from_db() assert fetch.status == "finished" assert init.call_count == 1 assert init.call_args[0][1] == artist assert init.call_args[1]["data"] == payload assert save.call_count == 1
def test_fetch_url(factory_name, factory_kwargs, serializer_class, factories, r_mock, mocker): obj = factories[factory_name](**factory_kwargs) fetch = factories["federation.Fetch"](url=obj.fid) payload = serializer_class(obj).data init = mocker.spy(serializer_class, "__init__") save = mocker.spy(serializer_class, "save") r_mock.get(obj.fid, json=payload) tasks.fetch(fetch_id=fetch.pk) fetch.refresh_from_db() assert fetch.status == "finished" assert fetch.object == obj assert init.call_count == 1 assert init.call_args[0][1] == obj assert init.call_args[1]["data"] == payload assert save.call_count == 1