Skip to content

Commit

Permalink
Some fixes for Windows support (especially for tests)
Browse files Browse the repository at this point in the history
The main motive here isn't full Windows support per, but being
able to run tests on Windows, as this is my main platform.
Booting a VM just to run tests is cumbersome.
  • Loading branch information
spl0k committed Nov 8, 2020
1 parent 7d18251 commit 5c46c96
Show file tree
Hide file tree
Showing 14 changed files with 156 additions and 123 deletions.
37 changes: 19 additions & 18 deletions supysonic/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,25 +143,26 @@ def set_fileobj(self, key):
>>> with cache.set_fileobj(key) as fp:
... json.dump(some_data, fp)
"""
f = tempfile.NamedTemporaryFile(
dir=self._cache_dir, suffix=".part", delete=False
)
try:
with tempfile.NamedTemporaryFile(
dir=self._cache_dir, suffix=".part", delete=True
) as f:
yield f

# seek to end and get position to get filesize
f.seek(0, 2)
size = f.tell()

with self._lock:
if self._auto_prune:
self._make_space(size, key=key)
os.replace(f.name, self._filepath(key))
self._record_file(key, size)
except OSError as e:
# Ignore error from trying to delete the renamed temp file
if e.errno != errno.ENOENT:
raise
yield f

# seek to end and get position to get filesize
f.seek(0, 2)
size = f.tell()
f.close()

with self._lock:
if self._auto_prune:
self._make_space(size, key=key)
os.replace(f.name, self._filepath(key))
self._record_file(key, size)
except:
f.close()
os.remove(f.name)
raise

def set(self, key, value):
"""Set a literal value into the cache and return its path"""
Expand Down
7 changes: 5 additions & 2 deletions supysonic/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
# This file is part of Supysonic.
# Supysonic is a Python implementation of the Subsonic server API.
#
# Copyright (C) 2013-2019 Alban 'spl0k' Féron
# Copyright (C) 2013-2020 Alban 'spl0k' Féron
# 2017 Óscar García Amor
#
# Distributed under terms of the GNU AGPLv3 license.

import os
import sys
import tempfile

from configparser import RawConfigParser
Expand Down Expand Up @@ -39,7 +40,9 @@ class DefaultConfig(object):
"mount_api": True,
}
DAEMON = {
"socket": os.path.join(tempdir, "supysonic.sock"),
"socket": r"\\.\pipe\supysonic"
if sys.platform == "win32"
else os.path.join(tempdir, "supysonic.sock"),
"run_watcher": True,
"wait_delay": 5,
"jukebox_command": None,
Expand Down
107 changes: 64 additions & 43 deletions tests/api/test_radio.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,25 @@ def test_create_radio_station(self):
self._make_request(
"createInternetRadioStation",
{"u": "bob", "p": "B0b", "username": "alice"},
error=50
error=50,
)

# check params
self._make_request("createInternetRadioStation", error=10)
self._make_request("createInternetRadioStation", {"streamUrl": "missingName"}, error=10)
self._make_request("createInternetRadioStation", {"name": "missing stream"}, error=10)
self._make_request(
"createInternetRadioStation", {"streamUrl": "missingName"}, error=10
)
self._make_request(
"createInternetRadioStation", {"name": "missing stream"}, error=10
)

# create w/ required fields
stream_url = "http://example.com/radio/create"
name = "radio station"

self._make_request("createInternetRadioStation", {
"streamUrl": stream_url,
"name": name,
})
self._make_request(
"createInternetRadioStation", {"streamUrl": stream_url, "name": name}
)

# the correct value is 2 because _make_request uses GET then POST
self.assertRadioStationCountEqual(2)
Expand All @@ -66,11 +69,10 @@ def test_create_radio_station(self):
name = "radio station1"
homepage_url = "http://example.com/home"

self._make_request("createInternetRadioStation", {
"streamUrl": stream_url,
"name": name,
"homepageUrl": homepage_url,
})
self._make_request(
"createInternetRadioStation",
{"streamUrl": stream_url, "name": name, "homepageUrl": homepage_url},
)

# the correct value is 2 because _make_request uses GET then POST
self.assertRadioStationCountEqual(2)
Expand All @@ -83,7 +85,7 @@ def test_update_radio_station(self):
self._make_request(
"updateInternetRadioStation",
{"u": "bob", "p": "B0b", "username": "alice"},
error=50
error=50,
)

# test data
Expand All @@ -107,67 +109,86 @@ def test_update_radio_station(self):
)

# check params
self._make_request("updateInternetRadioStation", {
"id": station.id, "homepageUrl": "missing required params",
}, error=10)
self._make_request("updateInternetRadioStation", {
"id": station.id, "name": "missing streamUrl",
}, error=10)
self._make_request("updateInternetRadioStation", {
"id": station.id, "streamUrl": "missing name",
}, error=10)
self._make_request(
"updateInternetRadioStation",
{"id": station.id, "homepageUrl": "missing required params"},
error=10,
)
self._make_request(
"updateInternetRadioStation",
{"id": station.id, "name": "missing streamUrl"},
error=10,
)
self._make_request(
"updateInternetRadioStation",
{"id": station.id, "streamUrl": "missing name"},
error=10,
)

# update the record w/ required fields
self._make_request("updateInternetRadioStation", {
"id": station.id,
"streamUrl": update["stream_url"],
"name": update["name"],
})
self._make_request(
"updateInternetRadioStation",
{
"id": station.id,
"streamUrl": update["stream_url"],
"name": update["name"],
},
)

with db_session:
rs_update = RadioStation[station.id]

self.assertRadioStationEquals(rs_update, update["stream_url"], update["name"], test["homepage_url"])
self.assertRadioStationEquals(
rs_update, update["stream_url"], update["name"], test["homepage_url"]
)

# update the record w/ all fields
self._make_request("updateInternetRadioStation", {
"id": station.id,
"streamUrl": update["stream_url"],
"name": update["name"],
"homepageUrl": update["homepage_url"],
})
self._make_request(
"updateInternetRadioStation",
{
"id": station.id,
"streamUrl": update["stream_url"],
"name": update["name"],
"homepageUrl": update["homepage_url"],
},
)

with db_session:
rs_update = RadioStation[station.id]

self.assertRadioStationEquals(rs_update, update["stream_url"], update["name"], update["homepage_url"])
self.assertRadioStationEquals(
rs_update, update["stream_url"], update["name"], update["homepage_url"]
)

def test_delete_radio_station(self):
# test for non-admin access
self._make_request(
"deleteInternetRadioStation",
{"u": "bob", "p": "B0b", "username": "alice"},
error=50
error=50,
)

# check params
self._make_request("deleteInternetRadioStation", error=10)
self._make_request("deleteInternetRadioStation", {"id": 1}, error=0)
self._make_request("deleteInternetRadioStation", {"id": str(uuid.uuid4())}, error=70)
self._make_request(
"deleteInternetRadioStation", {"id": str(uuid.uuid4())}, error=70
)

# delete
with db_session:
station = RadioStation(
stream_url="http://example.com/radio/delete",
name="Radio Delete",
homepage_url="http://example.com/update"
homepage_url="http://example.com/update",
)

self._make_request("deleteInternetRadioStation", {"id": station.id}, skip_post=True)
self._make_request(
"deleteInternetRadioStation", {"id": station.id}, skip_post=True
)

self.assertRadioStationCountEqual(0)


def test_get_radio_stations(self):
test_range = 3
with db_session:
Expand All @@ -180,7 +201,9 @@ def test_get_radio_stations(self):

# verify happy path is clean
self.assertRadioStationCountEqual(test_range)
rv, child = self._make_request("getInternetRadioStations", tag="internetRadioStations")
rv, child = self._make_request(
"getInternetRadioStations", tag="internetRadioStations"
)
self.assertEqual(len(child), test_range)
# This order is guaranteed to work because the api returns in order by name.
# Test data is sequential by design.
Expand All @@ -190,7 +213,6 @@ def test_get_radio_stations(self):
self.assertTrue(station.get("name").endswith("Radio {}".format(x)))
self.assertTrue(station.get("homePageUrl").endswith("update-{}".format(x)))


# test for non-admin access
rv, child = self._make_request(
"getInternetRadioStations",
Expand All @@ -199,4 +221,3 @@ def test_get_radio_stations(self):
)

self.assertEqual(len(child), test_range)

12 changes: 10 additions & 2 deletions tests/api/test_transcoding.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#!/usr/bin/env python
# coding: utf-8
#
# This file is part of Supysonic.
# Supysonic is a Python implementation of the Subsonic server API.
#
# Copyright (C) 2017-2018 Alban 'spl0k' Féron
# Copyright (C) 2017-2020 Alban 'spl0k' Féron
#
# Distributed under terms of the GNU AGPLv3 license.

import unittest
import sys

from pony.orm import db_session

Expand Down Expand Up @@ -46,11 +46,19 @@ def _stream(self, **kwargs):
def test_no_transcoding_available(self):
self._make_request("stream", {"id": self.trackid, "format": "wat"}, error=0)

@unittest.skipIf(
sys.platform == "win32",
"Can't test transcoding on Windows because of a lack of simple commandline tools",
)
def test_direct_transcode(self):
rv = self._stream(maxBitRate=96, estimateContentLength="true")
self.assertIn("tests/assets/folder/silence.mp3", rv.data)
self.assertTrue(rv.data.endswith("96"))

@unittest.skipIf(
sys.platform == "win32",
"Can't test transcoding on Windows because of a lack of simple commandline tools",
)
def test_decode_encode(self):
rv = self._stream(format="cat")
self.assertEqual(rv.data, "Pushing out some mp3 data...")
Expand Down
1 change: 0 additions & 1 deletion tests/assets/formats/silence.mp3

This file was deleted.

Binary file added tests/assets/formats/silence.mp3
Binary file not shown.
Loading

0 comments on commit 5c46c96

Please sign in to comment.