|
|
@ -2,7 +2,7 @@ |
|
|
|
# kate: space-indent on; indent-width 4; replace-tabs on; |
|
|
|
|
|
|
|
""" |
|
|
|
* Copyright © 2009-2010, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> |
|
|
|
* Copyright © 2009-2014, Michael "Svedrin" Ziegler <diese-addy@funzt-halt.net> |
|
|
|
* |
|
|
|
* Mumble-Django is free software; you can redistribute it and/or modify |
|
|
|
* it under the terms of the GNU General Public License as published by |
|
|
@ -15,326 +15,68 @@ |
|
|
|
* GNU General Public License for more details. |
|
|
|
""" |
|
|
|
|
|
|
|
# Privs: |
|
|
|
# |
|
|
|
# Unauthed users: |
|
|
|
# * Registration: no Anon_MumbleUser{,Link}FormTestCase |
|
|
|
# * Administration: no Anon_MumbleFormTestCase |
|
|
|
# * User texture: no |
|
|
|
# * User list: no |
|
|
|
# * Log messages: no |
|
|
|
# * Instance scope: ALL |
|
|
|
# |
|
|
|
# Authed users, unregistered: |
|
|
|
# * Registration: self, User{,Password,Link}Form User_MumbleUserLinkFormTestCase |
|
|
|
# * Administration: no |
|
|
|
# * User texture: no |
|
|
|
# * User list: no |
|
|
|
# * Log messages: no |
|
|
|
# * Instance scope: CURRENT |
|
|
|
# |
|
|
|
# Authed users, not admins: |
|
|
|
# * Registration: self, UserForm |
|
|
|
# * Administration: no |
|
|
|
# * User texture: self |
|
|
|
# * User list: no |
|
|
|
# * Log messages: no |
|
|
|
# * Instance scope: CURRENT |
|
|
|
# |
|
|
|
# Authed users, admins: |
|
|
|
# * Registration: everyone |
|
|
|
# * Administration: yes |
|
|
|
# * User texture: everyone |
|
|
|
# * User list: yes |
|
|
|
# * Log messages: yes |
|
|
|
# * Instance scope: CURRENT |
|
|
|
# |
|
|
|
# Authed users, superadmins: |
|
|
|
# * Registration: everyone Super_MumbleUser{,Link}FormTestCase |
|
|
|
# * Administration: yes Super_MumbleFormTestCase |
|
|
|
# * User texture: everyone |
|
|
|
# * User list: yes |
|
|
|
# * Log messages: yes |
|
|
|
# * Instance scope: ALL |
|
|
|
# This is somewhat ugly, but it makes life much easier. |
|
|
|
import os |
|
|
|
os.environ['MURMUR_CONNSTR'] = 'Meta:tcp -h 127.0.0.1 -p 6502' |
|
|
|
os.environ['MURMUR_ICESECRET'] = '' |
|
|
|
|
|
|
|
import json |
|
|
|
import mock |
|
|
|
|
|
|
|
from django.conf import settings |
|
|
|
from django.test import TestCase |
|
|
|
from django.test.client import Client |
|
|
|
from django.contrib.auth.models import User |
|
|
|
from django.test import TestCase |
|
|
|
|
|
|
|
from models import Mumble, MumbleUser |
|
|
|
from utils import ObjectInfo |
|
|
|
from mumble.models import MumbleServer, Mumble, MumbleUser |
|
|
|
|
|
|
|
class ExtDirectFormTestMixin(object): |
|
|
|
""" Methods for testing a Form exported via Ext.Direct. |
|
|
|
These only define the methods, you will need to inherit your TestCase |
|
|
|
from this class and set the following class attributes: |
|
|
|
class IceTestCase(TestCase): |
|
|
|
def test_loadSlice_getSliceDir(self): |
|
|
|
with mock.patch("mumble.MumbleCtlIce.Ice") as mock_Ice: |
|
|
|
mock_Ice.getSliceDir.return_value = "/tmp/slice" |
|
|
|
|
|
|
|
api_baseurl: |
|
|
|
The URL under which the Ext.Direct provider has been registered. |
|
|
|
formname: |
|
|
|
The name of the exported form class. |
|
|
|
""" |
|
|
|
def setUp(self): |
|
|
|
self.cl = Client() |
|
|
|
super(ExtDirectFormTestMixin, self).setUp() |
|
|
|
self.tid = 1 |
|
|
|
from mumble.MumbleCtlIce import loadSlice |
|
|
|
loadSlice("someslice") |
|
|
|
|
|
|
|
def testFormApi(self): |
|
|
|
rawr = self.cl.get( "%s/%s.js" % ( self.api_baseurl, self.formname.lower() ) ) |
|
|
|
self.assertEquals( rawr.status_code, 200 ) |
|
|
|
self.assertTrue( mock_Ice.loadSlice.called) |
|
|
|
self.assertEqual(mock_Ice.loadSlice.call_count, 1) |
|
|
|
self.assertEqual(mock_Ice.loadSlice.call_args[0], ('', ['-I/tmp/slice', 'someslice'])) |
|
|
|
|
|
|
|
def formGet( self, data=[] ): |
|
|
|
rawr = self.cl.post( self.api_baseurl+'/router', |
|
|
|
data=json.dumps({ |
|
|
|
'tid': self.tid, |
|
|
|
'action': ('XD_%s' % self.formname), |
|
|
|
'method': 'get', |
|
|
|
'data': data, |
|
|
|
'type': 'rpc' |
|
|
|
}), |
|
|
|
content_type='application/json' ) |
|
|
|
self.tid += 1 |
|
|
|
response = json.loads(rawr.content) |
|
|
|
if response['type'] == "exception": |
|
|
|
raise Exception( response["message"] ) |
|
|
|
self.assert_( "result" in response ) |
|
|
|
return response['result'] |
|
|
|
def test_loadSlice_getSliceDir_empty(self): |
|
|
|
with mock.patch("mumble.MumbleCtlIce.Ice") as mock_Ice: |
|
|
|
mock_Ice.getSliceDir.return_value = "" |
|
|
|
|
|
|
|
def formPost( self, data={} ): |
|
|
|
postdata={ |
|
|
|
'extAction': ('XD_%s' % self.formname), |
|
|
|
'extMethod': 'update', |
|
|
|
'extTID': self.tid, |
|
|
|
'extType': 'rpc', |
|
|
|
'extUpload': 'false', |
|
|
|
} |
|
|
|
self.tid += 1 |
|
|
|
postdata.update( data ) |
|
|
|
rawr = self.cl.post( self.api_baseurl+'/router', data=postdata ) |
|
|
|
response = json.loads(rawr.content) |
|
|
|
if response['type'] == "exception": |
|
|
|
raise Exception( response["message"] ) |
|
|
|
self.assert_( "result" in response ) |
|
|
|
return response['result'] |
|
|
|
from django.conf import settings |
|
|
|
from mumble.MumbleCtlIce import loadSlice |
|
|
|
loadSlice("someslice") |
|
|
|
|
|
|
|
self.assertTrue( mock_Ice.loadSlice.called) |
|
|
|
self.assertEqual(mock_Ice.loadSlice.call_count, 1) |
|
|
|
self.assertEqual(mock_Ice.loadSlice.call_args[0], ('', ['-I' + settings.SLICEDIR, 'someslice'])) |
|
|
|
|
|
|
|
def generateTestCase( name, formname, data, login=None ): |
|
|
|
attrs = { |
|
|
|
'fixtures': ['testdb.json'], |
|
|
|
'formname': formname, |
|
|
|
'api_baseurl': '/mumble/forms', |
|
|
|
} |
|
|
|
def test_loadSlice_getSliceDir_nonexistant(self): |
|
|
|
with mock.patch("mumble.MumbleCtlIce.Ice") as mock_Ice: |
|
|
|
mock_Ice.mock_add_spec(["loadSlice"]) |
|
|
|
|
|
|
|
if login: |
|
|
|
def setUp( self ): |
|
|
|
ExtDirectFormTestMixin.setUp( self ) |
|
|
|
if not self.cl.login( **login ): |
|
|
|
raise Exception( "Login failed" ) |
|
|
|
attrs['setUp'] = setUp |
|
|
|
from django.conf import settings |
|
|
|
from mumble.MumbleCtlIce import loadSlice |
|
|
|
loadSlice("someslice") |
|
|
|
|
|
|
|
def mkGet( data, result ): |
|
|
|
def testFormGet( self ): |
|
|
|
callresult = self.formGet( [{ 'pk': data['pk'] }] ) |
|
|
|
if "data" in callresult: |
|
|
|
del callresult['data'] # don't care |
|
|
|
self.assertEquals( callresult, result ) |
|
|
|
return testFormGet |
|
|
|
self.assertTrue( mock_Ice.loadSlice.called) |
|
|
|
self.assertEqual(mock_Ice.loadSlice.call_count, 1) |
|
|
|
self.assertEqual(mock_Ice.loadSlice.call_args[0], ('', ['-I' + settings.SLICEDIR, 'someslice'])) |
|
|
|
|
|
|
|
def mkPost( data, result ): |
|
|
|
def testFormPost( self ): |
|
|
|
callresult = self.formPost( data ) |
|
|
|
self.assertEquals( callresult, result, |
|
|
|
("errors" in callresult and callresult['errors'] or None) |
|
|
|
) |
|
|
|
return testFormPost |
|
|
|
def test_MumbleCtlIce(self): |
|
|
|
with mock.patch("mumble.MumbleCtlIce.Ice") as mock_Ice, \ |
|
|
|
mock.patch("mumble.MumbleCtlIce.IcePy") as mock_IcePy, \ |
|
|
|
mock.patch("Murmur.MetaPrx") as mock_MetaPrx: |
|
|
|
|
|
|
|
for testname in data: |
|
|
|
if len(data[testname]) == 3: |
|
|
|
testdata, getresult, postresult = data[testname] |
|
|
|
else: |
|
|
|
testdata, getresult = data[testname] |
|
|
|
postresult = getresult |
|
|
|
mock_MetaPrx.checkedCast().getVersion.return_value = (1, 2, 3, "12oi3j1") |
|
|
|
|
|
|
|
attrs.update({ |
|
|
|
('testForm%sGet' % testname): mkGet( testdata, getresult ), |
|
|
|
('testForm%sPost' % testname): mkPost( testdata, postresult ), |
|
|
|
}) |
|
|
|
from mumble.MumbleCtlIce import MumbleCtlIce |
|
|
|
ctl = MumbleCtlIce('Meta:tcp -h 127.0.0.1 -p 6502') |
|
|
|
|
|
|
|
return type( name, (ExtDirectFormTestMixin, TestCase), attrs ) |
|
|
|
self.assertTrue( mock_Ice.createProperties().setProperty.called) |
|
|
|
self.assertEqual(mock_Ice.createProperties().setProperty.call_count, 2) |
|
|
|
self.assertEqual(mock_Ice.createProperties().setProperty.call_args_list[0][0], ("Ice.ImplicitContext", "Shared")) |
|
|
|
self.assertEqual(mock_Ice.createProperties().setProperty.call_args_list[1][0], ("Ice.MessageSizeMax", "65535")) |
|
|
|
|
|
|
|
RES_SUCCESS = {'success': True} |
|
|
|
RES_ACCESSDENIED = {'success': False, 'errors': {'__all__': 'access denied'}} |
|
|
|
RES_PREVALFAIL = {'success': False, 'errors': {'__all__': 'pre-validation failed'}} |
|
|
|
|
|
|
|
LOGIN_SUPERADMIN = {'username': 'svedrin', 'password': 'passwort'} |
|
|
|
LOGIN_UNREGUSER = {'username': 'unreg', 'password': 'passwort'} |
|
|
|
LOGIN_USER = {'username': 'user', 'password': 'passwort'} |
|
|
|
LOGIN_ADMIN = {'username': 'admin', 'password': 'passwort'} |
|
|
|
|
|
|
|
############################################################# |
|
|
|
### ANON: Unauthed (not logged in) users ### |
|
|
|
############################################################# |
|
|
|
|
|
|
|
Anon_Registration = generateTestCase( |
|
|
|
name = "Anon_Registration", |
|
|
|
formname = "MumbleUserForm", |
|
|
|
data = { |
|
|
|
'My': ( {'pk': 1, 'name': "svedrin", 'password': 'passwort', 'serverid': 1}, RES_ACCESSDENIED ), |
|
|
|
'Other': ( {'pk': 1, 'name': "svedrin", 'password': 'passwort'}, RES_ACCESSDENIED ) |
|
|
|
} |
|
|
|
) |
|
|
|
|
|
|
|
Anon_Administration = generateTestCase( |
|
|
|
name = "Anon_Administration", |
|
|
|
formname = "MumbleForm", |
|
|
|
data = { 'My': ( {'pk': 1, 'url': '', 'player': ''}, RES_ACCESSDENIED ) }, |
|
|
|
) |
|
|
|
|
|
|
|
Anon_UserLink = generateTestCase( |
|
|
|
name = "Anon_UserLink", |
|
|
|
formname = "MumbleUserLinkForm", |
|
|
|
data = { |
|
|
|
'My': ( {'pk': 1, 'name': "ohai", 'password': 'failfail', 'serverid': 1}, RES_ACCESSDENIED ), |
|
|
|
} |
|
|
|
) |
|
|
|
|
|
|
|
############################################################# |
|
|
|
### UNREG: Authenticated but no MumbleUser avail ### |
|
|
|
############################################################# |
|
|
|
|
|
|
|
Unreg_Registration = generateTestCase( |
|
|
|
name = "Unreg_Registration", |
|
|
|
formname = "MumbleUserForm", |
|
|
|
data = { |
|
|
|
'My': ( {'pk': -1, 'name': "neueruser", 'password': 'passwort', 'serverid': 1}, RES_SUCCESS ), |
|
|
|
'Taken': ( {'pk': -1, 'name': "svedrin", 'password': 'passwort', 'serverid': 1}, RES_SUCCESS, |
|
|
|
{'success': False, 'errors': {'name': 'Another player already registered that name.'}} ), |
|
|
|
'Other': ( {'pk': 1, 'name': "svedrin", 'password': 'passwort'}, RES_ACCESSDENIED ) |
|
|
|
}, |
|
|
|
login = LOGIN_UNREGUSER |
|
|
|
) |
|
|
|
|
|
|
|
if settings.ALLOW_ACCOUNT_LINKING and settings.ALLOW_ACCOUNT_LINKING_ADMINS: |
|
|
|
unreg_adminlinkresult = RES_SUCCESS |
|
|
|
else: |
|
|
|
unreg_adminlinkresult = {'success': False, 'errors': {'__all__': 'Linking Admin accounts is not allowed.'}} |
|
|
|
|
|
|
|
Unreg_UserLink = generateTestCase( |
|
|
|
name = "User_UserLink", |
|
|
|
formname = "MumbleUserLinkForm", |
|
|
|
data = { |
|
|
|
'My': ( {'pk': -1, 'name': "nichtadmin", 'password': 'nichtadmin', 'serverid': 1, 'linkacc': 'on'}, |
|
|
|
RES_ACCESSDENIED, RES_SUCCESS if settings.ALLOW_ACCOUNT_LINKING else RES_ACCESSDENIED ), |
|
|
|
'Admin': ( {'pk': -1, 'name': "dochadmin", 'password': 'dochadmin', 'serverid': 1, 'linkacc': 'on'}, |
|
|
|
RES_ACCESSDENIED, unreg_adminlinkresult ), |
|
|
|
'Other': ( {'pk': 1, 'name': "svedrin", 'password': 'passwort', 'serverid': 1}, RES_ACCESSDENIED ), |
|
|
|
'Taken': ( {'pk': -1, 'name': "svedrin", 'password': 'passwort', 'serverid': 1}, RES_ACCESSDENIED, |
|
|
|
{'success': False, 'errors':{'name': 'Another player already registered that name.'}} ), |
|
|
|
}, |
|
|
|
login = LOGIN_UNREGUSER |
|
|
|
) |
|
|
|
|
|
|
|
Unreg_Administration = generateTestCase( |
|
|
|
name = "Unreg_Administration", |
|
|
|
formname = "MumbleForm", |
|
|
|
data = { |
|
|
|
'My': ( {'pk': 1, 'name': 'test server', 'url': '', 'player': ''}, RES_ACCESSDENIED ), |
|
|
|
'Other': ( {'pk': 2, 'name': 'alealejandro', 'url': '', 'player': ''}, RES_ACCESSDENIED ), |
|
|
|
}, |
|
|
|
login = LOGIN_UNREGUSER, |
|
|
|
) |
|
|
|
|
|
|
|
############################################################# |
|
|
|
### USER: MumbleUser but not a server admin ### |
|
|
|
############################################################# |
|
|
|
|
|
|
|
User_Administration = generateTestCase( |
|
|
|
name = "User_Administration", |
|
|
|
formname = "MumbleForm", |
|
|
|
data = { |
|
|
|
'My': ( {'pk': 1, 'name': 'test server', 'url': '', 'player': ''}, RES_ACCESSDENIED ), |
|
|
|
'Other': ( {'pk': 2, 'name': 'alealejandro', 'url': '', 'player': ''}, RES_ACCESSDENIED ), |
|
|
|
}, |
|
|
|
login = LOGIN_USER, |
|
|
|
) |
|
|
|
|
|
|
|
############################################################# |
|
|
|
### ADMIN: MumbleUser is a server admin ### |
|
|
|
############################################################# |
|
|
|
|
|
|
|
Admin_Administration = generateTestCase( |
|
|
|
name = "Admin_Administration", |
|
|
|
formname = "MumbleForm", |
|
|
|
data = { |
|
|
|
'My': ( {'pk': 1, 'name': 'test server', 'url': '', 'player': ''}, RES_SUCCESS ), |
|
|
|
'Other': ( {'pk': 2, 'name': 'alealejandro', 'url': '', 'player': ''}, RES_ACCESSDENIED ), |
|
|
|
}, |
|
|
|
login = LOGIN_ADMIN, |
|
|
|
) |
|
|
|
|
|
|
|
############################################################# |
|
|
|
### SUPER: User is superadmin, MumbleUser irrelevant ### |
|
|
|
############################################################# |
|
|
|
|
|
|
|
Super_Registration = generateTestCase( |
|
|
|
name = "Super_Registration", |
|
|
|
formname = "MumbleUserForm", |
|
|
|
data = { |
|
|
|
'My': ( {'pk': 1, 'name': "svedrin", 'password': 'passwort', 'serverid': 1}, RES_SUCCESS ), |
|
|
|
'Fail': ( {'pk': 1, 'name': "svedrin", 'password': 'passwort'}, RES_SUCCESS, RES_PREVALFAIL ), |
|
|
|
}, |
|
|
|
login = LOGIN_SUPERADMIN |
|
|
|
) |
|
|
|
|
|
|
|
Super_Administration = generateTestCase( |
|
|
|
name = "Super_Administration", |
|
|
|
formname = "MumbleForm", |
|
|
|
data = { |
|
|
|
'My': ( {'pk': 1, 'name': 'test server', 'url': '', 'player': ''}, RES_SUCCESS ), |
|
|
|
'Other': ( {'pk': 2, 'name': 'alealejandro', 'url': '', 'player': ''}, RES_SUCCESS ), |
|
|
|
}, |
|
|
|
login = LOGIN_SUPERADMIN, |
|
|
|
) |
|
|
|
|
|
|
|
Super_UserLink = generateTestCase( |
|
|
|
name = "Super_UserLink", |
|
|
|
formname = "MumbleUserLinkForm", |
|
|
|
data = { |
|
|
|
'My': ( {'pk': 1, 'name': "svedrin", 'password': 'passwort', 'serverid': 1}, |
|
|
|
RES_ACCESSDENIED ), |
|
|
|
'Link': ( {'pk': 1, 'name': "svedrin", 'password': 'passwort', 'serverid': 1, 'linkacc': 'on'}, |
|
|
|
RES_ACCESSDENIED ) |
|
|
|
}, |
|
|
|
) |
|
|
|
|
|
|
|
class ExportedForms(TestCase): |
|
|
|
""" Makes sure needed forms are exported, and admin forms are not. """ |
|
|
|
|
|
|
|
def setUp(self): |
|
|
|
self.cl = Client() |
|
|
|
|
|
|
|
def testMumbleUserFormApi(self): |
|
|
|
rawr = self.cl.get( '/mumble/forms/mumbleuserform.js' ) |
|
|
|
self.assertEquals( rawr.status_code, 200 ) |
|
|
|
|
|
|
|
def testMumbleUserPasswordFormApi(self): |
|
|
|
rawr = self.cl.get( '/mumble/forms/mumbleuserpasswordform.js' ) |
|
|
|
self.assertEquals( rawr.status_code, 200 ) |
|
|
|
|
|
|
|
def testMumbleUserLinkFormApi(self): |
|
|
|
rawr = self.cl.get( '/mumble/forms/mumbleuserlinkform.js' ) |
|
|
|
self.assertEquals( rawr.status_code, 200 ) |
|
|
|
|
|
|
|
def testMumbleAdminFormApi(self): |
|
|
|
# This form is NOT exported (and shouldn't be) because it's only used in the admin |
|
|
|
rawr = self.cl.get( '/mumble/forms/mumbleadminform.js' ) |
|
|
|
self.assertEquals( rawr.status_code, 404 ) |
|
|
|
|
|
|
|
def testMumbleUserAdminFormApi(self): |
|
|
|
# This form is NOT exported (and shouldn't be) because it's only used in the admin |
|
|
|
rawr = self.cl.get( '/mumble/forms/mumbleuseradminform.js' ) |
|
|
|
self.assertEquals( rawr.status_code, 404 ) |
|
|
|
mock_prx = mock_Ice.initialize().stringToProxy() |
|
|
|
self.assertTrue( mock_prx.ice_ping.called) |
|
|
|
|