1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-12-23 01:16:18 +00:00

Test architecture unifying

This commit is contained in:
spl0k 2017-11-17 23:26:25 +01:00
parent 74ce600e03
commit 2cf6d01489
9 changed files with 149 additions and 158 deletions

View File

@ -11,9 +11,7 @@
import unittest import unittest
import base, managers, api import base, managers, api, frontend
from .test_frontend import FrontendTestCase
def suite(): def suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
@ -21,7 +19,6 @@ def suite():
suite.addTest(managers.suite()) suite.addTest(managers.suite())
suite.addTest(base.suite()) suite.addTest(base.suite())
suite.addTest(api.suite()) suite.addTest(api.suite())
suite.addTest(frontend.suite())
suite.addTest(unittest.makeSuite(FrontendTestCase))
return suite return suite

View File

@ -8,44 +8,27 @@
# #
# Distributed under terms of the GNU AGPLv3 license. # Distributed under terms of the GNU AGPLv3 license.
import unittest
import re import re
import sys
from lxml import etree from lxml import etree
from supysonic.managers.user import UserManager from supysonic.managers.user import UserManager
from .appmock import AppMock from ..testbase import TestBase
path_replace_regexp = re.compile(r'/(\w+)') path_replace_regexp = re.compile(r'/(\w+)')
NS = 'http://subsonic.org/restapi' NS = 'http://subsonic.org/restapi'
NSMAP = { 'sub': NS } NSMAP = { 'sub': NS }
class ApiTestBase(unittest.TestCase): class ApiTestBase(TestBase):
__module_to_test__ = 'supysonic.api'
def setUp(self): def setUp(self):
app_mock = AppMock() super(ApiTestBase, self).setUp()
self.app = app_mock.app
self.store = app_mock.store
self.client = self.app.test_client()
sys.modules['supysonic.web'] = app_mock
import supysonic.api
UserManager.add(self.store, 'alice', 'Alic3', 'test@example.com', True)
UserManager.add(self.store, 'bob', 'B0b', 'bob@example.com', False)
xsd = etree.parse('tests/assets/subsonic-rest-api-1.8.0.xsd') xsd = etree.parse('tests/assets/subsonic-rest-api-1.8.0.xsd')
self.schema = etree.XMLSchema(xsd) self.schema = etree.XMLSchema(xsd)
def tearDown(self):
self.store.close()
to_unload = [ m for m in sys.modules if m.startswith('supysonic') ]
for m in to_unload:
del sys.modules[m]
def _find(self, xml, path): def _find(self, xml, path):
""" """
Helper method that insert the namespace in ElementPath 'path' Helper method that insert the namespace in ElementPath 'path'

View File

@ -12,35 +12,14 @@
import base64 import base64
import binascii import binascii
import io
import simplejson import simplejson
import sys
import unittest
from flask import request
from xml.etree import ElementTree from xml.etree import ElementTree
from supysonic.managers.user import UserManager from ..testbase import TestBase
from .appmock import AppMock class ApiSetupTestCase(TestBase):
__module_to_test__ = 'supysonic.api'
class ApiSetupTestCase(unittest.TestCase):
def setUp(self):
app_mock = AppMock()
self.app = app_mock.app
self.store = app_mock.store
self.client = self.app.test_client()
sys.modules['supysonic.web'] = app_mock
import supysonic.api
UserManager.add(self.store, 'alice', 'Alic3', 'test@example.com', True)
def tearDown(self):
self.store.close()
to_unload = [ m for m in sys.modules if m.startswith('supysonic') ]
for m in to_unload:
del sys.modules[m]
def __basic_auth_get(self, username, password): def __basic_auth_get(self, username, password):
hashed = base64.b64encode('{}:{}'.format(username, password)) hashed = base64.b64encode('{}:{}'.format(username, password))

View File

@ -14,7 +14,7 @@ import unittest, sys
import simplejson import simplejson
from xml.etree import ElementTree from xml.etree import ElementTree
from .appmock import AppMock from ..appmock import AppMock
class ResponseHelperBaseCase(unittest.TestCase): class ResponseHelperBaseCase(unittest.TestCase):
def setUp(self): def setUp(self):

View File

@ -14,8 +14,9 @@ from supysonic.db import get_store
class AppMock(object): class AppMock(object):
def __init__(self, with_store = True): def __init__(self, with_store = True):
self.app = Flask(__name__) self.app = Flask(__name__, template_folder = '../supysonic/templates')
self.app.testing = True self.app.testing = True
self.app.secret_key = 'Testing secret'
if with_store: if with_store:
self.store = get_store('sqlite:') self.store = get_store('sqlite:')

View File

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# This file is part of Supysonic.
# Supysonic is a Python implementation of the Subsonic server API.
#
# Copyright (C) 2017 Alban 'spl0k' Féron
#
# Distributed under terms of the GNU AGPLv3 license.
import unittest
from .test_login import LoginTestCase
def suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(LoginTestCase))
return suite

View File

@ -0,0 +1,78 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# This file is part of Supysonic.
# Supysonic is a Python implementation of the Subsonic server API.
#
# Copyright (C) 2013-2017 Alban 'spl0k' Féron
# 2017 Óscar García Amor
#
# Distributed under terms of the GNU AGPLv3 license.
import uuid
from supysonic.db import User
from ..testbase import TestBase
class LoginTestCase(TestBase):
__module_to_test__ = 'supysonic.frontend'
def test_unauthorized_request(self):
# Unauthorized request
rv = self.client.get('/', follow_redirects=True)
self.assertIn('Please login', rv.data)
def test_login_with_bad_data(self):
# Login with not blank user or password
rv = self.client.post('/user/login', data=dict(name='', password=''), follow_redirects=True)
self.assertIn('Missing user name', rv.data)
self.assertIn('Missing password', rv.data)
# Login with not valid user or password
rv = self.client.post('/user/login', data=dict(user='nonexistent', password='nonexistent'), follow_redirects=True)
self.assertIn('No such user', rv.data)
rv = self.client.post('/user/login', data=dict(user='alice', password='badpassword'), follow_redirects=True)
self.assertIn('Wrong password', rv.data)
def test_login_admin(self):
# Login with a valid admin user
rv = self.client.post('/user/login', data=dict(user='alice', password='Alic3'), follow_redirects=True)
self.assertIn('Logged in', rv.data)
self.assertIn('Users', rv.data)
self.assertIn('Folders', rv.data)
def test_login_non_admin(self):
# Login with a valid non-admin user
rv = self.client.post('/user/login', data=dict(user='bob', password='B0b'), follow_redirects=True)
self.assertIn('Logged in', rv.data)
# Non-admin user cannot acces to users and folders
self.assertNotIn('Users', rv.data)
self.assertNotIn('Folders', rv.data)
def test_root_with_valid_session(self):
# Root with valid session
with self.client.session_transaction() as sess:
sess['userid'] = self.store.find(User, User.name == 'alice').one().id
sess['username'] = 'alice'
rv = self.client.get('/', follow_redirects=True)
self.assertIn('alice', rv.data)
self.assertIn('Log out', rv.data)
self.assertIn('There\'s nothing much to see here.', rv.data)
def test_root_with_non_valid_session(self):
# Root with a no-valid session
with self.client.session_transaction() as sess:
sess['userid'] = uuid.uuid4()
sess['username'] = 'alice'
rv = self.client.get('/', follow_redirects=True)
self.assertIn('Please login', rv.data)
# Root with a no-valid user
with self.client.session_transaction() as sess:
sess['userid'] = self.store.find(User, User.name == 'alice').one().id
sess['username'] = 'nonexistent'
rv = self.client.get('/', follow_redirects=True)
self.assertIn('Please login', rv.data)
if __name__ == '__main__':
unittest.main()

View File

@ -1,105 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# This file is part of Supysonic.
# Supysonic is a Python implementation of the Subsonic server API.
#
# Copyright (C) 2013-2017 Alban 'spl0k' Féron
# 2017 Óscar García Amor
#
# Distributed under terms of the GNU AGPLv3 license.
from supysonic import db
from supysonic.managers.user import UserManager
import sys
import unittest
import uuid
# Create an empty sqlite database in memory
store = db.get_store("sqlite:")
# Read schema from file
with open('schema/sqlite.sql') as sql:
schema = sql.read()
# Create tables on memory database
for command in schema.split(';'):
store.execute(command)
# Create some users
UserManager.add(store, 'alice', 'alice', 'test@example.com', True)
UserManager.add(store, 'bob', 'bob', 'bob@example.com', False)
UserManager.add(store, 'charlie', 'charlie', 'charlie@example.com', False)
# Create a mockup of web
from flask import Flask
app = Flask(__name__, template_folder='../supysonic/templates')
class web():
app = app
store = store
sys.modules['supysonic.web'] = web()
# Import module and set app in test mode
import supysonic.frontend
app.secret_key = 'test-suite'
class FrontendTestCase(unittest.TestCase):
def setUp(self):
self.app = app.test_client()
def test_unauthorized_request(self):
# Unauthorized request
rv = self.app.get('/', follow_redirects=True)
self.assertIn('Please login', rv.data)
def test_login_with_bad_data(self):
# Login with not blank user or password
rv = self.app.post('/user/login', data=dict(name='', password=''), follow_redirects=True)
self.assertIn('Missing user name', rv.data)
self.assertIn('Missing password', rv.data)
# Login with not valid user or password
rv = self.app.post('/user/login', data=dict(user='nonexistent', password='nonexistent'), follow_redirects=True)
self.assertIn('No such user', rv.data)
rv = self.app.post('/user/login', data=dict(user='alice', password='badpassword'), follow_redirects=True)
self.assertIn('Wrong password', rv.data)
def test_login_admin(self):
# Login with a valid admin user
rv = self.app.post('/user/login', data=dict(user='alice', password='alice'), follow_redirects=True)
self.assertIn('Logged in', rv.data)
self.assertIn('Users', rv.data)
self.assertIn('Folders', rv.data)
def test_login_non_admin(self):
# Login with a valid non-admin user
rv = self.app.post('/user/login', data=dict(user='bob', password='bob'), follow_redirects=True)
self.assertIn('Logged in', rv.data)
# Non-admin user cannot acces to users and folders
self.assertNotIn('Users', rv.data)
self.assertNotIn('Folders', rv.data)
def test_root_with_valid_session(self):
# Root with valid session
with self.app.session_transaction() as sess:
sess['userid'] = store.find(db.User, db.User.name == 'alice').one().id
sess['username'] = 'alice'
rv = self.app.get('/', follow_redirects=True)
self.assertIn('alice', rv.data)
self.assertIn('Log out', rv.data)
self.assertIn('There\'s nothing much to see here.', rv.data)
def test_root_with_non_valid_session(self):
# Root with a no-valid session
with self.app.session_transaction() as sess:
sess['userid'] = uuid.uuid4()
sess['username'] = 'alice'
rv = self.app.get('/', follow_redirects=True)
self.assertIn('Please login', rv.data)
# Root with a no-valid user
with self.app.session_transaction() as sess:
sess['userid'] = store.find(db.User, db.User.name == 'alice').one().id
sess['username'] = 'nonexistent'
rv = self.app.get('/', follow_redirects=True)
self.assertIn('Please login', rv.data)
if __name__ == '__main__':
unittest.main()

37
tests/testbase.py Normal file
View File

@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# This file is part of Supysonic.
# Supysonic is a Python implementation of the Subsonic server API.
#
# Copyright (C) 2017 Alban 'spl0k' Féron
#
# Distributed under terms of the GNU AGPLv3 license.
import importlib
import unittest
import sys
from supysonic.managers.user import UserManager
from .appmock import AppMock
class TestBase(unittest.TestCase):
def setUp(self):
app_mock = AppMock()
self.app = app_mock.app
self.store = app_mock.store
self.client = self.app.test_client()
sys.modules['supysonic.web'] = app_mock
importlib.import_module(self.__module_to_test__)
UserManager.add(self.store, 'alice', 'Alic3', 'test@example.com', True)
UserManager.add(self.store, 'bob', 'B0b', 'bob@example.com', False)
def tearDown(self):
self.store.close()
to_unload = [ m for m in sys.modules if m.startswith('supysonic') ]
for m in to_unload:
del sys.modules[m]