iro/tests/jsonresource.py
branchdevel
changeset 297 93686b0c028b
equal deleted inserted replaced
296:a73bbc1d8b4b 297:93686b0c028b
       
     1 # Copyright (c) 2012 netzguerilla.net <iro@netzguerilla.net>
       
     2 #
       
     3 # This file is part of Iro.
       
     4 #
       
     5 # Permission is hereby granted, free of charge, to any person obtaining a copy of
       
     6 # this software and associated documentation files (the "Software"), to deal in
       
     7 # the Software without restriction, including without limitation the rights to use,
       
     8 # copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
       
     9 # #Software, and to permit persons to whom the Software is furnished to do so,
       
    10 # subject to the following conditions:
       
    11 #
       
    12 # The above copyright notice and this permission notice shall be included in
       
    13 # all copies or substantial portions of the Software.
       
    14 #
       
    15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
       
    16 # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
       
    17 # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
       
    18 # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
       
    19 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
       
    20 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       
    21 from twisted.trial import unittest
       
    22 
       
    23 from twisted.web.client import Agent, ResponseDone
       
    24 from twisted.internet import reactor
       
    25 from twisted.web.http_headers import Headers
       
    26 from twisted.python.failure import Failure
       
    27 from twisted.internet.protocol import Protocol
       
    28 from twisted.internet import defer
       
    29 
       
    30 from zope.interface import implements
       
    31 
       
    32 from twisted.internet.defer import succeed
       
    33 from twisted.web.iweb import IBodyProducer
       
    34 
       
    35 import json
       
    36 
       
    37 from twisted.web import server
       
    38 from txjsonrpc.web.jsonrpc import Fault
       
    39 
       
    40 from datetime import datetime
       
    41 
       
    42 from iro.model.schema import User, Offer, Userright, Job, Message
       
    43 
       
    44 from iro.view import jsonresource
       
    45 import iro.error as IroError
       
    46 
       
    47 from iro.test_helpers.dbtestcase import DBTestCase
       
    48 
       
    49 from iro.model import setEngine, setPool
       
    50 from iro.controller.pool import startPool, dbPool
       
    51 
       
    52 
       
    53 class StringProducer(object):
       
    54     implements(IBodyProducer)
       
    55 
       
    56     def __init__(self, body):
       
    57         self.body = json.dumps(body)
       
    58         self.length = len(self.body)
       
    59 
       
    60     def startProducing(self, consumer):
       
    61         consumer.write(self.body)
       
    62         return succeed(None)
       
    63 
       
    64     def pauseProducing(self):
       
    65         pass
       
    66 
       
    67     def stopProducing(self):
       
    68         pass
       
    69 
       
    70 class SimpleReceiver(Protocol):
       
    71     def __init__(self, d):
       
    72         self.d = d
       
    73         self.data = ""
       
    74 
       
    75     def dataReceived(self, data):
       
    76         self.data += data
       
    77 
       
    78     def connectionLost(self, reason):
       
    79         try:
       
    80             if reason.check(ResponseDone):
       
    81                 self.d.callback(json.loads(self.data))
       
    82             else:
       
    83                 self.d.errback(reason)
       
    84         except:
       
    85             self.d.errback(Failure())
       
    86 
       
    87 class JSONRPCTest(DBTestCase):
       
    88     """tests for the jsonrpc interface"""
       
    89     ContentType = 'application/json'
       
    90     StringProducer = StringProducer
       
    91     def setUp(self):
       
    92         DBTestCase.setUp(self)
       
    93 
       
    94         setEngine(self.engine)
       
    95         startPool(reactor)
       
    96         setPool(dbPool)
       
    97         self.p = reactor.listenTCP(0, server.Site(jsonresource.JSONFactory()),
       
    98                 interface="127.0.0.1")
       
    99         self.port = self.p.getHost().port
       
   100         self.agent = Agent(reactor)
       
   101 
       
   102     def tearDown(self):
       
   103         DBTestCase.tearDown(self)
       
   104         return self.p.stopListening()
       
   105 
       
   106     def proxy(self, method, data=None, **kargs):
       
   107         d = self.agent.request(
       
   108                 'GET',
       
   109                 'http://localhost:%d/%s'%(self.port, method),
       
   110                 Headers({'Content-Type':[self.ContentType]}),
       
   111                 self.StringProducer(data) if data else None,
       
   112                 )
       
   113 
       
   114         def cbResponse(response):
       
   115             if kargs.has_key('code'):
       
   116                 self.failUnlessEqual(response.code, kargs["code"])
       
   117             if response.code not in [200,400,500]:
       
   118                 raise Fault(response.code,'')
       
   119             self.failUnlessEqual(response.headers.getRawHeaders('Content-Type'), ['application/json'])
       
   120             d = defer.Deferred()
       
   121             response.deliverBody(SimpleReceiver(d))
       
   122             def _(data):
       
   123                 if data["status"]:
       
   124                     return data["result"]
       
   125                 else:
       
   126                     raise Fault(data["error"]["code"],data["error"]["msg"])
       
   127 
       
   128             d.addCallback(_)
       
   129             return d
       
   130         d.addCallback(cbResponse)
       
   131         return d
       
   132 
       
   133 
       
   134     def testListMethods(self):
       
   135         '''list of all offical Methods, that can be executed'''
       
   136 
       
   137         def cbMethods(ret):
       
   138             ret.sort()
       
   139             self.failUnlessEqual(ret, ['bill', 'defaultRoute', 'email', 'fax', 'listMethods', 'mail', 'routes', 'sms', 'status', 'telnumber'])
       
   140 
       
   141         d=self.proxy("listMethods", code=200)
       
   142         d.addCallback(cbMethods)
       
   143         return d
       
   144 
       
   145     def testApikey(self):
       
   146         ''' test apikey'''
       
   147         with self.session() as session:
       
   148             session.add(User(name='test',apikey='abcdef123456789'))
       
   149 
       
   150         d = self.proxy('status', ['abcdef123456789'], code=200)
       
   151         d.addCallback(lambda ret: self.failUnlessEqual(ret,{}))
       
   152 
       
   153         return d
       
   154 
       
   155     def testStatus(self):
       
   156         ''' test the status function'''
       
   157         with self.session() as session:
       
   158             u = User(name='test',apikey='abcdef123456789')
       
   159             session.add(u)
       
   160             j = Job(info='info', status="started")
       
   161             j.user=u
       
   162             session.add(j)
       
   163             session.commit()
       
   164             jid=j.id
       
   165         status = {str(jid):{"status":"started"}}
       
   166         args=[('abcdef123456789',jid),
       
   167                 ('abcdef123456789',),
       
   168                 ('abcdef123456789', '', 'false'),
       
   169                 ('abcdef123456789', '', 0),
       
   170                 ('abcdef123456789', '', 0),
       
   171                 {"id":jid, "user":'abcdef123456789'},
       
   172                 ]
       
   173         dl=[]
       
   174         for a in args:
       
   175             d = self.proxy('status', a, code=200)
       
   176             d.addCallback(lambda ret: self.failUnlessEqual(ret,status))
       
   177             dl.append(d)
       
   178 
       
   179         def f(exc):
       
   180             jnf = IroError.JobNotFound()
       
   181             self.failUnlessEqual(exc.faultCode, jnf.code)
       
   182             self.failUnlessEqual(exc.faultString, jnf.msg)
       
   183         d = self.proxy('status', ['abcdef123456789', jid+1], code=500)
       
   184         d = self.assertFailure(d, Fault)
       
   185         d.addCallback(f)
       
   186         dl.append(d)
       
   187 
       
   188         return defer.DeferredList(dl, fireOnOneErrback=True)
       
   189 
       
   190     def testNoSuchUser(self):
       
   191         '''a unknown user should raise a UserNotNound Exception
       
   192         bewcause xmlrpc only has a Fault exception this Exception has to be deliverd through a xmlrpclib.Fault Exception'''
       
   193         def f(exc):
       
   194             unf = IroError.UserNotFound()
       
   195             self.failUnlessEqual(exc.faultCode, unf.code)
       
   196             self.failUnlessEqual(exc.faultString, unf.msg)
       
   197         d = self.proxy('status', ['abcdef123456789'], code=500)
       
   198         d = self.assertFailure(d, Fault)
       
   199         d.addCallback(f)
       
   200         return d
       
   201 
       
   202     def testNoSuchMethod(self):
       
   203         '''a unknown mothod should raise a Exception '''
       
   204         def f(exc):
       
   205             self.failUnlessEqual(exc.faultCode, 404)
       
   206             self.failUnlessEqual(exc.faultString, '')
       
   207         d = self.proxy('nosuchmethod', code=404)
       
   208         d = self.assertFailure(d, Fault)
       
   209         d.addCallback(f)
       
   210         return d
       
   211 
       
   212     def testValidationFault(self):
       
   213         '''a validate Exception should be translated to a xmlrpclib.Fault.'''
       
   214         def f(exc):
       
   215             self.failUnlessEqual(exc.faultCode, 700)
       
   216             self.failUnlessEqual(exc.faultString, "Validation of 'apikey' failed.")
       
   217         d = self.proxy('status',{'user':'xxx'}, code=400)
       
   218         d = self.assertFailure(d, Fault)
       
   219         d.addCallback(f)
       
   220         return d
       
   221 
       
   222     @defer.inlineCallbacks
       
   223     def testRoutes(self):
       
   224         '''test the route function'''
       
   225         with self.session() as session:
       
   226             u=User(name='test',apikey='abcdef123456789')
       
   227             o=Offer(name="sipgate_basic", provider="sipgate", route="basic", typ="sms")
       
   228             u.rights.append(Userright(o))
       
   229             session.add(u)
       
   230 
       
   231         x = yield self.proxy('routes',['abcdef123456789','sms'], code=200)
       
   232         self.failUnlessEqual(x,['sipgate_basic'])
       
   233 
       
   234         def f(exc):
       
   235             self.failUnlessEqual(exc.faultCode, 700)
       
   236             self.failUnlessEqual(exc.faultString, "Typ fax is not valid.")
       
   237         d = self.proxy('routes',['abcdef123456789','fax'], code=400)
       
   238         d = self.assertFailure(d, Fault)
       
   239         d.addCallback(f)
       
   240         yield d
       
   241 
       
   242         with self.session() as session:
       
   243             o=Offer(name="sipgate_plus", provider="sipgate", route="plus", typ="sms")
       
   244             u = session.query(User).filter_by(name="test").first()
       
   245             u.rights.append(Userright(o))
       
   246             o=Offer(name="faxde", provider="faxde", route="", typ="fax")
       
   247             session.add(o)
       
   248             session.commit()
       
   249 
       
   250         x = yield self.proxy('routes',['abcdef123456789','sms'], code=200)
       
   251         self.failUnlessEqual(x, ['sipgate_basic','sipgate_plus'])
       
   252         x = yield self.proxy('routes', ['abcdef123456789','fax'], code=200)
       
   253         self.failUnlessEqual(x, [])
       
   254 
       
   255         with self.session() as session:
       
   256             u = session.query(User).filter_by(name="test").first()
       
   257             u.rights.append(Userright(o))
       
   258 
       
   259         x = yield self.proxy('routes',['abcdef123456789','sms'], code=200)
       
   260         self.failUnlessEqual(x, ['sipgate_basic','sipgate_plus'])
       
   261         x = yield self.proxy('routes', ['abcdef123456789','fax'], code=200)
       
   262         self.failUnlessEqual(x, ['faxde'])
       
   263 
       
   264     def testDefaultRoutes(self):
       
   265         '''test the defaultRoute function'''
       
   266         with self.session() as session:
       
   267             u=User(name='test',apikey='abcdef123456789')
       
   268             o=Offer(name="sipgate_basic", provider="sipgate", route="basic", typ="sms")
       
   269             u.rights.append(Userright(o,True))
       
   270             o=Offer(name="sipgate_plus", provider="sipgate", route="plus", typ="sms")
       
   271             u.rights.append(Userright(o))
       
   272             session.add(u)
       
   273         d = self.proxy('defaultRoute', ['abcdef123456789','sms'], code=200)
       
   274         d.addCallback(lambda x: self.failUnlessEqual(x,['sipgate_basic']))
       
   275 
       
   276         return d
       
   277 
       
   278     def testTelnumbers(self):
       
   279         '''test the telefon validator'''
       
   280         dl = []
       
   281         d = self.proxy('telnumber',[["0123/456(78)","+4912346785433","00123435456-658"]], code=200)
       
   282         d.addCallback(lambda x: self.failUnlessEqual(x,True))
       
   283         dl.append(d)
       
   284 
       
   285         invalid=['xa','+1','1-23',';:+0','0123']
       
   286         def f(exc):
       
   287             self.failUnlessEqual(exc.faultCode, 701)
       
   288             self.failUnlessEqual(exc.faultString, "No valid telnumber: '%s'" % invalid[0])
       
   289         d = self.proxy('telnumber',[['01234']+invalid], code=400)
       
   290         d = self.assertFailure(d, Fault)
       
   291         d.addCallback(f)
       
   292         dl.append(d)
       
   293 
       
   294         return defer.DeferredList(dl, fireOnOneErrback=True)
       
   295 
       
   296     def testVaildEmail(self):
       
   297         '''test vaild email adresses (got from wikipedia)'''
       
   298         validmails=["niceandsimple@example.com"]
       
   299         d = self.proxy('email', {"recipients":validmails}, code=200)
       
   300         d.addCallback(lambda x: self.failUnlessEqual(x,True))
       
   301         return d
       
   302 
       
   303     def testInvaildEmail(self):
       
   304         '''test invaild email adresses (got from wikipedia)'''
       
   305         invalid=["Abc.example.com",'foo@t.de']
       
   306         def f(exc):
       
   307             self.failUnlessEqual(exc.faultCode, 702)
       
   308             self.failUnlessEqual(exc.faultString, "No valid email: '%s'" % invalid[0])
       
   309         d = self.proxy('email', [invalid], code=400)
       
   310         d = self.assertFailure(d, Fault)
       
   311         d.addCallback(f)
       
   312         return d
       
   313 
       
   314     def testBill(self):
       
   315         '''test bill function'''
       
   316         apikey='abcdef123456789'
       
   317         with self.session() as session:
       
   318             u=User(name='test',apikey=apikey)
       
   319             session.add(u)
       
   320         d = self.proxy('bill', {"user":apikey}, code=200)
       
   321         d.addCallback(lambda x: self.failUnlessEqual(x,{'total':{'price':0.0,'anz':0}}))
       
   322 
       
   323         return d
       
   324 
       
   325     def testBillWithPrice(self):
       
   326         apikey='abcdef123456789'
       
   327         with self.session() as session:
       
   328             u=User(name='test',apikey=apikey)
       
   329             session.add(u)
       
   330             o = Offer(name='sipgate_basic',provider="sipgate",route="basic",typ="sms")
       
   331             u.rights.append(Userright(o))
       
   332             j = Job(info='i',status='sended')
       
   333             j.messages.append(Message(recipient='0123456789', isBilled=False, date=datetime.now() , price=0.4, offer=o))
       
   334             u.jobs.append(j)
       
   335 
       
   336             j = Job(info='a',status='sended')
       
   337             j.messages.append(Message(recipient='0123456789', isBilled=False, date=datetime.now(), price=0.4, offer=o))
       
   338             u.jobs.append(j)
       
   339 
       
   340         def f(ret):
       
   341             self.failUnlessEqual(ret['total'],{'price':0.8,'anz':2})
       
   342             self.failUnlessEqual(ret['sipgate_basic'],
       
   343                 {'price':0.8,'anz':2,
       
   344                     'info':{'i':{'price':0.4,'anz':1},
       
   345                         'a':{'price':0.4,'anz':1},
       
   346                     }
       
   347                 })
       
   348 
       
   349         d = self.proxy('bill', [apikey], code=200)
       
   350         d.addCallback(f)
       
   351         return d
       
   352 
       
   353 if __name__ == '__main__':
       
   354     unittest.main()