예제 #1
0
    def testConnectAuthenticated(self):
        tub = self.services[0]
        target = HelperTarget("bob")
        target.obj = "unset"
        url = tub.registerReference(target)
        # can we connect to a reference on our own Tub?
        d = tub.getReference(url)

        def _connected(ref):
            return ref.callRemote("set", 12)

        d.addCallback(_connected)

        def _check(res):
            self.assertEqual(target.obj, 12)

        d.addCallback(_check)

        def _connect_again(res):
            target.obj = None
            return tub.getReference(url)

        d.addCallback(_connect_again)
        d.addCallback(_connected)
        d.addCallback(_check)
        return d
예제 #2
0
 def create_constrained_characters(self):
     self.alice = HelperTarget("alice")
     self.bob = ConstrainedHelper("bob")
     self.bob_url = self.tubB.registerReference(self.bob, "bob")
     self.carol = HelperTarget("carol")
     self.carol_url = self.tubC.registerReference(self.carol, "carol")
     self.dave = HelperTarget("dave")
     self.dave_url = self.tubD.registerReference(self.dave, "dave")
예제 #3
0
파일: test_tub.py 프로젝트: sajith/foolscap
    def testNameLookup(self):
        t1 = HelperTarget()
        t2 = HelperTarget()
        self.names["foo"] = t1
        self.names2["bar"] = t2
        self.names2["baz"] = t2
        self.tubB.registerNameLookupHandler(self.lookup)
        self.tubB.registerNameLookupHandler(self.lookup2)
        # hack up a new furl pointing at the same tub but with a name that
        # hasn't been registered.
        s = SturdyRef(self.url_on_b)
        s.name = "foo"

        d = self.tubA.getReference(s)

        def _check(res):
            self.assertTrue(isinstance(res, RemoteReference))
            self.assertEqual(self.lookups, ["foo"])
            # the first lookup should short-circuit the process
            self.assertEqual(self.lookups2, [])
            self.lookups = []; self.lookups2 = []
            s.name = "bar"
            return self.tubA.getReference(s)
        d.addCallback(_check)

        def _check2(res):
            self.assertTrue(isinstance(res, RemoteReference))
            # if the first lookup fails, the second handler should be asked
            self.assertEqual(self.lookups, ["bar"])
            self.assertEqual(self.lookups2, ["bar"])
            self.lookups = []; self.lookups2 = []
            # make sure that loopbacks use this too
            return self.tubB.getReference(s)
        d.addCallback(_check2)

        def _check3(res):
            self.assertTrue(isinstance(res, RemoteReference))
            self.assertEqual(self.lookups, ["bar"])
            self.assertEqual(self.lookups2, ["bar"])
            self.lookups = []; self.lookups2 = []
            # and make sure we can de-register handlers
            self.tubB.unregisterNameLookupHandler(self.lookup)
            s.name = "baz"
            return self.tubA.getReference(s)
        d.addCallback(_check3)

        def _check4(res):
            self.assertTrue(isinstance(res, RemoteReference))
            self.assertEqual(self.lookups, [])
            self.assertEqual(self.lookups2, ["baz"])
            self.lookups = []; self.lookups2 = []
        d.addCallback(_check4)

        return d
예제 #4
0
    def setUp(self):
        TargetMixin.setUp(self)
        (self.tubB, ) = self.makeTubs(1)

        self.barry = HelperTarget("barry")
        self.barry_url = self.tubB.registerReference(self.barry)

        self.bill = HelperTarget("bill")
        self.bill_url = self.tubB.registerReference(self.bill)

        self.bob = HelperTarget("bob")
        self.bob_url = self.tubB.registerReference(self.bob)
예제 #5
0
 def test_callRemote(self):
     t = HelperTarget()
     t.obj = None
     rref = IRemoteReference(t)
     marker = rref.notifyOnDisconnect(self.ignored, "args", kwargs="foo")
     rref.dontNotifyOnDisconnect(marker)
     d = rref.callRemote("set", 12)
     # the callRemote should be put behind an eventual-send
     self.assertEqual(t.obj, None)
     def _check(res):
         self.assertEqual(t.obj, 12)
         self.assertEqual(res, True)
     d.addCallback(_check)
     return d
예제 #6
0
 def test_callRemote(self):
     t = HelperTarget()
     t.obj = None
     rref = IRemoteReference(t)
     marker = rref.notifyOnDisconnect(self.ignored, "args", kwargs="foo")
     rref.dontNotifyOnDisconnect(marker)
     d = rref.callRemote("set", 12)
     # the callRemote should be put behind an eventual-send
     self.failUnlessEqual(t.obj, None)
     def _check(res):
         self.failUnlessEqual(t.obj, 12)
         self.failUnlessEqual(res, True)
     d.addCallback(_check)
     return d
예제 #7
0
    def test_connection_lost_is_deadref(self):
        rr, target = self.setupTarget(HelperTarget())
        d1 = rr.callRemote("hang")

        def get_d():
            return d1

        rr.tracker.broker.transport.loseConnection(Failure(CONNECTION_LOST))
        d = self.shouldFail(DeadReferenceError, "lost_is_deadref.1",
                            "Connection was lost", get_d)

        def _examine_error((f, )):
            # the (to tubid=XXX) part will see "tub=call", which is an
            # abbreviation of "callingBroker" as created in
            # TargetMixin.setupBrokers
            self.failUnlessIn("(to tubid=call)", str(f.value))
            self.failUnlessIn("(during method=None:hang)", str(f.value))

        d.addCallback(_examine_error)
        # and once the connection is down, we should get a DeadReferenceError
        # for new messages
        d.addCallback(lambda res: self.shouldFail(
            DeadReferenceError, "lost_is_deadref.2", "Calling Stale Broker", rr
            .callRemote, "hang"))
        return d
예제 #8
0
 def test_connection_done_is_deadref(self):
     rr, target = self.setupTarget(HelperTarget())
     d = rr.callRemote("hang")
     rr.tracker.broker.transport.loseConnection(Failure(CONNECTION_DONE))
     d.addCallbacks(lambda res: self.fail("should have failed"),
                    lambda why: why.trap(DeadReferenceError) and None)
     return d
예제 #9
0
    def test_negotiate_fails_and_retry(self):
        connects = []
        target = HelperTarget("bob")
        url = self.tubB.registerReference(target, "target")
        hint = referenceable.SturdyRef(url).getTubRef().getLocations()[0]
        l = self.tubB.getListeners()[0]
        l._negotiationClass = AlwaysFailNegotiation
        portb = self.tub_ports[1]

        d1 = defer.Deferred()
        notifiers = [d1]
        rc = self.tubA.connectTo(url, self._connected, notifiers, connects)
        yield self.poll(lambda: rc.getReconnectionInfo().state == "waiting")

        # the reconnector should have failed once or twice, since the
        # negotiation would always fail.
        self.failUnlessEqual(len(connects), 0)
        ci = rc.getReconnectionInfo().connectionInfo
        cs = ci.connectorStatuses
        self.assertEqual(cs, {hint: "negotiation failed: I always fail"})

        # Now we fix tubB. We only touched the Listener, so re-doing the
        # listenOn should clear it.
        yield self.tubB.stopListeningOn(l)

        self.tubB.listenOn("tcp:%d:interface=127.0.0.1" % portb)

        # the next time the reconnector tries, it should succeed
        yield d1

        self.failUnlessEqual(len(connects), 1)
        rc.stopConnecting()
예제 #10
0
    def test_stop_trying(self):
        connects = []
        target = HelperTarget("bob")
        url = self.tubB.registerReference(target, "target")
        self.services.remove(self.tubB)
        # this will fail, since tubB is not listening anymore
        yield self.tubB.stopService()
        rc = self.tubA.connectTo(url, self._connected, [], connects)
        rc.verbose = True  # get better code coverage

        # wait for at least one retry
        yield self.poll(lambda: rc.getReconnectionInfo().state == "waiting")

        # and a bit more, for good measure
        yield self.stall(2)

        self.failUnlessEqual(len(connects), 0)
        f = rc.getLastFailure()
        self.failUnless(f.check(error.ConnectionRefusedError))
        delay = rc.getDelayUntilNextAttempt()
        self.failUnless(delay > 0, delay)
        self.failUnless(delay < 60, delay)
        rc.reset()
        delay = rc.getDelayUntilNextAttempt()
        self.failUnless(delay < 2)
        # this stopConnecting occurs while the reconnector's timer is
        # active
        rc.stopConnecting()
        self.failUnlessEqual(rc.getDelayUntilNextAttempt(), None)
예제 #11
0
    def test_bad_hints(self):
        self.tubA = Tub()
        self.tubA.startService()
        self.services.append(self.tubA)
        self.tubB = Tub()
        self.tubB.startService()
        self.services.append(self.tubB)
        portnum = allocate_tcp_port()
        self.tubB.listenOn("tcp:%d:interface=127.0.0.1" % portnum)
        bad1 = "no-colon"
        bad2 = "unknown:foo"
        bad3 = "tcp:300.300.300.300:333"
        self.tubB.setLocation(bad1, bad2, bad3)

        target = HelperTarget("bob")
        url = self.tubB.registerReference(target)
        rc = self.tubA.connectTo(url, None)
        ri = rc.getReconnectionInfo()
        self.assertEqual(ri.state, "connecting")

        yield self.poll(lambda: rc.getReconnectionInfo().state != "connecting")

        # now look at the details
        ri = rc.getReconnectionInfo()
        self.assertEqual(ri.state, "waiting")
        ci = ri.connectionInfo
        self.assertEqual(ci.connected, False)
        self.assertEqual(ci.winningHint, None)
        s = ci.connectorStatuses
        self.assertEqual(set(s.keys()), set([bad1, bad2, bad3]))
        self.assertEqual(s[bad1], "bad hint: no colon")
        self.assertEqual(s[bad2], "bad hint: no handler registered")
        self.assertIn("DNS lookup failed", s[bad3])
        ch = ci.connectionHandlers
        self.assertEqual(ch, {bad2: None, bad3: "tcp"})
예제 #12
0
    def test_stop_trying(self):
        connects = []
        target = HelperTarget("bob")
        url = self.tubB.registerReference(target, "target")
        d1 = defer.Deferred()
        self.services.remove(self.tubB)
        d = self.tubB.stopService()

        def _start_connecting(res):
            # this will fail, since tubB is not listening anymore
            self.rc = self.tubA.connectTo(url, self._connected, d1, connects)
            self.rc.verbose = True  # get better code coverage
            # give it a few tries, then tell it to stop trying
            return self.stall(2)

        d.addCallback(_start_connecting)

        def _stop_trying(res):
            self.failUnlessEqual(len(connects), 0)
            f = self.rc.getLastFailure()
            self.failUnless(f.check(error.ConnectionRefusedError))
            delay = self.rc.getDelayUntilNextAttempt()
            self.failUnless(delay > 0, delay)
            self.failUnless(delay < 60, delay)
            self.rc.reset()
            delay = self.rc.getDelayUntilNextAttempt()
            self.failUnless(delay < 2)
            # this stopConnecting occurs while the reconnector's timer is
            # active
            self.rc.stopConnecting()
            self.failUnlessEqual(self.rc.getDelayUntilNextAttempt(), None)

        d.addCallback(_stop_trying)
        # if it keeps trying, we'll see a dirty reactor
        return d
예제 #13
0
    def testMegaSchema(self):
        # try to exercise all our constraints at once
        rr, target = self.setupTarget(HelperTarget())

        t = (
            set([1, 2, 3]),
            b'bytes',
            True,
            12,
            19.3,
            None,
            'string',
            b'bytestring',
            'any',
            14.3,
            15,
            'a' * 95,
            '1234567890',
        )

        obj1 = {'key': [t]}
        obj2 = (set([1, 2, 3]), [1, 2, 3], {1: 'two'})

        d = rr.callRemote('megaschema', obj1, obj2)
        d.addCallback(lambda res: self.assertEqual(res, None))
        return d
예제 #14
0
    def test_retry(self):
        tubC = Tub(certData=self.tubB.getCertData())
        connects = []
        target = HelperTarget("bob")
        url = self.tubB.registerReference(target, "target")
        portb = self.tub_ports[1]
        d1 = defer.Deferred()
        notifiers = [d1]
        self.services.remove(self.tubB)

        # This will fail, since tubB is not listening anymore. Wait until it's
        # moved to the "waiting" state.
        yield self.tubB.stopService()
        rc = self.tubA.connectTo(url, self._connected, notifiers, connects)
        yield self.poll(lambda: rc.getReconnectionInfo().state == "waiting")
        self.failUnlessEqual(len(connects), 0)

        # now start tubC listening on the same port that tubB used to, which
        # should allow the connection to complete (since they both use the same
        # certData)

        self.services.append(tubC)
        tubC.startService()
        tubC.listenOn("tcp:%d:interface=127.0.0.1" % portb)
        tubC.setLocation("tcp:127.0.0.1:%d" % portb)
        url2 = tubC.registerReference(target, "target")
        assert url2 == url
        yield d1

        self.failUnlessEqual(len(connects), 1)
        rc.stopConnecting()
예제 #15
0
 def testDisconnect_during_call(self):
     rr, target = self.setupTarget(HelperTarget())
     d = rr.callRemote("hang")
     e = RuntimeError("lost connection")
     rr.tracker.broker.transport.loseConnection(Failure(e))
     d.addCallbacks(lambda res: self.fail("should have failed"),
                    lambda why: why.trap(RuntimeError) and None)
     return d
예제 #16
0
 def testMega3(self):
     # exercise a specific bug: shared references don't pass schemas
     t = (0,1)
     obj = [t, t]
     rr, target = self.setupTarget(HelperTarget())
     d = rr.callRemote("mega3", obj)
     d.addCallback(lambda res: self.failUnlessEqual(res, None))
     return d
예제 #17
0
 def createCharacters(self):
     self.alice = HelperTarget("alice")
     self.bob = HelperTarget("bob")
     self.bob_url = self.tubB.registerReference(self.bob, "bob")
     self.carol = HelperTarget("carol")
     self.carol_url = self.tubC.registerReference(self.carol, "carol")
     # cindy is Carol's little sister. She doesn't have a phone, but
     # Carol might talk about her anyway.
     self.cindy = HelperTarget("cindy")
     # more sisters. Alice knows them, and she introduces Bob to them.
     self.charlene = HelperTarget("charlene")
     self.christine = HelperTarget("christine")
     self.clarisse = HelperTarget("clarisse")
     self.colette = HelperTarget("colette")
     self.courtney = HelperTarget("courtney")
     self.dave = HelperTarget("dave")
     self.dave_url = self.tubD.registerReference(self.dave, "dave")
예제 #18
0
 def send(self, arg):
     rr, target = self.setupTarget(HelperTarget())
     d = rr.callRemote("set", obj=arg)
     d.addCallback(self.failUnless)
     # some of these tests require that we return a Failure object, so we
     # have to wrap this in a tuple to survive the Deferred.
     d.addCallback(lambda res: (target.obj, ))
     return d
예제 #19
0
 def testAnswer2(self):
     # but objects returned by separate method calls should be distinct
     rr, target = self.setupTarget(HelperTarget())
     r = [1, 2]
     target.obj = r
     d = rr.callRemote("get")
     d.addCallback(self._testAnswer2_1, rr, target)
     return d
예제 #20
0
    def setUp(self):
        TargetMixin.setUp(self)
        self.tubB = GoodEnoughTub()
        self.services = [self.tubB]
        for s in self.services:
            s.startService()
            l = s.listenOn("tcp:0:interface=127.0.0.1")
            s.setLocation("127.0.0.1:%d" % l.getPortnum())

        self.barry = HelperTarget("barry")
        self.barry_url = self.tubB.registerReference(self.barry)

        self.bill = HelperTarget("bill")
        self.bill_url = self.tubB.registerReference(self.bill)

        self.bob = HelperTarget("bob")
        self.bob_url = self.tubB.registerReference(self.bob)
예제 #21
0
 def testAnswer1(self):
     # also, shared objects in a return value should be shared
     r = [1, 2]
     rr, target = self.setupTarget(HelperTarget())
     target.obj = (r, r)
     d = rr.callRemote("get")
     d.addCallback(lambda res: self.assertIs(res[0], res[1]))
     return d
예제 #22
0
 def testArgs2(self):
     # but sending them as multiple arguments of the *same* method call
     # results in identical objects
     r = [1, 2]
     rr, target = self.setupTarget(HelperTarget())
     d = rr.callRemote("set2", obj1=r, obj2=r)
     d.addCallback(self._testArgs2_1, rr, target)
     return d
예제 #23
0
 def testRef4(self):
     # sending the same Referenceable in multiple calls will result in
     # equivalent RRs
     r = Target()
     rr, target = self.setupTarget(HelperTarget())
     d = rr.callRemote("set", obj=r)
     d.addCallback(self._testRef4_1, rr, r, target)
     return d
예제 #24
0
    def test_reference_counting(self):
        self.source_tub.setOption("expose-remote-exception-types", True)
        target = HelperTarget()
        d = self.setupTarget(target)

        def _stash(rref):
            # to exercise bug #104, we need to trigger remote Violations, so
            # we tell the sending side to not use a RemoteInterface. We do
            # this by reaching inside the RemoteReference and making it
            # forget
            rref.tracker.interfaceName = None
            rref.tracker.interface = None
            self.rref = rref

        d.addCallback(_stash)

        # the first call causes an error, which discards all remaining
        # tokens, including the OPEN tokens for the arguments. The #104 bug
        # is that this causes the open-count to get out of sync, by -2 (one
        # for the arguments sequence, one for the list inside it).
        d.addCallback(
            lambda ign: self.shouldFail(Violation, "one", None, self.rref.
                                        callRemote, "bogus", ["one list"]))

        #d.addCallback(lambda ign:
        #              self.rref.callRemote("set", ["one list"]))

        # a method call that has no arguments (specifically no REFERENCE
        # sequences) won't notice the loss of sync
        d.addCallback(lambda ign: self.rref.callRemote("set", 42))

        def _check_42(ign):
            self.failUnlessEqual(target.obj, 42)

        d.addCallback(_check_42)
        # but when the call takes shared arguments, sync matters
        l = ["list", 1, 2]
        s = set([3, 4])
        t = ("tuple", 5, 6)
        d.addCallback(lambda ign: self.rref.callRemote("set", [t, l, s, t]))

        def _check_shared(ign):
            # the off-by-two bug would cause the second tuple shared-ref to
            # point at the set instead of the first tuple
            self.failUnlessEqual(type(target.obj), list)
            one, two, three, four = target.obj
            self.failUnlessEqual(type(one), tuple)
            self.failUnlessEqual(one, t)
            self.failUnlessEqual(type(two), list)
            self.failUnlessEqual(two, l)
            self.failUnlessEqual(type(three), set)
            self.failUnlessEqual(three, s)
            self.failUnlessEqual(type(four), tuple)  # this is where it fails
            self.failUnlessEqual(four, t)
            self.failUnlessIdentical(one, four)

        d.addCallback(_check_shared)
        return d
예제 #25
0
 def test_try(self):
     self.count = 0
     self.attached = False
     self.done = defer.Deferred()
     target = HelperTarget("bob")
     url = self.tubB.registerReference(target)
     rc = self.tubA.connectTo(url, self._got_ref, "arg", kw="kwarg")
     # at least make sure the stopConnecting method is present, even if we
     # don't have a real test for it yet
     self.failUnless(rc.stopConnecting)
     return self.done
예제 #26
0
 def testConnectAuthenticated(self):
     tub = self.services[0]
     target = HelperTarget("bob")
     target.obj = "unset"
     url = tub.registerReference(target)
     # can we connect to a reference on our own Tub?
     d = tub.getReference(url)
     def _connected(ref):
         return ref.callRemote("set", 12)
     d.addCallback(_connected)
     def _check(res):
         self.failUnlessEqual(target.obj, 12)
     d.addCallback(_check)
     def _connect_again(res):
         target.obj = None
         return tub.getReference(url)
     d.addCallback(_connect_again)
     d.addCallback(_connected)
     d.addCallback(_check)
     return d
예제 #27
0
 def testStallOrdering(self):
     # if the first message hangs (it returns a Deferred that doesn't fire
     # for a while), that shouldn't stall the second message.
     rr, target = self.setupTarget(HelperTarget())
     d0 = rr.callRemote("hang")
     d = rr.callRemote("echo", 1)
     d.addCallback(lambda res: self.failUnlessEqual(res, 1))
     def _done(res):
         target.d.callback(2)
         return d0
     d.addCallback(_done)
     return d
예제 #28
0
 def test_duplicate(self):
     basedir = "test_registration"
     os.makedirs(basedir)
     ff = os.path.join(basedir, "duplicate.furl")
     t1 = HelperTarget()
     tub = UnauthenticatedTub()
     tub.setLocation("bogus:1234567")
     u1 = tub.registerReference(t1, "name", furlFile=ff)
     u2 = tub.registerReference(t1, "name", furlFile=ff)
     self.failUnlessEqual(u1, u2)
     self.failUnlessRaises(WrongNameError,
                           tub.registerReference, t1, "newname", furlFile=ff)
예제 #29
0
 def testArgs1(self):
     # sending the same non-Referenceable object in multiple calls results
     # in distinct objects, because the serialization scope is bounded by
     # each method call
     r = [1, 2]
     rr, target = self.setupTarget(HelperTarget())
     d = rr.callRemote("set", obj=r)
     d.addCallback(self._testArgs1_1, rr, r, target)
     # TODO: also make sure the original list goes out of scope once the
     # method call has finished, to guard against a leaky
     # reference-tracking implementation.
     return d
예제 #30
0
 def testNotifyOnDisconnect_args(self):
     rr, target = self.setupTarget(HelperTarget())
     self.lost = 0
     rr.notifyOnDisconnect(self.disconnected, "arg", foo="kwarg")
     rr.tracker.broker.transport.loseConnection(Failure(CONNECTION_LOST))
     d = flushEventualQueue()
     def _check(res):
         self.failUnless(self.lost)
         self.failUnlessEqual(self.lost_args, (("arg",),
                                               {"foo": "kwarg"}))
     d.addCallback(_check)
     return d
예제 #31
0
 def testConnectAuthenticated(self):
     self.requireCrypto()
     tub = Tub()
     self.startTub(tub)
     target = HelperTarget("bob")
     target.obj = "unset"
     url = tub.registerReference(target)
     # can we connect to a reference on our own Tub?
     d = tub.getReference(url)
     def _connected(ref):
         return ref.callRemote("set", 12)
     d.addCallback(_connected)
     def _check(res):
         self.failUnlessEqual(target.obj, 12)
     d.addCallback(_check)
     def _connect_again(res):
         target.obj = None
         return tub.getReference(url)
     d.addCallback(_connect_again)
     d.addCallback(_connected)
     d.addCallback(_check)
     return d
예제 #32
0
 def testNotifyOnDisconnect_unregister(self):
     rr, target = self.setupTarget(HelperTarget())
     self.lost = 0
     m = rr.notifyOnDisconnect(self.disconnected)
     rr.dontNotifyOnDisconnect(m)
     # dontNotifyOnDisconnect is supposed to be tolerant of duplicate
     # unregisters, because otherwise it is hard to avoid race conditions.
     # Validate that we can unregister something multiple times.
     rr.dontNotifyOnDisconnect(m)
     rr.tracker.broker.transport.loseConnection(Failure(CONNECTION_LOST))
     d = flushEventualQueue()
     d.addCallback(lambda res: self.failIf(self.lost))
     return d
예제 #33
0
 def test_callRemoteOnly(self):
     t = HelperTarget()
     t.obj = None
     rref = IRemoteReference(t)
     rc = rref.callRemoteOnly("set", 12)
     self.failUnlessEqual(rc, None)