Changeset c9c68cb4856333078390a4fedecaed57636682bc

Show
Ignore:
Timestamp:
05/28/2011 02:56:31 PM (2 years ago)
Author:
Loic Dachary <loic@…>
Children:
cbaf5abc0bd22defc08e9cee4c5e9ba77daf7791
Parents:
aff7187e7c0c6e5a15b2ac000e44a46a8f578b10
git-committer:
Loic Dachary <loic@…> (05/28/2011 02:56:31 PM)
Message:

Add the listen and notify functions to CardstoriesServices?. listen() returns a deferred that will be called when a) the service is started (type start), b) the service is stopped (type stop), c) a game is deleted (type delete), d) a game has changed (type change). The result argument of the callback is a map with a "type" member set as explained above. When the type is either "delete" or "change", it the "game" member is the CardstoriesGame? object to which the even relates. The "detail" member further describes the event when the "type" is "change" or it is set to None when the "type" is "delete". refs#62

Files:
2 modified

Legend:

Unmodified
Added
Removed
  • cardstories/service.py

    r2c789e9 rc9c68cb  
    5555        self.games = {} 
    5656        self.players = {} 
     57        self.listeners = [] 
     58 
     59    def listen(self): 
     60        d = defer.Deferred() 
     61        self.listeners.append(d) 
     62        return d 
     63 
     64    def notify(self, result): 
     65        if hasattr(self, 'notify_running'): 
     66            raise UserWarning, 'recursive call to notify' 
     67        self.notify_running = True 
     68        listeners = self.listeners 
     69        self.listeners = [] 
     70        def error(reason): 
     71            reason.printDetailedTraceback() 
     72            return True 
     73        for listener in listeners: 
     74            listener.addErrback(error) 
     75            listener.callback(result) 
     76        del self.notify_running 
    5777 
    5878    def startService(self): 
     
    6989        db.close() 
    7090        self.db = adbapi.ConnectionPool("sqlite3", database=database, cp_noisy=True) 
     91        self.notify({'type': 'start'}) 
    7192         
    7293    def stopService(self): 
     94        self.notify({'type': 'stop'}) 
    7395        for game in self.games.values(): 
    7496            game.destroy() 
     
    171193    def game_notify(self, args, game_id): 
    172194        if args == None: 
     195            self.notify({'type': 'delete', 'game': self.games[game_id], 'details': args}) 
    173196            del self.games[game_id] 
    174197            return False 
     
    176199            return False 
    177200        game = self.games[game_id] 
     201        self.notify({'type': 'change', 'game': game, 'details': args}) 
    178202        for player_id in game.get_players(): 
    179203            if self.players.has_key(player_id): 
  • tests/test_service.py

    r2c789e9 rc9c68cb  
    3232base.DelayedCall.debug = True 
    3333 
     34class CardstoriesServiceTestNotify(unittest.TestCase): 
     35     
     36    def test00_notify(self): 
     37        service = CardstoriesService({}) 
     38        d = service.listen() 
     39        def check(result): 
     40            self.assertTrue(result) 
     41            service.checked = True 
     42            return result 
     43        d.addCallback(check) 
     44        service.notify(True) 
     45        self.assertTrue(service.checked) 
     46 
     47    def test01_notify_recursive(self): 
     48        service = CardstoriesService({}) 
     49        d = service.listen() 
     50        def recurse(result): 
     51            try: 
     52                service.notify(False) 
     53            except UserWarning, e: 
     54                self.failUnlessSubstring('recurs', e.args[0]) 
     55                service.recursed = True 
     56            return result 
     57        d.addCallback(recurse) 
     58        service.notify(True) 
     59        self.assertTrue(service.recursed) 
     60 
     61    def test02_notify_ignore_exception(self): 
     62        service = CardstoriesService({}) 
     63        d = service.listen() 
     64        def fail(result): 
     65            service.raised = True 
     66            raise UserWarning, 'raise exception' 
     67        d.addCallback(fail) 
     68        service.notify(True) 
     69        self.assertTrue(service.raised) 
     70 
    3471class CardstoriesServiceTestInit(unittest.TestCase): 
    3572 
     
    3875        service = CardstoriesService({'db': database}) 
    3976        self.assertFalse(os.path.exists(database)) 
     77        def start(event): 
     78            self.assertEqual(event['type'], 'start') 
     79            service.notified_start = True 
     80            return event 
     81        service.listen().addCallback(start) 
    4082        service.startService() 
     83        self.assertTrue(service.notified_start) 
    4184        self.assertTrue(os.path.exists(database)) 
    42         return service.stopService() 
     85        def stop(event): 
     86            self.assertEqual(event['type'], 'stop') 
     87            service.notified_stop = True 
     88            return event 
     89        service.listen().addCallback(stop) 
     90        d = service.stopService() 
     91        self.assertTrue(service.notified_stop) 
     92        return d 
    4393 
    4494    @defer.inlineCallbacks 
     
    395445            self.assertEquals(result['player_id'], [owner_id]) 
    396446            self.assertEquals(result['game_id'], [game.id]) 
     447            game.checked = True 
    397448            return result 
    398449        d.addCallback(check) 
     450        def change(event): 
     451            self.assertTrue(event['type'], 'change') 
     452            self.assertTrue(event['game'].get_id(), game.get_id()) 
     453            game.changed = True 
     454        self.service.listen().addCallback(change) 
    399455        game.touch() # calls game_notify indirectly 
     456        self.assertTrue(game.checked) 
     457        self.assertTrue(game.changed) 
     458        # 
     459        # Event notification when a game is destroyed 
     460        # 
     461        def destroy(event): 
     462            self.assertTrue(event['type'], 'delete') 
     463            self.assertTrue(event['game'].get_id(), game.get_id()) 
     464            game.destroyed = True 
     465        self.service.listen().addCallback(destroy)             
     466        game.destroy() 
     467        self.assertTrue(game.destroyed) 
    400468        # 
    401469        # calling game_notify on a non existent game is a noop 
     
    564632#    loader.methodPrefix = "test11_" 
    565633    suite = loader.suiteFactory() 
     634    suite.addTest(loader.loadClass(CardstoriesServiceTestNotify)) 
    566635    suite.addTest(loader.loadClass(CardstoriesServiceTestInit)) 
    567636    suite.addTest(loader.loadClass(CardstoriesServiceTest))