Changeset 469:30576260957d

Show
Ignore:
Timestamp:
08/25/08 13:45:02 (5 months ago)
Author:
Brian Warner <warner@allmydata.com>
branch:
default
Message:

replace ConnectionDone? and ConnectionClosed? with DeadReferenceError?, so application code only has to check for a single exception type. Closes #89.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • ChangeLog

    r468 r469  
     12008-08-25  Brian Warner  <warner@lothar.com> 
     2 
     3        * foolscap/broker.py (Broker.abandonAllRequests): map both 
     4        ConnectionLost and ConnectionDone into DeadReferenceError, so that 
     5        application code only needs to check for one exception type. 
     6        * foolscap/negotiate.py (Negotiation.evaluateNegotiationVersion1): 
     7        when an existing connection is dropped in favor of a new one, drop 
     8        it with DeadReferenceError instead of ConnectionDone. The mapping 
     9        in Broker.abandonAllRequests doesn't seem to quite catch 
     10        everything in unit tests. 
     11        (Negotiation.acceptDecisionVersion1): same, when we're the slave 
     12        * foolscap/test/test_call.py (TestCall.test_connection_lost_is_deadref): 
     13        test it 
     14        (TestCall.test_connection_done_is_deadref): same 
     15        (TestCall.testChoiceOf): switch to use ShouldFailMixin 
     16        * foolscap/test/test_gifts.py (Gifts): remove 
     17        ignoreConnectionDone, just look for DeadReferenceError 
     18 
    1192008-08-21  Brian Warner  <warner@lothar.com> 
    220 
  • foolscap/broker.py

    r406 r469  
    483483 
    484484    def abandonAllRequests(self, why): 
     485        # map all connection-lost errors to DeadReferenceError, so 
     486        # application code only needs to check for one exception type 
     487        if why.check(error.ConnectionLost, error.ConnectionDone): 
     488            why = failure.Failure(DeadReferenceError("Connection was lost")) 
    485489        for req in self.waitingForAnswers.values(): 
    486490            eventually(req.fail, why) 
  • foolscap/negotiate.py

    r379 r469  
    44from twisted.python.failure import Failure 
    55from twisted.internet import protocol, reactor 
    6 from twisted.internet.error import ConnectionDone 
    76 
    87from foolscap import broker, referenceable, vocab 
     
    109from foolscap.tokens import SIZE_LIMIT, ERROR, \ 
    1110     BananaError, NegotiationError, RemoteNegotiationError 
     11from foolscap.ipb import DeadReferenceError 
    1212from foolscap.banana import int2b128 
    1313from foolscap.logging import log 
     
    785785                    self.log("accepting new offer, dropping existing connection", 
    786786                             parent=lp) 
    787                     err = ConnectionDone("[%s] replaced by a new connection" 
    788                                          % theirTubRef.getShortTubID()) 
     787                    err = DeadReferenceError("[%s] replaced by a new connection" 
     788                                             % theirTubRef.getShortTubID()) 
    789789                    why = Failure(err) 
    790790                    existing.shutdown(why) 
     
    10791079            self.log("master told us to use a new connection, " 
    10801080                     "so we must drop the existing one", level=UNUSUAL) 
    1081             err = ConnectionDone("replaced by a new connection") 
     1081            err = DeadReferenceError("replaced by a new connection") 
    10821082            why = Failure(err) 
    10831083            self.tub.brokers[self.theirTubRef].shutdown(why) 
  • foolscap/test/test_call.py

    r374 r469  
    1111from twisted.python import log 
    1212from twisted.trial import unittest 
    13 from twisted.internet.main import CONNECTION_LOST 
     13from twisted.internet.main import CONNECTION_LOST, CONNECTION_DONE 
    1414from twisted.python.failure import Failure 
    1515 
    1616from foolscap.tokens import Violation 
    1717from foolscap.eventual import flushEventualQueue 
    18 from foolscap.test.common import HelperTarget, TargetMixin 
     18from foolscap.test.common import HelperTarget, TargetMixin, ShouldFailMixin 
    1919from foolscap.test.common import RIMyTarget, Target, TargetWithoutInterfaces, \ 
    2020     BrokenTarget 
     21from foolscap import DeadReferenceError 
    2122 
    2223class Unsendable: 
     
    2425 
    2526 
    26 class TestCall(TargetMixin, unittest.TestCase): 
     27class TestCall(TargetMixin, ShouldFailMixin, unittest.TestCase): 
    2728    def setUp(self): 
    2829        TargetMixin.setUp(self) 
     
    201202        d.addCallback(lambda res: rr.callRemote("choice1", "a"*2000)) 
    202203        d.addCallback(lambda res: self.failUnlessEqual(res, None)) 
    203         def _check_false(res): 
    204             # False does not conform 
    205             d1 = rr.callRemote("choice1", False) 
    206             d1.addBoth(self.shouldFail, Violation, "testChoiceOf") 
    207             return d1 
    208         d.addCallback(_check_false) 
    209         return d 
    210  
    211     def shouldFail(self, res, expected_failure, which, substring=None): 
    212         if isinstance(res, Failure): 
    213             res.trap(expected_failure) 
    214             if substring: 
    215                 self.failUnless(substring in str(res), 
    216                                 "substring '%s' not in '%s'" 
    217                                 % (substring, str(res))) 
    218         else: 
    219             self.fail("%s was supposed to raise %s, not get '%s'" % 
    220                       (which, expected_failure, res)) 
     204        # False does not conform 
     205        d.addCallback(lambda res: 
     206                      self.shouldFail(Violation, "testChoiceOf", None, 
     207                                      rr.callRemote, "choice1", False)) 
     208        return d 
    221209 
    222210    def testMegaSchema(self): 
     
    410398        return d 
    411399 
     400    def test_connection_lost_is_deadref(self): 
     401        rr, target = self.setupTarget(HelperTarget()) 
     402        d1 = rr.callRemote("hang") 
     403        def get_d(): return d1 
     404        rr.tracker.broker.transport.loseConnection(Failure(CONNECTION_LOST)) 
     405        d = self.shouldFail(DeadReferenceError, "lost_is_deadref.1", 
     406                            "Connection was lost", 
     407                            get_d) 
     408        # and once the connection is down, we should get a DeadReferenceError 
     409        # for new messages 
     410        d.addCallback(lambda res: 
     411                      self.shouldFail(DeadReferenceError, "lost_is_deadref.2", 
     412                                      "Calling Stale Broker", 
     413                                      rr.callRemote, "hang")) 
     414        return d 
     415 
     416    def test_connection_done_is_deadref(self): 
     417        rr, target = self.setupTarget(HelperTarget()) 
     418        d = rr.callRemote("hang") 
     419        rr.tracker.broker.transport.loseConnection(Failure(CONNECTION_DONE)) 
     420        d.addCallbacks(lambda res: self.fail("should have failed"), 
     421                       lambda why: why.trap(DeadReferenceError) and None) 
     422        return d 
     423 
    412424    def disconnected(self, *args, **kwargs): 
    413425        self.lost = 1 
  • foolscap/test/test_gifts.py

    r446 r469  
    33from twisted.trial import unittest 
    44from twisted.internet import defer, protocol, reactor 
    5 from twisted.internet.error import ConnectionDone, ConnectionLost, \ 
    6      ConnectionRefusedError 
     5from twisted.internet.error import ConnectionRefusedError 
    76from twisted.python import failure 
    87from foolscap import RemoteInterface, Referenceable 
     
    1211from foolscap.eventual import flushEventualQueue 
    1312from foolscap.tokens import BananaError, NegotiationError 
    14  
    15 def ignoreConnectionDone(f): 
    16     f.trap(ConnectionDone, ConnectionLost) 
    17     return None 
    1813 
    1914class RIConstrainedHelper(RemoteInterface): 
     
    161156            if self.debug: print "Alice introduces Carol to Bob" 
    162157            # send the gift. This might not get acked by the time the test is 
    163             # done and everything is torn down, so explicitly silence any 
    164             # ConnectionDone error that might result. When we get 
    165             # callRemoteOnly(), use that instead. 
    166             d3 = self.abob.callRemote("set", obj=(self.alice, self.acarol)) 
    167             d3.addErrback(ignoreConnectionDone) 
     158            # done and everything is torn down, so we use callRemoteOnly 
     159            self.abob.callRemoteOnly("set", obj=(self.alice, self.acarol)) 
    168160            return d2 # this fires with the gift that bob got 
    169161        d.addCallback(_introduce) 
     
    174166            d2 = self.carol.waitfor() 
    175167            # handle ConnectionDone as described before 
    176             d3 = self.bcarol.callRemote("set", obj=12) 
    177             d3.addErrback(ignoreConnectionDone) 
     168            self.bcarol.callRemoteOnly("set", obj=12) 
    178169            return d2 
    179170        d.addCallback(_bobGotCarol) 
     
    212203            # ConnectionDone error that might result. When we get 
    213204            # callRemoteOnly(), use that instead. 
    214             d3 = self.abob.callRemote("set", obj=(self.alice, 
    215                                                   self.acarol, 
    216                                                   a_cindy)) 
    217             d3.addErrback(ignoreConnectionDone) 
     205            self.abob.callRemoteOnly("set", obj=(self.alice, 
     206                                                 self.acarol, 
     207                                                 a_cindy)) 
    218208            return d2 # this fires with the gift that bob got 
    219209        d.addCallback(_introduce) 
     
    230220 
    231221            # handle ConnectionDone as described before 
    232             d4 = b_carol.callRemote("set", obj=4) 
    233             d4.addErrback(ignoreConnectionDone) 
    234             d5 = b_cindy.callRemote("set", obj=5) 
    235             d5.addErrback(ignoreConnectionDone) 
     222            b_carol.callRemoteOnly("set", obj=4) 
     223            b_cindy.callRemoteOnly("set", obj=5) 
    236224            return defer.DeferredList([d2,d3]) 
    237225        d.addCallback(_bobGotCarol)