diff --git a/pyweb/mumble/fixtures/testdb.json b/pyweb/mumble/fixtures/testdb.json new file mode 100644 index 0000000..8e661ce --- /dev/null +++ b/pyweb/mumble/fixtures/testdb.json @@ -0,0 +1,441 @@ +[ + { + "pk": 1, + "model": "mumble.mumbleserver", + "fields": { + "dbus": "Meta:tcp -h 127.0.0.1 -p 6502", + "secret": "" + } + }, + { + "pk": 1, + "model": "mumble.mumble", + "fields": { + "addr": "0.0.0.0 ::", + "name": "test server", + "display": "", + "server": 1, + "port": null, + "srvid": 1 + } + }, + { + "pk": 2, + "model": "mumble.mumble", + "fields": { + "addr": "", + "name": "n00 test serv0r", + "display": "", + "server": 1, + "port": null, + "srvid": 2 + } + }, + { + "pk": 1, + "model": "mumble.mumbleuser", + "fields": { + "owner": 1, + "mumbleid": 1, + "password": "", + "name": "svedrin", + "server": 1 + } + }, + { + "pk": 13, + "model": "auth.permission", + "fields": { + "codename": "add_logentry", + "name": "Can add log entry", + "content_type": 5 + } + }, + { + "pk": 14, + "model": "auth.permission", + "fields": { + "codename": "change_logentry", + "name": "Can change log entry", + "content_type": 5 + } + }, + { + "pk": 15, + "model": "auth.permission", + "fields": { + "codename": "delete_logentry", + "name": "Can delete log entry", + "content_type": 5 + } + }, + { + "pk": 4, + "model": "auth.permission", + "fields": { + "codename": "add_group", + "name": "Can add group", + "content_type": 2 + } + }, + { + "pk": 5, + "model": "auth.permission", + "fields": { + "codename": "change_group", + "name": "Can change group", + "content_type": 2 + } + }, + { + "pk": 6, + "model": "auth.permission", + "fields": { + "codename": "delete_group", + "name": "Can delete group", + "content_type": 2 + } + }, + { + "pk": 10, + "model": "auth.permission", + "fields": { + "codename": "add_message", + "name": "Can add message", + "content_type": 4 + } + }, + { + "pk": 11, + "model": "auth.permission", + "fields": { + "codename": "change_message", + "name": "Can change message", + "content_type": 4 + } + }, + { + "pk": 12, + "model": "auth.permission", + "fields": { + "codename": "delete_message", + "name": "Can delete message", + "content_type": 4 + } + }, + { + "pk": 1, + "model": "auth.permission", + "fields": { + "codename": "add_permission", + "name": "Can add permission", + "content_type": 1 + } + }, + { + "pk": 2, + "model": "auth.permission", + "fields": { + "codename": "change_permission", + "name": "Can change permission", + "content_type": 1 + } + }, + { + "pk": 3, + "model": "auth.permission", + "fields": { + "codename": "delete_permission", + "name": "Can delete permission", + "content_type": 1 + } + }, + { + "pk": 7, + "model": "auth.permission", + "fields": { + "codename": "add_user", + "name": "Can add user", + "content_type": 3 + } + }, + { + "pk": 8, + "model": "auth.permission", + "fields": { + "codename": "change_user", + "name": "Can change user", + "content_type": 3 + } + }, + { + "pk": 9, + "model": "auth.permission", + "fields": { + "codename": "delete_user", + "name": "Can delete user", + "content_type": 3 + } + }, + { + "pk": 16, + "model": "auth.permission", + "fields": { + "codename": "add_contenttype", + "name": "Can add content type", + "content_type": 6 + } + }, + { + "pk": 17, + "model": "auth.permission", + "fields": { + "codename": "change_contenttype", + "name": "Can change content type", + "content_type": 6 + } + }, + { + "pk": 18, + "model": "auth.permission", + "fields": { + "codename": "delete_contenttype", + "name": "Can delete content type", + "content_type": 6 + } + }, + { + "pk": 40, + "model": "auth.permission", + "fields": { + "codename": "add_evolution", + "name": "Can add evolution", + "content_type": 14 + } + }, + { + "pk": 41, + "model": "auth.permission", + "fields": { + "codename": "change_evolution", + "name": "Can change evolution", + "content_type": 14 + } + }, + { + "pk": 42, + "model": "auth.permission", + "fields": { + "codename": "delete_evolution", + "name": "Can delete evolution", + "content_type": 14 + } + }, + { + "pk": 37, + "model": "auth.permission", + "fields": { + "codename": "add_version", + "name": "Can add version", + "content_type": 13 + } + }, + { + "pk": 38, + "model": "auth.permission", + "fields": { + "codename": "change_version", + "name": "Can change version", + "content_type": 13 + } + }, + { + "pk": 39, + "model": "auth.permission", + "fields": { + "codename": "delete_version", + "name": "Can delete version", + "content_type": 13 + } + }, + { + "pk": 31, + "model": "auth.permission", + "fields": { + "codename": "add_mumble", + "name": "Can add Server instance", + "content_type": 11 + } + }, + { + "pk": 32, + "model": "auth.permission", + "fields": { + "codename": "change_mumble", + "name": "Can change Server instance", + "content_type": 11 + } + }, + { + "pk": 33, + "model": "auth.permission", + "fields": { + "codename": "delete_mumble", + "name": "Can delete Server instance", + "content_type": 11 + } + }, + { + "pk": 28, + "model": "auth.permission", + "fields": { + "codename": "add_mumbleserver", + "name": "Can add Mumble Server", + "content_type": 10 + } + }, + { + "pk": 29, + "model": "auth.permission", + "fields": { + "codename": "change_mumbleserver", + "name": "Can change Mumble Server", + "content_type": 10 + } + }, + { + "pk": 30, + "model": "auth.permission", + "fields": { + "codename": "delete_mumbleserver", + "name": "Can delete Mumble Server", + "content_type": 10 + } + }, + { + "pk": 34, + "model": "auth.permission", + "fields": { + "codename": "add_mumbleuser", + "name": "Can add User account", + "content_type": 12 + } + }, + { + "pk": 35, + "model": "auth.permission", + "fields": { + "codename": "change_mumbleuser", + "name": "Can change User account", + "content_type": 12 + } + }, + { + "pk": 36, + "model": "auth.permission", + "fields": { + "codename": "delete_mumbleuser", + "name": "Can delete User account", + "content_type": 12 + } + }, + { + "pk": 25, + "model": "auth.permission", + "fields": { + "codename": "add_registrationprofile", + "name": "Can add registration profile", + "content_type": 9 + } + }, + { + "pk": 26, + "model": "auth.permission", + "fields": { + "codename": "change_registrationprofile", + "name": "Can change registration profile", + "content_type": 9 + } + }, + { + "pk": 27, + "model": "auth.permission", + "fields": { + "codename": "delete_registrationprofile", + "name": "Can delete registration profile", + "content_type": 9 + } + }, + { + "pk": 19, + "model": "auth.permission", + "fields": { + "codename": "add_session", + "name": "Can add session", + "content_type": 7 + } + }, + { + "pk": 20, + "model": "auth.permission", + "fields": { + "codename": "change_session", + "name": "Can change session", + "content_type": 7 + } + }, + { + "pk": 21, + "model": "auth.permission", + "fields": { + "codename": "delete_session", + "name": "Can delete session", + "content_type": 7 + } + }, + { + "pk": 22, + "model": "auth.permission", + "fields": { + "codename": "add_site", + "name": "Can add site", + "content_type": 8 + } + }, + { + "pk": 23, + "model": "auth.permission", + "fields": { + "codename": "change_site", + "name": "Can change site", + "content_type": 8 + } + }, + { + "pk": 24, + "model": "auth.permission", + "fields": { + "codename": "delete_site", + "name": "Can delete site", + "content_type": 8 + } + }, + { + "pk": 1, + "model": "auth.user", + "fields": { + "username": "svedrin", + "first_name": "", + "last_name": "", + "is_active": true, + "is_superuser": true, + "is_staff": true, + "last_login": "2010-08-02 15:56:15", + "groups": [], + "user_permissions": [], + "password": "sha1$71bab$1dd52b90d6b63ba95483292dc50ac58ee71ca551", + "email": "diese-addy@funzt-halt.net", + "date_joined": "2010-07-23 08:43:57" + } + } +] diff --git a/pyweb/mumble/tests.py b/pyweb/mumble/tests.py index aab57e5..7c47fba 100644 --- a/pyweb/mumble/tests.py +++ b/pyweb/mumble/tests.py @@ -15,195 +15,212 @@ * GNU General Public License for more details. """ +import simplejson from django.conf import settings from django.test import TestCase - -from models import Mumble -from utils import ObjectInfo - - -class InstancesHandling( TestCase ): - """ Tests creation, editing and removing of vserver instances. """ +from django.test.client import Client +from django.contrib.auth.models import User + +from models import Mumble, MumbleUser +from utils import ObjectInfo + +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: + + 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 + + def testFormApi(self): + rawr = self.cl.get( "%s/%s.js" % ( self.api_baseurl, self.formname.lower() ) ) + self.assertEquals( rawr.status_code, 200 ) + + def formGet( self, data=[] ): + rawr = self.cl.post( self.api_baseurl+'/router', + data=simplejson.dumps({ + 'tid': self.tid, + 'action': ('XD_%s' % self.formname), + 'method': 'get', + 'data': data, + 'type': 'rpc' + }), + content_type='application/json' ) + self.tid += 1 + response = simplejson.loads(rawr.content) + if response['type'] == "exception": + raise Exception( response["message"] ) + self.assert_( "result" in response ) + return response['result'] + + 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 = simplejson.loads(rawr.content) + if response['type'] == "exception": + raise Exception( response["message"] ) + self.assert_( "result" in response ) + return response['result'] + + +class AuthedTestCase( TestCase ): + fixtures = ["testdb.json"] def setUp( self ): - # Make sure we always start with a FRESH murmur instance, checking for left-over instances - # and deleting them before creating ours. - try: - self.murmur = Mumble.objects.get( addr="0.0.0.0", port=31337 ) - except Mumble.DoesNotExist: - pass + TestCase.setUp( self ) + if not self.cl.login( username="svedrin", password="passwort" ): + raise Exception( "Login failed" ) + +class UnauthedMumbleFormTestCase( ExtDirectFormTestMixin, TestCase ): + api_baseurl = "/mumble/forms" + formname = "MumbleForm" + + def testFormGet( self ): + result = self.formGet( [{'pk': 1}] ) + self.assertEquals( result['success'], False ) + self.assertEquals( result['errors'][''], 'access denied' ) + + def testFormPost( self ): + result = self.formPost( {'pk': 1, 'url': '', 'player': ''} ) + self.assertEquals( result['success'], False ) + self.assertEquals( result['errors'][''], 'access denied' ) + + +class AuthedMumbleFormTestCase( ExtDirectFormTestMixin, AuthedTestCase ): + api_baseurl = "/mumble/forms" + formname = "MumbleForm" + + def testFormGet( self ): + result = self.formGet( [{'pk': 1}] ) + self.assertEquals( result['success'], True, ("errors" in result and result['errors'] or None) ) + + def testFormPostSrvAdmin( self ): + result = self.formPost( {'pk': 1, 'name': 'test server', 'url': '', 'player': ''} ) + self.assertEquals( result['success'], True, ("errors" in result and result['errors'] or None) ) + + def testFormPostNonSrvAdmin( self ): + result = self.formPost( {'pk': 2, 'name': 'alealejandro', 'url': '', 'player': ''} ) + self.assertEquals( result['success'], True, ("errors" in result and result['errors'] or None) ) + + +class UnauthedMumbleUserFormTestCase( ExtDirectFormTestMixin, TestCase ): + api_baseurl = "/mumble/forms" + formname = "MumbleUserForm" + + def testFormGet( self ): + result = self.formGet( [{'pk': 1}] ) + self.assertEquals( result['success'], False ) + self.assertEquals( result['errors'][''], 'access denied' ) + + def testFormPostWithoutServer( self ): + result = self.formPost( {'pk': 1, 'name': "ohai", 'password': "failfail"} ) + self.assertEquals( result['success'], False ) + self.assertEquals( result['errors'][''], 'access denied' ) + + def testFormPost( self ): + result = self.formPost( {'pk': 1, 'name': "svedrin", 'password': 'passwort', 'serverid': 1} ) + self.assertEquals( result['success'], False ) + self.assertEquals( result['errors'][''], 'access denied' ) + +class AuthedMumbleUserFormTestCase( ExtDirectFormTestMixin, AuthedTestCase ): + api_baseurl = "/mumble/forms" + formname = "MumbleUserForm" + + def testFormGet( self ): + result = self.formGet( [{'pk': 1}] ) + self.assertEquals( result['success'], True, ("errors" in result and result['errors'] or None) ) + + def testFormPostWithoutServer( self ): + result = self.formPost( {'pk': 1, 'name': "svedrin", 'password': 'passwort' } ) + self.assertEquals( result['success'], False ) + self.assertEquals( result['errors'][''], 'pre-validation failed' ) + + def testFormPost( self ): + result = self.formPost( {'pk': 1, 'name': "svedrin", 'password': 'passwort', 'serverid': 1} ) + self.assertEquals( result['success'], True, ("errors" in result and result['errors'] or None) ) + +class UnauthedMumbleUserLinkFormTestCase( UnauthedMumbleUserFormTestCase ): + api_baseurl = "/mumble/forms" + formname = "MumbleUserLinkForm" + + def testFormGet( self ): + result = self.formGet( [{'pk': 1}] ) + self.assertEquals( result['success'], False ) + self.assertEquals( result['errors'][''], 'access denied' ) + + def testFormPost( self ): + result = self.formPost( {'pk': 1, 'name': "ohai", 'password': 'failfail', 'serverid': 1} ) + self.assertEquals( result['success'], False ) + self.assertEquals( result['errors'][''], 'access denied' ) + +class AuthedMumbleUserLinkFormTestCase( ExtDirectFormTestMixin, AuthedTestCase ): + api_baseurl = "/mumble/forms" + formname = "MumbleUserLinkForm" + + def testFormGet( self ): + if settings.ALLOW_ACCOUNT_LINKING: + # Excepts because linkacc can't be retrieved, but this form is for being + # displayed when empty only so retrieval is either forbidden or an error + self.assertRaises( Exception, self.formGet, [{'pk': 1}] ) else: - self.murmur.delete() - finally: - self.murmur = Mumble( name="#unit testing instance#", addr="0.0.0.0", port=31337 ) - self.murmur.save() - - def testDefaultConf( self ): - conf = self.murmur.ctl.getAllConf( self.murmur.srvid ) - - self.assert_( type(conf) == dict ) - self.assert_( "host" in conf ) - self.assert_( "port" in conf ) - self.assert_( "certificate" in conf ) - self.assert_( "key" in conf ) - self.assert_( "registerhostname" in conf ) - self.assert_( "registername" in conf ) - self.assert_( "channelname" in conf ) - self.assert_( "username" in conf ) - self.assert_( "obfuscate" in conf ) - self.assert_( "defaultchannel" in conf ) - - def testAddrPortUnique( self ): - try: - duplicate = Mumble( - name="#another unit testing instance#", - addr=self.murmur.addr, port=self.murmur.port, - dbus=settings.DEFAULT_CONN - ) - if duplicate.ctl.method == "ICE": - import Murmur - self.assertRaises( Murmur.ServerFailureException, duplicate.save ) - elif self.murmur.version[:2] == [ 1, 2 ]: - from dbus import DBusException - self.assertRaises( DBusException, duplicate.save ) - else: - from sqlite3 import IntegrityError - self.assertRaises( IntegrityError, duplicate.save ) - finally: - # make sure the duplicate is removed - duplicate.ctl.deleteServer( duplicate.srvid ) - - def tearDown( self ): - self.murmur.delete() - - -class DataReading( TestCase ): - """ Tests reading data from murmur using the low-level CTL methods. """ - - def setUp( self ): - # BIG FAT WARNING: This sucks ass, because it assumes the tester has a - # Murmur database like the one I have. - # I definitely need to prepare Murmur somehow before running these tests. - # Just don't yet know how. - self.murmur = Mumble.objects.get(id=1) - - - def testCtlGetChannels( self ): - """ Test getChannels() """ - - channels = self.murmur.ctl.getChannels( self.murmur.srvid ) - - if self.murmur.ctl.method == "ICE": - import Murmur - self.assertEquals( type( channels[0] ), Murmur.Channel ) + result = self.formGet( [{'pk': 1}] ) + self.assertEquals( result['success'], False ) + self.assertEquals( result['errors'][''], 'access denied' ) + + def testFormPost( self ): + result = self.formPost( {'pk': 1, 'name': "svedrin", 'password': 'passwort', 'serverid': 1} ) + if settings.ALLOW_ACCOUNT_LINKING: + self.assertEquals( result['success'], True, ("errors" in result and result['errors'] or None) ) else: - self.assertEquals( type( channels[0] ), ObjectInfo ) - - self.assert_( hasattr( channels[0], "id" ) ) - self.assert_( hasattr( channels[0], "name" ) ) - self.assert_( hasattr( channels[0], "parent" ) ) - self.assert_( hasattr( channels[0], "links" ) ) - - - def testCtlGetPlayers( self ): - """ Test getPlayers() """ - - players = self.murmur.ctl.getPlayers( self.murmur.srvid ) - - self.assert_( len(players) > 0 ) - - self.assertEquals( type(players), dict ) - - for plidx in players: - player = players[plidx] - - if self.murmur.ctl.method == "ICE" and self.murmur.version[:2] == ( 1, 2 ): - import Murmur - self.assertEquals( type( player ), Murmur.User ) - else: - self.assertEquals( type( player ), ObjectInfo ) - - self.assert_( hasattr( player, "session" ) ) - self.assert_( hasattr( player, "mute" ) ) - self.assert_( hasattr( player, "deaf" ) ) - self.assert_( hasattr( player, "selfMute" ) ) - self.assert_( hasattr( player, "selfDeaf" ) ) - self.assert_( hasattr( player, "channel" ) ) - self.assert_( hasattr( player, "userid" ) ) - self.assert_( hasattr( player, "name" ) ) - self.assert_( hasattr( player, "onlinesecs" ) ) - self.assert_( hasattr( player, "bytespersec" ) ) - - - def testCtlGetRegisteredPlayers( self ): - """ Test getRegistredPlayers() and getRegistration() """ - - players = self.murmur.ctl.getRegisteredPlayers( self.murmur.srvid ) - - self.assert_( len(players) > 0 ) - - self.assertEquals( type(players), dict ) - - for plidx in players: - player = players[plidx] - - self.assertEquals( type( player ), ObjectInfo ) - - self.assert_( hasattr( player, "userid" ) ) - self.assert_( hasattr( player, "name" ) ) - self.assert_( hasattr( player, "email" ) ) - self.assert_( hasattr( player, "pw" ) ) - - # compare with getRegistration result - reg = self.murmur.ctl.getRegistration( self.murmur.srvid, player.userid ) - - self.assertEquals( type( reg ), ObjectInfo ) - - self.assert_( hasattr( reg, "userid" ) ) - self.assert_( hasattr( reg, "name" ) ) - self.assert_( hasattr( reg, "email" ) ) - self.assert_( hasattr( reg, "pw" ) ) - - self.assertEquals( player.userid, reg.userid ) - self.assertEquals( player.name, reg.name ) - self.assertEquals( player.email, reg.email ) - self.assertEquals( player.pw, reg.pw ) - - - def testCtlGetAcl( self ): - """ Test getACL() for the root channel """ - - acls, groups, inherit = self.murmur.ctl.getACL( self.murmur.srvid, 0 ) - - for rule in acls: - if self.murmur.ctl.method == "ICE" and self.murmur.version[:2] == ( 1, 2 ): - import Murmur - self.assertEquals( type( rule ), Murmur.ACL ) - else: - self.assertEquals( type( rule ), ObjectInfo ) - - self.assert_( hasattr( rule, "applyHere" ) ) - self.assert_( hasattr( rule, "applySubs" ) ) - self.assert_( hasattr( rule, "inherited" ) ) - self.assert_( hasattr( rule, "userid" ) ) - self.assert_( hasattr( rule, "group" ) ) - self.assert_( hasattr( rule, "allow" ) ) - self.assert_( hasattr( rule, "deny" ) ) - - for grp in groups: - if self.murmur.ctl.method == "ICE": - import Murmur - self.assertEquals( type( grp ), Murmur.Group ) - else: - self.assertEquals( type( grp ), ObjectInfo ) - - self.assert_( hasattr( grp, "name" ) ) - self.assert_( hasattr( grp, "inherited" ) ) - self.assert_( hasattr( grp, "inherit" ) ) - self.assert_( hasattr( grp, "inheritable" ) ) - self.assert_( hasattr( grp, "add" ) ) - self.assert_( hasattr( grp, "remove" ) ) - self.assert_( hasattr( grp, "members" ) ) - - + self.assertEquals( result['success'], False ) + self.assertEquals( result['errors'][''], 'access denied' ) + + def testFormPostLinking( self ): + result = self.formPost( {'pk': 1, 'name': "svedrin", 'password': 'passwort', 'serverid': 1, 'linkacc': 'on'} ) + self.assertEquals( result['success'], False ) + + +class UnauthedFormLoading(TestCase): + """ Makes unauthorized requests to forms which require auth, and checks + that those handle auth correctly. + """ + 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 )