Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
funkwhale
Manage
Activity
Members
Labels
Plan
Issues
0
Issue boards
Milestones
Wiki
Code
Merge requests
0
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container Registry
Model registry
Operate
Environments
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Zwordi
funkwhale
Commits
47aa209d
Verified
Commit
47aa209d
authored
6 years ago
by
Eliot Berriot
Browse files
Options
Downloads
Patches
Plain Diff
See !368: ensure we filter playable entities in subsonic API
parent
224fa4bf
No related branches found
No related tags found
No related merge requests found
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
api/funkwhale_api/music/factories.py
+22
-0
22 additions, 0 deletions
api/funkwhale_api/music/factories.py
api/funkwhale_api/subsonic/views.py
+26
-8
26 additions, 8 deletions
api/funkwhale_api/subsonic/views.py
api/tests/subsonic/test_views.py
+64
-27
64 additions, 27 deletions
api/tests/subsonic/test_views.py
with
112 additions
and
35 deletions
api/funkwhale_api/music/factories.py
+
22
−
0
View file @
47aa209d
...
@@ -14,11 +14,28 @@ SAMPLES_PATH = os.path.join(
...
@@ -14,11 +14,28 @@ SAMPLES_PATH = os.path.join(
)
)
def
playable_factory
(
field
):
@factory.post_generation
def
inner
(
self
,
create
,
extracted
,
**
kwargs
):
if
not
create
:
return
if
extracted
:
UploadFactory
(
library__privacy_level
=
"
everyone
"
,
import_status
=
"
finished
"
,
**
{
field
:
self
}
)
return
inner
@registry.register
@registry.register
class
ArtistFactory
(
factory
.
django
.
DjangoModelFactory
):
class
ArtistFactory
(
factory
.
django
.
DjangoModelFactory
):
name
=
factory
.
Faker
(
"
name
"
)
name
=
factory
.
Faker
(
"
name
"
)
mbid
=
factory
.
Faker
(
"
uuid4
"
)
mbid
=
factory
.
Faker
(
"
uuid4
"
)
fid
=
factory
.
Faker
(
"
federation_url
"
)
fid
=
factory
.
Faker
(
"
federation_url
"
)
playable
=
playable_factory
(
"
track__album__artist
"
)
class
Meta
:
class
Meta
:
model
=
"
music.Artist
"
model
=
"
music.Artist
"
...
@@ -33,6 +50,7 @@ class AlbumFactory(factory.django.DjangoModelFactory):
...
@@ -33,6 +50,7 @@ class AlbumFactory(factory.django.DjangoModelFactory):
artist
=
factory
.
SubFactory
(
ArtistFactory
)
artist
=
factory
.
SubFactory
(
ArtistFactory
)
release_group_id
=
factory
.
Faker
(
"
uuid4
"
)
release_group_id
=
factory
.
Faker
(
"
uuid4
"
)
fid
=
factory
.
Faker
(
"
federation_url
"
)
fid
=
factory
.
Faker
(
"
federation_url
"
)
playable
=
playable_factory
(
"
track__album
"
)
class
Meta
:
class
Meta
:
model
=
"
music.Album
"
model
=
"
music.Album
"
...
@@ -47,6 +65,7 @@ class TrackFactory(factory.django.DjangoModelFactory):
...
@@ -47,6 +65,7 @@ class TrackFactory(factory.django.DjangoModelFactory):
artist
=
factory
.
SelfAttribute
(
"
album.artist
"
)
artist
=
factory
.
SelfAttribute
(
"
album.artist
"
)
position
=
1
position
=
1
tags
=
ManyToManyFromList
(
"
tags
"
)
tags
=
ManyToManyFromList
(
"
tags
"
)
playable
=
playable_factory
(
"
track
"
)
class
Meta
:
class
Meta
:
model
=
"
music.Track
"
model
=
"
music.Track
"
...
@@ -71,6 +90,9 @@ class UploadFactory(factory.django.DjangoModelFactory):
...
@@ -71,6 +90,9 @@ class UploadFactory(factory.django.DjangoModelFactory):
class
Params
:
class
Params
:
in_place
=
factory
.
Trait
(
audio_file
=
None
)
in_place
=
factory
.
Trait
(
audio_file
=
None
)
playable
=
factory
.
Trait
(
import_status
=
"
finished
"
,
library__privacy_level
=
"
everyone
"
)
@registry.register
@registry.register
...
...
This diff is collapsed.
Click to expand it.
api/funkwhale_api/subsonic/views.py
+
26
−
8
View file @
47aa209d
...
@@ -19,7 +19,9 @@ from funkwhale_api.playlists import models as playlists_models
...
@@ -19,7 +19,9 @@ from funkwhale_api.playlists import models as playlists_models
from
.
import
authentication
,
filters
,
negotiation
,
serializers
from
.
import
authentication
,
filters
,
negotiation
,
serializers
def
find_object
(
queryset
,
model_field
=
"
pk
"
,
field
=
"
id
"
,
cast
=
int
):
def
find_object
(
queryset
,
model_field
=
"
pk
"
,
field
=
"
id
"
,
cast
=
int
,
filter_playable
=
False
):
def
decorator
(
func
):
def
decorator
(
func
):
def
inner
(
self
,
request
,
*
args
,
**
kwargs
):
def
inner
(
self
,
request
,
*
args
,
**
kwargs
):
data
=
request
.
GET
or
request
.
POST
data
=
request
.
GET
or
request
.
POST
...
@@ -50,6 +52,11 @@ def find_object(queryset, model_field="pk", field="id", cast=int):
...
@@ -50,6 +52,11 @@ def find_object(queryset, model_field="pk", field="id", cast=int):
qs
=
queryset
qs
=
queryset
if
hasattr
(
qs
,
"
__call__
"
):
if
hasattr
(
qs
,
"
__call__
"
):
qs
=
qs
(
request
)
qs
=
qs
(
request
)
if
filter_playable
:
actor
=
utils
.
get_actor_from_request
(
request
)
qs
=
qs
.
playable_by
(
actor
).
distinct
()
try
:
try
:
obj
=
qs
.
get
(
**
{
model_field
:
value
})
obj
=
qs
.
get
(
**
{
model_field
:
value
})
except
qs
.
model
.
DoesNotExist
:
except
qs
.
model
.
DoesNotExist
:
...
@@ -124,7 +131,9 @@ class SubsonicViewSet(viewsets.GenericViewSet):
...
@@ -124,7 +131,9 @@ class SubsonicViewSet(viewsets.GenericViewSet):
@list_route
(
methods
=
[
"
get
"
,
"
post
"
],
url_name
=
"
get_artists
"
,
url_path
=
"
getArtists
"
)
@list_route
(
methods
=
[
"
get
"
,
"
post
"
],
url_name
=
"
get_artists
"
,
url_path
=
"
getArtists
"
)
def
get_artists
(
self
,
request
,
*
args
,
**
kwargs
):
def
get_artists
(
self
,
request
,
*
args
,
**
kwargs
):
artists
=
music_models
.
Artist
.
objects
.
all
()
artists
=
music_models
.
Artist
.
objects
.
all
().
playable_by
(
utils
.
get_actor_from_request
(
request
)
)
data
=
serializers
.
GetArtistsSerializer
(
artists
).
data
data
=
serializers
.
GetArtistsSerializer
(
artists
).
data
payload
=
{
"
artists
"
:
data
}
payload
=
{
"
artists
"
:
data
}
...
@@ -132,14 +141,16 @@ class SubsonicViewSet(viewsets.GenericViewSet):
...
@@ -132,14 +141,16 @@ class SubsonicViewSet(viewsets.GenericViewSet):
@list_route
(
methods
=
[
"
get
"
,
"
post
"
],
url_name
=
"
get_indexes
"
,
url_path
=
"
getIndexes
"
)
@list_route
(
methods
=
[
"
get
"
,
"
post
"
],
url_name
=
"
get_indexes
"
,
url_path
=
"
getIndexes
"
)
def
get_indexes
(
self
,
request
,
*
args
,
**
kwargs
):
def
get_indexes
(
self
,
request
,
*
args
,
**
kwargs
):
artists
=
music_models
.
Artist
.
objects
.
all
()
artists
=
music_models
.
Artist
.
objects
.
all
().
playable_by
(
utils
.
get_actor_from_request
(
request
)
)
data
=
serializers
.
GetArtistsSerializer
(
artists
).
data
data
=
serializers
.
GetArtistsSerializer
(
artists
).
data
payload
=
{
"
indexes
"
:
data
}
payload
=
{
"
indexes
"
:
data
}
return
response
.
Response
(
payload
,
status
=
200
)
return
response
.
Response
(
payload
,
status
=
200
)
@list_route
(
methods
=
[
"
get
"
,
"
post
"
],
url_name
=
"
get_artist
"
,
url_path
=
"
getArtist
"
)
@list_route
(
methods
=
[
"
get
"
,
"
post
"
],
url_name
=
"
get_artist
"
,
url_path
=
"
getArtist
"
)
@find_object
(
music_models
.
Artist
.
objects
.
all
())
@find_object
(
music_models
.
Artist
.
objects
.
all
()
,
filter_playable
=
True
)
def
get_artist
(
self
,
request
,
*
args
,
**
kwargs
):
def
get_artist
(
self
,
request
,
*
args
,
**
kwargs
):
artist
=
kwargs
.
pop
(
"
obj
"
)
artist
=
kwargs
.
pop
(
"
obj
"
)
data
=
serializers
.
GetArtistSerializer
(
artist
).
data
data
=
serializers
.
GetArtistSerializer
(
artist
).
data
...
@@ -148,7 +159,7 @@ class SubsonicViewSet(viewsets.GenericViewSet):
...
@@ -148,7 +159,7 @@ class SubsonicViewSet(viewsets.GenericViewSet):
return
response
.
Response
(
payload
,
status
=
200
)
return
response
.
Response
(
payload
,
status
=
200
)
@list_route
(
methods
=
[
"
get
"
,
"
post
"
],
url_name
=
"
get_song
"
,
url_path
=
"
getSong
"
)
@list_route
(
methods
=
[
"
get
"
,
"
post
"
],
url_name
=
"
get_song
"
,
url_path
=
"
getSong
"
)
@find_object
(
music_models
.
Track
.
objects
.
all
())
@find_object
(
music_models
.
Track
.
objects
.
all
()
,
filter_playable
=
True
)
def
get_song
(
self
,
request
,
*
args
,
**
kwargs
):
def
get_song
(
self
,
request
,
*
args
,
**
kwargs
):
track
=
kwargs
.
pop
(
"
obj
"
)
track
=
kwargs
.
pop
(
"
obj
"
)
data
=
serializers
.
GetSongSerializer
(
track
).
data
data
=
serializers
.
GetSongSerializer
(
track
).
data
...
@@ -159,14 +170,16 @@ class SubsonicViewSet(viewsets.GenericViewSet):
...
@@ -159,14 +170,16 @@ class SubsonicViewSet(viewsets.GenericViewSet):
@list_route
(
@list_route
(
methods
=
[
"
get
"
,
"
post
"
],
url_name
=
"
get_artist_info2
"
,
url_path
=
"
getArtistInfo2
"
methods
=
[
"
get
"
,
"
post
"
],
url_name
=
"
get_artist_info2
"
,
url_path
=
"
getArtistInfo2
"
)
)
@find_object
(
music_models
.
Artist
.
objects
.
all
())
@find_object
(
music_models
.
Artist
.
objects
.
all
()
,
filter_playable
=
True
)
def
get_artist_info2
(
self
,
request
,
*
args
,
**
kwargs
):
def
get_artist_info2
(
self
,
request
,
*
args
,
**
kwargs
):
payload
=
{
"
artist-info2
"
:
{}}
payload
=
{
"
artist-info2
"
:
{}}
return
response
.
Response
(
payload
,
status
=
200
)
return
response
.
Response
(
payload
,
status
=
200
)
@list_route
(
methods
=
[
"
get
"
,
"
post
"
],
url_name
=
"
get_album
"
,
url_path
=
"
getAlbum
"
)
@list_route
(
methods
=
[
"
get
"
,
"
post
"
],
url_name
=
"
get_album
"
,
url_path
=
"
getAlbum
"
)
@find_object
(
music_models
.
Album
.
objects
.
select_related
(
"
artist
"
))
@find_object
(
music_models
.
Album
.
objects
.
select_related
(
"
artist
"
),
filter_playable
=
True
)
def
get_album
(
self
,
request
,
*
args
,
**
kwargs
):
def
get_album
(
self
,
request
,
*
args
,
**
kwargs
):
album
=
kwargs
.
pop
(
"
obj
"
)
album
=
kwargs
.
pop
(
"
obj
"
)
data
=
serializers
.
GetAlbumSerializer
(
album
).
data
data
=
serializers
.
GetAlbumSerializer
(
album
).
data
...
@@ -174,7 +187,7 @@ class SubsonicViewSet(viewsets.GenericViewSet):
...
@@ -174,7 +187,7 @@ class SubsonicViewSet(viewsets.GenericViewSet):
return
response
.
Response
(
payload
,
status
=
200
)
return
response
.
Response
(
payload
,
status
=
200
)
@list_route
(
methods
=
[
"
get
"
,
"
post
"
],
url_name
=
"
stream
"
,
url_path
=
"
stream
"
)
@list_route
(
methods
=
[
"
get
"
,
"
post
"
],
url_name
=
"
stream
"
,
url_path
=
"
stream
"
)
@find_object
(
music_models
.
Track
.
objects
.
all
())
@find_object
(
music_models
.
Track
.
objects
.
all
()
,
filter_playable
=
True
)
def
stream
(
self
,
request
,
*
args
,
**
kwargs
):
def
stream
(
self
,
request
,
*
args
,
**
kwargs
):
track
=
kwargs
.
pop
(
"
obj
"
)
track
=
kwargs
.
pop
(
"
obj
"
)
queryset
=
track
.
uploads
.
select_related
(
"
track__album__artist
"
,
"
track__artist
"
)
queryset
=
track
.
uploads
.
select_related
(
"
track__album__artist
"
,
"
track__artist
"
)
...
@@ -221,6 +234,9 @@ class SubsonicViewSet(viewsets.GenericViewSet):
...
@@ -221,6 +234,9 @@ class SubsonicViewSet(viewsets.GenericViewSet):
data
=
request
.
GET
or
request
.
POST
data
=
request
.
GET
or
request
.
POST
filterset
=
filters
.
AlbumList2FilterSet
(
data
,
queryset
=
queryset
)
filterset
=
filters
.
AlbumList2FilterSet
(
data
,
queryset
=
queryset
)
queryset
=
filterset
.
qs
queryset
=
filterset
.
qs
actor
=
utils
.
get_actor_from_request
(
request
)
queryset
=
queryset
.
playable_by
(
actor
)
try
:
try
:
offset
=
int
(
data
[
"
offset
"
])
offset
=
int
(
data
[
"
offset
"
])
except
(
TypeError
,
KeyError
,
ValueError
):
except
(
TypeError
,
KeyError
,
ValueError
):
...
@@ -240,6 +256,7 @@ class SubsonicViewSet(viewsets.GenericViewSet):
...
@@ -240,6 +256,7 @@ class SubsonicViewSet(viewsets.GenericViewSet):
def
search3
(
self
,
request
,
*
args
,
**
kwargs
):
def
search3
(
self
,
request
,
*
args
,
**
kwargs
):
data
=
request
.
GET
or
request
.
POST
data
=
request
.
GET
or
request
.
POST
query
=
str
(
data
.
get
(
"
query
"
,
""
)).
replace
(
"
*
"
,
""
)
query
=
str
(
data
.
get
(
"
query
"
,
""
)).
replace
(
"
*
"
,
""
)
actor
=
utils
.
get_actor_from_request
(
request
)
conf
=
[
conf
=
[
{
{
"
subsonic
"
:
"
artist
"
,
"
subsonic
"
:
"
artist
"
,
...
@@ -292,6 +309,7 @@ class SubsonicViewSet(viewsets.GenericViewSet):
...
@@ -292,6 +309,7 @@ class SubsonicViewSet(viewsets.GenericViewSet):
queryset
=
c
[
"
queryset
"
].
filter
(
queryset
=
c
[
"
queryset
"
].
filter
(
utils
.
get_query
(
query
,
c
[
"
search_fields
"
])
utils
.
get_query
(
query
,
c
[
"
search_fields
"
])
)
)
queryset
=
queryset
.
playable_by
(
actor
)
queryset
=
queryset
[
offset
:
offset
+
size
]
queryset
=
queryset
[
offset
:
offset
+
size
]
payload
[
"
searchResult3
"
][
c
[
"
subsonic
"
]]
=
c
[
"
serializer
"
](
queryset
)
payload
[
"
searchResult3
"
][
c
[
"
subsonic
"
]]
=
c
[
"
serializer
"
](
queryset
)
return
response
.
Response
(
payload
)
return
response
.
Response
(
payload
)
...
...
This diff is collapsed.
Click to expand it.
api/tests/subsonic/test_views.py
+
64
−
27
View file @
47aa209d
...
@@ -74,10 +74,13 @@ def test_ping(f, db, api_client):
...
@@ -74,10 +74,13 @@ def test_ping(f, db, api_client):
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
def
test_get_artists
(
f
,
db
,
logged_in_api_client
,
factories
):
def
test_get_artists
(
f
,
db
,
logged_in_api_client
,
factories
,
mocker
,
queryset_equal_queries
):
url
=
reverse
(
"
api:subsonic-get-artists
"
)
url
=
reverse
(
"
api:subsonic-get-artists
"
)
assert
url
.
endswith
(
"
getArtists
"
)
is
True
assert
url
.
endswith
(
"
getArtists
"
)
is
True
factories
[
"
music.Artist
"
].
create_batch
(
size
=
10
)
factories
[
"
music.Artist
"
].
create_batch
(
size
=
3
,
playable
=
True
)
playable_by
=
mocker
.
spy
(
music_models
.
ArtistQuerySet
,
"
playable_by
"
)
expected
=
{
expected
=
{
"
artists
"
:
serializers
.
GetArtistsSerializer
(
"
artists
"
:
serializers
.
GetArtistsSerializer
(
music_models
.
Artist
.
objects
.
all
()
music_models
.
Artist
.
objects
.
all
()
...
@@ -87,19 +90,25 @@ def test_get_artists(f, db, logged_in_api_client, factories):
...
@@ -87,19 +90,25 @@ def test_get_artists(f, db, logged_in_api_client, factories):
assert
response
.
status_code
==
200
assert
response
.
status_code
==
200
assert
response
.
data
==
expected
assert
response
.
data
==
expected
playable_by
.
assert_called_once_with
(
music_models
.
Artist
.
objects
.
all
(),
None
)
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
def
test_get_artist
(
f
,
db
,
logged_in_api_client
,
factories
):
def
test_get_artist
(
f
,
db
,
logged_in_api_client
,
factories
,
mocker
,
queryset_equal_queries
):
url
=
reverse
(
"
api:subsonic-get-artist
"
)
url
=
reverse
(
"
api:subsonic-get-artist
"
)
assert
url
.
endswith
(
"
getArtist
"
)
is
True
assert
url
.
endswith
(
"
getArtist
"
)
is
True
artist
=
factories
[
"
music.Artist
"
]()
artist
=
factories
[
"
music.Artist
"
](
playable
=
True
)
factories
[
"
music.Album
"
].
create_batch
(
size
=
3
,
artist
=
artist
)
factories
[
"
music.Album
"
].
create_batch
(
size
=
3
,
artist
=
artist
,
playable
=
True
)
playable_by
=
mocker
.
spy
(
music_models
.
ArtistQuerySet
,
"
playable_by
"
)
expected
=
{
"
artist
"
:
serializers
.
GetArtistSerializer
(
artist
).
data
}
expected
=
{
"
artist
"
:
serializers
.
GetArtistSerializer
(
artist
).
data
}
response
=
logged_in_api_client
.
get
(
url
,
{
"
id
"
:
artist
.
pk
})
response
=
logged_in_api_client
.
get
(
url
,
{
"
id
"
:
artist
.
pk
})
assert
response
.
status_code
==
200
assert
response
.
status_code
==
200
assert
response
.
data
==
expected
assert
response
.
data
==
expected
playable_by
.
assert_called_once_with
(
music_models
.
Artist
.
objects
.
all
(),
None
)
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
...
@@ -114,10 +123,13 @@ def test_get_invalid_artist(f, db, logged_in_api_client, factories):
...
@@ -114,10 +123,13 @@ def test_get_invalid_artist(f, db, logged_in_api_client, factories):
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
def
test_get_artist_info2
(
f
,
db
,
logged_in_api_client
,
factories
):
def
test_get_artist_info2
(
f
,
db
,
logged_in_api_client
,
factories
,
mocker
,
queryset_equal_queries
):
url
=
reverse
(
"
api:subsonic-get-artist-info2
"
)
url
=
reverse
(
"
api:subsonic-get-artist-info2
"
)
assert
url
.
endswith
(
"
getArtistInfo2
"
)
is
True
assert
url
.
endswith
(
"
getArtistInfo2
"
)
is
True
artist
=
factories
[
"
music.Artist
"
]()
artist
=
factories
[
"
music.Artist
"
](
playable
=
True
)
playable_by
=
mocker
.
spy
(
music_models
.
ArtistQuerySet
,
"
playable_by
"
)
expected
=
{
"
artist-info2
"
:
{}}
expected
=
{
"
artist-info2
"
:
{}}
response
=
logged_in_api_client
.
get
(
url
,
{
"
id
"
:
artist
.
pk
})
response
=
logged_in_api_client
.
get
(
url
,
{
"
id
"
:
artist
.
pk
})
...
@@ -125,50 +137,62 @@ def test_get_artist_info2(f, db, logged_in_api_client, factories):
...
@@ -125,50 +137,62 @@ def test_get_artist_info2(f, db, logged_in_api_client, factories):
assert
response
.
status_code
==
200
assert
response
.
status_code
==
200
assert
response
.
data
==
expected
assert
response
.
data
==
expected
playable_by
.
assert_called_once_with
(
music_models
.
Artist
.
objects
.
all
(),
None
)
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
def
test_get_album
(
f
,
db
,
logged_in_api_client
,
factories
):
def
test_get_album
(
f
,
db
,
logged_in_api_client
,
factories
,
mocker
,
queryset_equal_queries
):
url
=
reverse
(
"
api:subsonic-get-album
"
)
url
=
reverse
(
"
api:subsonic-get-album
"
)
assert
url
.
endswith
(
"
getAlbum
"
)
is
True
assert
url
.
endswith
(
"
getAlbum
"
)
is
True
artist
=
factories
[
"
music.Artist
"
]()
artist
=
factories
[
"
music.Artist
"
]()
album
=
factories
[
"
music.Album
"
](
artist
=
artist
)
album
=
factories
[
"
music.Album
"
](
artist
=
artist
)
factories
[
"
music.Track
"
].
create_batch
(
size
=
3
,
album
=
album
)
factories
[
"
music.Track
"
].
create_batch
(
size
=
3
,
album
=
album
,
playable
=
True
)
playable_by
=
mocker
.
spy
(
music_models
.
AlbumQuerySet
,
"
playable_by
"
)
expected
=
{
"
album
"
:
serializers
.
GetAlbumSerializer
(
album
).
data
}
expected
=
{
"
album
"
:
serializers
.
GetAlbumSerializer
(
album
).
data
}
response
=
logged_in_api_client
.
get
(
url
,
{
"
f
"
:
f
,
"
id
"
:
album
.
pk
})
response
=
logged_in_api_client
.
get
(
url
,
{
"
f
"
:
f
,
"
id
"
:
album
.
pk
})
assert
response
.
status_code
==
200
assert
response
.
status_code
==
200
assert
response
.
data
==
expected
assert
response
.
data
==
expected
playable_by
.
assert_called_once_with
(
music_models
.
Album
.
objects
.
select_related
(
"
artist
"
),
None
)
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
def
test_get_song
(
f
,
db
,
logged_in_api_client
,
factories
):
def
test_get_song
(
f
,
db
,
logged_in_api_client
,
factories
,
mocker
,
queryset_equal_queries
):
url
=
reverse
(
"
api:subsonic-get-song
"
)
url
=
reverse
(
"
api:subsonic-get-song
"
)
assert
url
.
endswith
(
"
getSong
"
)
is
True
assert
url
.
endswith
(
"
getSong
"
)
is
True
artist
=
factories
[
"
music.Artist
"
]()
artist
=
factories
[
"
music.Artist
"
]()
album
=
factories
[
"
music.Album
"
](
artist
=
artist
)
album
=
factories
[
"
music.Album
"
](
artist
=
artist
)
track
=
factories
[
"
music.Track
"
](
album
=
album
)
track
=
factories
[
"
music.Track
"
](
album
=
album
,
playable
=
True
)
upload
=
factories
[
"
music.Upload
"
](
track
=
track
)
upload
=
factories
[
"
music.Upload
"
](
track
=
track
)
playable_by
=
mocker
.
spy
(
music_models
.
TrackQuerySet
,
"
playable_by
"
)
response
=
logged_in_api_client
.
get
(
url
,
{
"
f
"
:
f
,
"
id
"
:
track
.
pk
})
response
=
logged_in_api_client
.
get
(
url
,
{
"
f
"
:
f
,
"
id
"
:
track
.
pk
})
assert
response
.
status_code
==
200
assert
response
.
status_code
==
200
assert
response
.
data
==
{
assert
response
.
data
==
{
"
song
"
:
serializers
.
get_track_data
(
track
.
album
,
track
,
upload
)
"
song
"
:
serializers
.
get_track_data
(
track
.
album
,
track
,
upload
)
}
}
playable_by
.
assert_called_once_with
(
music_models
.
Track
.
objects
.
all
(),
None
)
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
def
test_stream
(
f
,
db
,
logged_in_api_client
,
factories
,
mocker
):
def
test_stream
(
f
,
db
,
logged_in_api_client
,
factories
,
mocker
,
queryset_equal_queries
):
url
=
reverse
(
"
api:subsonic-stream
"
)
url
=
reverse
(
"
api:subsonic-stream
"
)
mocked_serve
=
mocker
.
spy
(
music_views
,
"
handle_serve
"
)
mocked_serve
=
mocker
.
spy
(
music_views
,
"
handle_serve
"
)
assert
url
.
endswith
(
"
stream
"
)
is
True
assert
url
.
endswith
(
"
stream
"
)
is
True
artist
=
factories
[
"
music.Artist
"
]()
upload
=
factories
[
"
music.Upload
"
](
playable
=
True
)
album
=
factories
[
"
music.Album
"
](
artist
=
artist
)
playable_by
=
mocker
.
spy
(
music_models
.
TrackQuerySet
,
"
playable_by
"
)
track
=
factories
[
"
music.Track
"
](
album
=
album
)
response
=
logged_in_api_client
.
get
(
url
,
{
"
f
"
:
f
,
"
id
"
:
upload
.
track
.
pk
})
upload
=
factories
[
"
music.Upload
"
](
track
=
track
)
response
=
logged_in_api_client
.
get
(
url
,
{
"
f
"
:
f
,
"
id
"
:
track
.
pk
})
mocked_serve
.
assert_called_once_with
(
upload
=
upload
,
user
=
logged_in_api_client
.
user
)
mocked_serve
.
assert_called_once_with
(
upload
=
upload
,
user
=
logged_in_api_client
.
user
)
assert
response
.
status_code
==
200
assert
response
.
status_code
==
200
playable_by
.
assert_called_once_with
(
music_models
.
Track
.
objects
.
all
(),
None
)
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
...
@@ -231,25 +255,30 @@ def test_get_starred(f, db, logged_in_api_client, factories):
...
@@ -231,25 +255,30 @@ def test_get_starred(f, db, logged_in_api_client, factories):
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
def
test_get_album_list2
(
f
,
db
,
logged_in_api_client
,
factories
):
def
test_get_album_list2
(
f
,
db
,
logged_in_api_client
,
factories
,
mocker
,
queryset_equal_queries
):
url
=
reverse
(
"
api:subsonic-get-album-list2
"
)
url
=
reverse
(
"
api:subsonic-get-album-list2
"
)
assert
url
.
endswith
(
"
getAlbumList2
"
)
is
True
assert
url
.
endswith
(
"
getAlbumList2
"
)
is
True
album1
=
factories
[
"
music.Album
"
]()
album1
=
factories
[
"
music.Album
"
](
playable
=
True
)
album2
=
factories
[
"
music.Album
"
]()
album2
=
factories
[
"
music.Album
"
](
playable
=
True
)
factories
[
"
music.Album
"
]()
playable_by
=
mocker
.
spy
(
music_models
.
AlbumQuerySet
,
"
playable_by
"
)
response
=
logged_in_api_client
.
get
(
url
,
{
"
f
"
:
f
,
"
type
"
:
"
newest
"
})
response
=
logged_in_api_client
.
get
(
url
,
{
"
f
"
:
f
,
"
type
"
:
"
newest
"
})
assert
response
.
status_code
==
200
assert
response
.
status_code
==
200
assert
response
.
data
==
{
assert
response
.
data
==
{
"
albumList2
"
:
{
"
album
"
:
serializers
.
get_album_list2_data
([
album2
,
album1
])}
"
albumList2
"
:
{
"
album
"
:
serializers
.
get_album_list2_data
([
album2
,
album1
])}
}
}
playable_by
.
assert_called_once
()
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
def
test_get_album_list2_pagination
(
f
,
db
,
logged_in_api_client
,
factories
):
def
test_get_album_list2_pagination
(
f
,
db
,
logged_in_api_client
,
factories
):
url
=
reverse
(
"
api:subsonic-get-album-list2
"
)
url
=
reverse
(
"
api:subsonic-get-album-list2
"
)
assert
url
.
endswith
(
"
getAlbumList2
"
)
is
True
assert
url
.
endswith
(
"
getAlbumList2
"
)
is
True
album1
=
factories
[
"
music.Album
"
]()
album1
=
factories
[
"
music.Album
"
](
playable
=
True
)
factories
[
"
music.Album
"
]()
factories
[
"
music.Album
"
](
playable
=
True
)
response
=
logged_in_api_client
.
get
(
response
=
logged_in_api_client
.
get
(
url
,
{
"
f
"
:
f
,
"
type
"
:
"
newest
"
,
"
size
"
:
1
,
"
offset
"
:
1
}
url
,
{
"
f
"
:
f
,
"
type
"
:
"
newest
"
,
"
size
"
:
1
,
"
offset
"
:
1
}
)
)
...
@@ -264,12 +293,15 @@ def test_get_album_list2_pagination(f, db, logged_in_api_client, factories):
...
@@ -264,12 +293,15 @@ def test_get_album_list2_pagination(f, db, logged_in_api_client, factories):
def
test_search3
(
f
,
db
,
logged_in_api_client
,
factories
):
def
test_search3
(
f
,
db
,
logged_in_api_client
,
factories
):
url
=
reverse
(
"
api:subsonic-search3
"
)
url
=
reverse
(
"
api:subsonic-search3
"
)
assert
url
.
endswith
(
"
search3
"
)
is
True
assert
url
.
endswith
(
"
search3
"
)
is
True
artist
=
factories
[
"
music.Artist
"
](
name
=
"
testvalue
"
)
artist
=
factories
[
"
music.Artist
"
](
name
=
"
testvalue
"
,
playable
=
True
)
factories
[
"
music.Artist
"
](
name
=
"
nope
"
)
factories
[
"
music.Artist
"
](
name
=
"
nope
"
)
album
=
factories
[
"
music.Album
"
](
title
=
"
testvalue
"
)
factories
[
"
music.Artist
"
](
name
=
"
nope2
"
,
playable
=
True
)
album
=
factories
[
"
music.Album
"
](
title
=
"
testvalue
"
,
playable
=
True
)
factories
[
"
music.Album
"
](
title
=
"
nope
"
)
factories
[
"
music.Album
"
](
title
=
"
nope
"
)
track
=
factories
[
"
music.Track
"
](
title
=
"
testvalue
"
)
factories
[
"
music.Album
"
](
title
=
"
nope2
"
,
playable
=
True
)
track
=
factories
[
"
music.Track
"
](
title
=
"
testvalue
"
,
playable
=
True
)
factories
[
"
music.Track
"
](
title
=
"
nope
"
)
factories
[
"
music.Track
"
](
title
=
"
nope
"
)
factories
[
"
music.Track
"
](
title
=
"
nope2
"
,
playable
=
True
)
response
=
logged_in_api_client
.
get
(
url
,
{
"
f
"
:
f
,
"
query
"
:
"
testval
"
})
response
=
logged_in_api_client
.
get
(
url
,
{
"
f
"
:
f
,
"
query
"
:
"
testval
"
})
...
@@ -385,20 +417,25 @@ def test_get_music_folders(f, db, logged_in_api_client, factories):
...
@@ -385,20 +417,25 @@ def test_get_music_folders(f, db, logged_in_api_client, factories):
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
@pytest.mark.parametrize
(
"
f
"
,
[
"
xml
"
,
"
json
"
])
def
test_get_indexes
(
f
,
db
,
logged_in_api_client
,
factories
):
def
test_get_indexes
(
f
,
db
,
logged_in_api_client
,
factories
,
mocker
,
queryset_equal_queries
):
url
=
reverse
(
"
api:subsonic-get-indexes
"
)
url
=
reverse
(
"
api:subsonic-get-indexes
"
)
assert
url
.
endswith
(
"
getIndexes
"
)
is
True
assert
url
.
endswith
(
"
getIndexes
"
)
is
True
factories
[
"
music.Artist
"
].
create_batch
(
size
=
10
)
factories
[
"
music.Artist
"
].
create_batch
(
size
=
3
,
playable
=
True
)
expected
=
{
expected
=
{
"
indexes
"
:
serializers
.
GetArtistsSerializer
(
"
indexes
"
:
serializers
.
GetArtistsSerializer
(
music_models
.
Artist
.
objects
.
all
()
music_models
.
Artist
.
objects
.
all
()
).
data
).
data
}
}
playable_by
=
mocker
.
spy
(
music_models
.
ArtistQuerySet
,
"
playable_by
"
)
response
=
logged_in_api_client
.
get
(
url
)
response
=
logged_in_api_client
.
get
(
url
)
assert
response
.
status_code
==
200
assert
response
.
status_code
==
200
assert
response
.
data
==
expected
assert
response
.
data
==
expected
playable_by
.
assert_called_once_with
(
music_models
.
Artist
.
objects
.
all
(),
None
)
def
test_get_cover_art_album
(
factories
,
logged_in_api_client
):
def
test_get_cover_art_album
(
factories
,
logged_in_api_client
):
url
=
reverse
(
"
api:subsonic-get-cover-art
"
)
url
=
reverse
(
"
api:subsonic-get-cover-art
"
)
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment