1

ここにあります

  • メッセージをリモートの Perspective Broker (PB) Friendに送信するクラスBodyがあります。

  • このテストでは、*speak_ to _friend* またはtellメソッドを呼び出して、 Meインスタンスが Friendと通信できるかどうかをチェックしています。

  • speak _ to _ friendは、 Body.tellメソッド によって上書きされるSoul.speak仮想関数のラッパーです。SoulクラスはBodyにカプセル化されています

  • tellメソッドは、受信したコールバック関数からのgotAnswerイベントを待機することにより、ブロッキング呼び出しをシミュレートします。

  • プリントアウトによると、Friendは単体テストとスタンドアロンの場合と同じ方法でMeと通信します。

問題

...トライアルでunittest ( unittest-me.py ) を実行すると、受信したコールバックが呼び出されることはありません。その代わりに、ばかげたエラー メッセージがクライアント側に表示されます。

接続がきれいに閉じられました

私にとっては、遅延キューが完全に処理される前にリアクターが閉じられているようです。

スタンドアロン テストtest-body.pyを実行している場合、すべてが期待どおりに機能します。

質問

  1. この場合、単体テストの動作が異なるのはなぜですか?
  2. 修正方法は?

単体テスト出力

Python2.7\Scripts\trial.py ..\Soapbox\Node\unittest-me.py
unittest-me
  Trial_TestCase
    test_conversation ... wake upConnecting to localhost:18800

DBG: speak
DBG: say
                                               [FAIL]
Friend not willing to talk with me because:  [Failure instance: Traceback (failure with no frames): <class 'twisted.internet.error.ConnectionDone
'>: Connection was closed cleanly.
]

===============================================================================
[FAIL]
Traceback (most recent call last):
  File "..\Soapbox\Node\unittest-me.py", line 50, in test_conversation
    self.assertTrue(answer is not None, "Friend gave no answer")
twisted.trial.unittest.FailTest: Friend gave no answer

unittest-me.Trial_TestCase.test_conversation
-------------------------------------------------------------------------------
Ran 1 tests in 3.096s

FAILED (failures=1)

テストボディ出力

python test-body.py
connector:  <twisted.internet.tcp.Connector instance at 0x01C87940>
Press any key to continue...Starting reactor


wake upDBG: speak
DBG: say

DBG: received
Friend's reply: <username>
Press any key to continue...

That's all

友人のアウトプット

Dr. Livesey: I got your words: whoami
DBG: answer:  <username>

Dr. Livesey: I got your words: whoami
DBG: answer:  <username>

unittest-me.py

from twisted.trial import unittest
from twisted.spread import pb
from twisted.internet import reactor
from body import Body

class Trial_TestCase(unittest.TestCase):

    def setUp(self):
        self.ref = None
        self.Me = Body('localhost', 18800)
        self.assertTrue(self.Me is not None, "Creating Me assertion failed")
        self.Me.start()

        self.Me.pbFactory = pb.PBClientFactory(self.Me)

        print "Connecting to " + self.Me.hostName + ":" + str(self.Me.portNo)
        connector = reactor.connectTCP(self.Me.hostName,
                                       self.Me.portNo,
                                       self.Me.pbFactory)
        self.addCleanup(connector.disconnect)

        # =====================================================================
        # unittest related parts
        # =====================================================================
        def gotRoot(ref):
            self.ref = ref

        df = self.Me.pbFactory.getRootObject()
        '''
            Without this dummy call, I can say no word - say not called
        '''
        obj = df.addCallback(gotRoot)
        return obj


    def tearDown(self):
        self.Me.remoteObj.broker.transport.loseConnection()
        self.Me.pbFactory.disconnect()
        pass


    def test_conversation(self):
        # answer = self.Me.speak_to_friend()
        answer = self.Me.tell(None)
        self.assertTrue(answer is not None, "Friend gave no answer")

        return self.Me.dm

if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()

test-body.py

if __name__ == '__main__':
    pass

from twisted.spread import pb
from twisted.internet import reactor, threads
import threading
import time
from body import Body

def controlThread(name, body):
    print "Press any key to continue..."
    raw_input()

    body.start()

    result = body.tell(None)

    print "Friend's reply: " + str(result)

    print "Press any key to continue..."
    raw_input()
    reactor.stop()
    pass


body = Body('127.0.0.1', 18800)
f = pb.PBClientFactory(body)
body.pbFactory = f

connector = reactor.connectTCP("127.0.0.1", 18800, f)
print "connector: ", connector

threading.Thread(target=controlThread, args=("Control", body)).start()
print "Starting reactor"
reactor.run()
print "That's all"

body.py

import threading
import types

class Soul():
    def speak(self):
        '''
            virtual method must be overwritten by derived class
        '''
        raise NotImplementedError("I cannot speak without a body. "\
                                  "Please give me body first")
        pass

class Body(threading.Thread):
    def __init__(self, hostname, portno):
        self.hostName = hostname
        self.portNo   = portno

        self.df = None
        self.dg = None
        self.dm = None
        self.remoteObj = None
        self.pbFactory = None

        self.answer = None
        self.gotAnswer = threading.Event()

        self.Soul = Soul()
        self.Soul.speak = types.MethodType(self.tell, self.Soul)

        threading.Thread.__init__(self)
        pass

    def run(self):
        print "wake up"
        pass

    def speak_to_friend(self):
        print 'DBG: speak_to_friend'
        return self.Soul.speak()

    def tell(self, soul):
        print 'DBG: speak'
        self.df = self.pbFactory.getRootObject()

        self.answer = None
        self.gotAnswer.clear()
        self.dg = self.df.addCallback(self.say)
        self.gotAnswer.wait(timeout=3)
        return self.answer

    def say(self, remoteObj):
        print 'DBG: say'
        self.remoteObj = remoteObj
        self.dm = remoteObj.callRemote('talk', 'whoami')
        self.dm.addCallback(self.received)
        self.dm.addErrback(self.broken)
        pass

    def received(self, (answer, result)):
        print 'DBG: received'
        self.answer = '\n\t'.join(str.splitlines(answer))
        self.gotAnswer.set()
        pass

    def broken(self,reason):
        print "Friend not willing to talk with me because: ", reason.getErrorMessage()
        pass

フレンド.py

from twisted.spread import pb
from twisted.internet import reactor
from twisted.internet import defer

from subprocess import Popen
import subprocess

from twisted.web import _newclient


class BrokenError(pb.Error):    pass

class Friend(pb.Root):
    def __init__(self,name):
        self.counter = 0
        self.name = str(name)

    def remote_broken(self):
        msg = "I don't hear you"
        print "Talk louder" % msg
        raise BrokenError(msg)

    def broken(self,reason):
        print "Communication is broken: ", reason.getErrorMessage()
        # print "printError > %r" % failure
        if reason.check(_newclient.RequestGenerationFailed):
            print "printError: RequestGenerationFailed"
            for f in reason.value.reasons:
                print "printError > %r" % f
                print f.getTraceback()
        pass


    def remote_talk(self,words):
        print self.name + ": I got your words: " + words

        process = Popen(words,stdout=subprocess.PIPE)
        answer = process.stdout.read()
        process.wait()

        print "DBG: answer: ", answer

        return (answer, process.returncode)

def main():
    reactor.listenTCP(18800, pb.PBServerFactory(Friend("Dr. Livesey")))
    reactor.run()

if __name__ == '__main__':
    main()
4

0 に答える 0