2018-04-03 19:30:15 +00:00
|
|
|
import pytest
|
|
|
|
from django import db
|
|
|
|
|
2018-12-26 22:03:27 +00:00
|
|
|
from funkwhale_api.federation import models
|
2019-10-19 16:10:42 +00:00
|
|
|
from funkwhale_api.music import models as music_models
|
2018-12-26 22:03:27 +00:00
|
|
|
|
2018-04-03 19:30:15 +00:00
|
|
|
|
|
|
|
def test_cannot_duplicate_actor(factories):
|
2018-06-09 13:36:16 +00:00
|
|
|
actor = factories["federation.Actor"]()
|
2018-04-03 19:30:15 +00:00
|
|
|
|
|
|
|
with pytest.raises(db.IntegrityError):
|
2018-06-09 13:36:16 +00:00
|
|
|
factories["federation.Actor"](
|
|
|
|
domain=actor.domain, preferred_username=actor.preferred_username
|
2018-04-03 19:30:15 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def test_cannot_duplicate_follow(factories):
|
2018-06-09 13:36:16 +00:00
|
|
|
follow = factories["federation.Follow"]()
|
2018-04-03 19:30:15 +00:00
|
|
|
|
|
|
|
with pytest.raises(db.IntegrityError):
|
2018-06-09 13:36:16 +00:00
|
|
|
factories["federation.Follow"](target=follow.target, actor=follow.actor)
|
2018-04-03 21:25:44 +00:00
|
|
|
|
2018-04-06 16:49:29 +00:00
|
|
|
|
2018-04-03 21:25:44 +00:00
|
|
|
def test_follow_federation_url(factories):
|
2018-06-09 13:36:16 +00:00
|
|
|
follow = factories["federation.Follow"](local=True)
|
2018-09-06 18:35:02 +00:00
|
|
|
expected = "{}#follows/{}".format(follow.actor.fid, follow.uuid)
|
|
|
|
|
|
|
|
assert follow.get_federation_id() == expected
|
|
|
|
|
|
|
|
|
|
|
|
def test_actor_get_quota(factories):
|
|
|
|
library = factories["music.Library"]()
|
2018-09-22 12:29:30 +00:00
|
|
|
factories["music.Upload"](
|
2018-09-06 18:35:02 +00:00
|
|
|
library=library,
|
|
|
|
import_status="pending",
|
|
|
|
audio_file__from_path=None,
|
|
|
|
audio_file__data=b"a",
|
|
|
|
)
|
2018-09-22 12:29:30 +00:00
|
|
|
factories["music.Upload"](
|
2018-09-06 18:35:02 +00:00
|
|
|
library=library,
|
|
|
|
import_status="skipped",
|
|
|
|
audio_file__from_path=None,
|
|
|
|
audio_file__data=b"aa",
|
|
|
|
)
|
2018-09-22 12:29:30 +00:00
|
|
|
factories["music.Upload"](
|
2018-09-06 18:35:02 +00:00
|
|
|
library=library,
|
|
|
|
import_status="errored",
|
|
|
|
audio_file__from_path=None,
|
|
|
|
audio_file__data=b"aaa",
|
|
|
|
)
|
2018-09-22 12:29:30 +00:00
|
|
|
factories["music.Upload"](
|
2018-09-06 18:35:02 +00:00
|
|
|
library=library,
|
|
|
|
import_status="finished",
|
|
|
|
audio_file__from_path=None,
|
|
|
|
audio_file__data=b"aaaa",
|
|
|
|
)
|
2019-12-04 08:55:07 +00:00
|
|
|
factories["music.Upload"](
|
|
|
|
library=library,
|
|
|
|
import_status="draft",
|
|
|
|
audio_file__from_path=None,
|
|
|
|
audio_file__data=b"aaaaa",
|
|
|
|
)
|
2019-03-21 09:32:12 +00:00
|
|
|
|
|
|
|
# this one is imported in place and don't count
|
|
|
|
factories["music.Upload"](
|
|
|
|
library=library,
|
|
|
|
import_status="finished",
|
|
|
|
source="file://test",
|
|
|
|
audio_file=None,
|
|
|
|
size=42,
|
|
|
|
)
|
|
|
|
# this one is imported in place but count because there is a mapped file
|
|
|
|
factories["music.Upload"](
|
|
|
|
library=library,
|
|
|
|
import_status="finished",
|
|
|
|
source="file://test2",
|
|
|
|
audio_file__from_path=None,
|
|
|
|
audio_file__data=b"aaaa",
|
|
|
|
)
|
|
|
|
|
2020-02-23 14:31:03 +00:00
|
|
|
# this one is in a channel
|
|
|
|
channel = factories["audio.Channel"](attributed_to=library.actor)
|
|
|
|
factories["music.Upload"](
|
|
|
|
library=channel.library,
|
|
|
|
import_status="finished",
|
|
|
|
audio_file__from_path=None,
|
|
|
|
audio_file__data=b"aaaaa",
|
|
|
|
)
|
|
|
|
|
2019-12-04 08:55:07 +00:00
|
|
|
expected = {
|
2020-02-23 14:31:03 +00:00
|
|
|
"total": 24,
|
2019-12-04 08:55:07 +00:00
|
|
|
"pending": 1,
|
|
|
|
"skipped": 2,
|
|
|
|
"errored": 3,
|
2020-02-23 14:31:03 +00:00
|
|
|
"finished": 13,
|
2019-12-04 08:55:07 +00:00
|
|
|
"draft": 5,
|
|
|
|
}
|
2018-09-06 18:35:02 +00:00
|
|
|
|
|
|
|
assert library.actor.get_current_usage() == expected
|
2018-12-05 11:13:37 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"value, expected",
|
|
|
|
[
|
|
|
|
("Domain.com", "domain.com"),
|
|
|
|
("hello-WORLD.com", "hello-world.com"),
|
|
|
|
("posés.com", "posés.com"),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_domain_name_saved_properly(value, expected, factories):
|
|
|
|
domain = factories["federation.Domain"](name=value)
|
|
|
|
assert domain.name == expected
|
2018-12-26 22:03:27 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_external_domains(factories, settings):
|
|
|
|
d1 = factories["federation.Domain"]()
|
|
|
|
d2 = factories["federation.Domain"]()
|
|
|
|
settings.FEDERATION_HOSTNAME = d1.pk
|
|
|
|
|
|
|
|
assert list(models.Domain.objects.external()) == [d2]
|
2018-12-27 18:58:34 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_domain_stats(factories):
|
|
|
|
expected = {
|
|
|
|
"actors": 0,
|
|
|
|
"libraries": 0,
|
|
|
|
"tracks": 0,
|
|
|
|
"albums": 0,
|
2020-03-31 08:45:41 +00:00
|
|
|
"channels": 0,
|
2018-12-27 18:58:34 +00:00
|
|
|
"uploads": 0,
|
|
|
|
"artists": 0,
|
|
|
|
"outbox_activities": 0,
|
|
|
|
"received_library_follows": 0,
|
|
|
|
"emitted_library_follows": 0,
|
|
|
|
"media_total_size": 0,
|
|
|
|
"media_downloaded_size": 0,
|
|
|
|
}
|
|
|
|
|
|
|
|
domain = factories["federation.Domain"]()
|
|
|
|
|
|
|
|
assert domain.get_stats() == expected
|
2019-01-03 16:10:02 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_actor_stats(factories):
|
|
|
|
expected = {
|
|
|
|
"libraries": 0,
|
|
|
|
"tracks": 0,
|
|
|
|
"albums": 0,
|
|
|
|
"uploads": 0,
|
|
|
|
"artists": 0,
|
2019-09-13 03:53:40 +00:00
|
|
|
"reports": 0,
|
2020-03-31 08:45:41 +00:00
|
|
|
"channels": 0,
|
2020-03-18 10:57:33 +00:00
|
|
|
"requests": 0,
|
2019-01-03 16:10:02 +00:00
|
|
|
"outbox_activities": 0,
|
|
|
|
"received_library_follows": 0,
|
|
|
|
"emitted_library_follows": 0,
|
|
|
|
"media_total_size": 0,
|
|
|
|
"media_downloaded_size": 0,
|
|
|
|
}
|
|
|
|
|
|
|
|
actor = factories["federation.Actor"]()
|
|
|
|
|
|
|
|
assert actor.get_stats() == expected
|
2019-04-11 08:17:10 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_actor_can_manage_false(mocker, factories):
|
|
|
|
obj = mocker.Mock()
|
|
|
|
actor = factories["federation.Actor"]()
|
|
|
|
|
|
|
|
assert actor.can_manage(obj) is False
|
|
|
|
|
|
|
|
|
|
|
|
def test_actor_can_manage_attributed_to(mocker, factories):
|
|
|
|
actor = factories["federation.Actor"]()
|
|
|
|
obj = mocker.Mock(attributed_to_id=actor.pk)
|
|
|
|
|
|
|
|
assert actor.can_manage(obj) is True
|
|
|
|
|
|
|
|
|
|
|
|
def test_actor_can_manage_domain_not_service_actor(mocker, factories):
|
|
|
|
actor = factories["federation.Actor"]()
|
|
|
|
obj = mocker.Mock(fid="https://{}/hello".format(actor.domain_id))
|
|
|
|
|
|
|
|
assert actor.can_manage(obj) is False
|
|
|
|
|
|
|
|
|
|
|
|
def test_actor_can_manage_domain_service_actor(mocker, factories):
|
|
|
|
actor = factories["federation.Actor"]()
|
|
|
|
actor.domain.service_actor = actor
|
|
|
|
actor.domain.save()
|
|
|
|
obj = mocker.Mock(fid="https://{}/hello".format(actor.domain_id))
|
|
|
|
|
|
|
|
assert actor.can_manage(obj) is True
|
2019-04-18 12:37:17 +00:00
|
|
|
|
|
|
|
|
|
|
|
def test_can_create_fetch_for_object(factories):
|
|
|
|
track = factories["music.Track"](fid="http://test.domain")
|
|
|
|
fetch = factories["federation.Fetch"](object=track)
|
|
|
|
assert fetch.url == "http://test.domain"
|
|
|
|
assert fetch.status == "pending"
|
|
|
|
assert fetch.detail == {}
|
|
|
|
assert fetch.object == track
|
2019-10-19 16:10:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"initial_approved, updated_approved, initial_playable_tracks, updated_playable_tracks",
|
|
|
|
[
|
|
|
|
(
|
|
|
|
True,
|
|
|
|
False,
|
|
|
|
{"owner": [0], "follower": [0], "local_actor": [], None: []},
|
|
|
|
{"owner": [0], "follower": [], "local_actor": [], None: []},
|
|
|
|
),
|
|
|
|
(
|
|
|
|
False,
|
|
|
|
True,
|
|
|
|
{"owner": [0], "follower": [], "local_actor": [], None: []},
|
|
|
|
{"owner": [0], "follower": [0], "local_actor": [], None: []},
|
|
|
|
),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_update_library_follow_approved_create_entries(
|
|
|
|
initial_approved,
|
|
|
|
updated_approved,
|
|
|
|
initial_playable_tracks,
|
|
|
|
updated_playable_tracks,
|
|
|
|
factories,
|
|
|
|
):
|
|
|
|
actors = {
|
|
|
|
"owner": factories["federation.Actor"](local=True),
|
|
|
|
"follower": factories["federation.Actor"](local=True),
|
|
|
|
"local_actor": factories["federation.Actor"](local=True),
|
|
|
|
None: None,
|
|
|
|
}
|
|
|
|
library = factories["music.Library"](actor=actors["owner"], privacy_level="me")
|
|
|
|
|
|
|
|
tracks = [
|
|
|
|
factories["music.Upload"](playable=True, library=library).track,
|
|
|
|
factories["music.Upload"](library=library, import_status="pending").track,
|
|
|
|
]
|
|
|
|
|
|
|
|
follow = factories["federation.LibraryFollow"](
|
|
|
|
target=library, actor=actors["follower"], approved=initial_approved
|
|
|
|
)
|
|
|
|
|
|
|
|
for actor_name, expected in initial_playable_tracks.items():
|
|
|
|
actor = actors[actor_name]
|
|
|
|
expected_tracks = [tracks[i] for i in expected]
|
|
|
|
assert list(music_models.Track.objects.playable_by(actor)) == expected_tracks
|
|
|
|
|
|
|
|
follow.approved = updated_approved
|
|
|
|
follow.save()
|
|
|
|
|
|
|
|
for actor_name, expected in updated_playable_tracks.items():
|
|
|
|
actor = actors[actor_name]
|
|
|
|
expected_tracks = [tracks[i] for i in expected]
|
|
|
|
assert list(music_models.Track.objects.playable_by(actor)) == expected_tracks
|
|
|
|
|
|
|
|
|
|
|
|
def test_update_library_follow_delete_delete_denormalization_entries(factories,):
|
|
|
|
updated_playable_tracks = {"owner": [0], "follower": []}
|
|
|
|
actors = {
|
|
|
|
"owner": factories["federation.Actor"](local=True),
|
|
|
|
"follower": factories["federation.Actor"](local=True),
|
|
|
|
}
|
|
|
|
library = factories["music.Library"](actor=actors["owner"], privacy_level="me")
|
|
|
|
|
|
|
|
tracks = [
|
|
|
|
factories["music.Upload"](playable=True, library=library).track,
|
|
|
|
factories["music.Upload"](library=library, import_status="pending").track,
|
|
|
|
]
|
|
|
|
|
|
|
|
follow = factories["federation.LibraryFollow"](
|
|
|
|
target=library, actor=actors["follower"], approved=True
|
|
|
|
)
|
|
|
|
|
|
|
|
follow.delete()
|
|
|
|
|
|
|
|
for actor_name, expected in updated_playable_tracks.items():
|
|
|
|
actor = actors[actor_name]
|
|
|
|
expected_tracks = [tracks[i] for i in expected]
|
|
|
|
assert list(music_models.Track.objects.playable_by(actor)) == expected_tracks
|