Hi,

I cleaned and covered your implementation of PokerRestClient:
http://pastebin.com/m1eb7a0a1

Name                              Stmts   Exec  Cover   Missing
---------------------------------------------------------------
../pokernetwork/pokerrestclient     171    171   100%   


Feel free to review the attached patch.
-- 
Johan Euphrosine <[email protected]>
Index: pokernetwork/pokerpackets.py
===================================================================
--- pokernetwork/pokerpackets.py	(revision 6210)
+++ pokernetwork/pokerpackets.py	(working copy)
@@ -4596,8 +4596,22 @@
         )
 
 Packet.infoDeclare(globals(), PacketPokerCreateTourney, Packet, "POKER_CREATE_TOURNEY", 166) # 166 # 0xa6 # %SEQ%
+########################################
+class PacketPokerLongPoll(Packet):
+    """ """
+    
+    info = Packet.info
 
+Packet.infoDeclare(globals(), PacketPokerLongPoll, Packet, "POKER_LONG_POLL", 167) # 167 # 0xa7 # %SEQ%
+########################################
+class PacketPokerLongPollReturn(Packet):
+    """ """
+    
+    info = Packet.info
 
+Packet.infoDeclare(globals(), PacketPokerLongPollReturn, Packet, "POKER_LONG_POLL_RETURN", 168) # 168 # 0xa8 # %SEQ%
+
+
 _TYPES = range(50,169)
 
 # Interpreted by emacs
Index: pokernetwork/pokerrestclient.py
===================================================================
--- pokernetwork/pokerrestclient.py	(revision 0)
+++ pokernetwork/pokerrestclient.py	(revision 0)
@@ -0,0 +1,240 @@
+#
+# Copyright (C) 2009 Loic Dachary <[email protected]>
+# Copyright (C) 2009 Johan Euphrosine <[email protected]>
+#
+# This software's license gives you freedom; you can copy, convey,
+# propagate, redistribute and/or modify this program under the terms of
+# the GNU Affero General Public License (AGPL) as published by the Free
+# Software Foundation (FSF), either version 3 of the License, or (at your
+# option) any later version of the AGPL published by the FSF.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program in a file in the toplevel directory called
+# "AGPLv3".  If not, see <http://www.gnu.org/licenses/>.
+#
+
+from twisted.internet import defer, protocol, reactor, error
+from twisted.web import http, client
+from twisted.python.util import InsensitiveDict
+from twisted.python.runtime import seconds
+from pokernetwork.pokerpackets import *
+
+import pokersite
+
+class RestClientFactory(protocol.ClientFactory):
+
+    protocol = client.HTTPPageGetter
+    
+    def __init__(self, host, port, path, data, timeout):
+        self.timeout = timeout
+        self.agent = "RestClient"
+        self.headers = InsensitiveDict()
+        self.headers.setdefault('Content-Length', len(data))
+        self.headers.setdefault("connection", "close")
+        self.method = 'POST'
+        self.url = 'http://' + host + ':' + str(port) + path
+        self.postdata = data
+        self.host = host
+        self.port = port
+        self.path = path
+        self.waiting = 1
+        self.deferred = defer.Deferred()
+        self.response_headers = None
+        self.cookies = {}
+
+    def __repr__(self):
+        return "<%s: %s>" % (self.__class__.__name__, self.url)
+
+    def buildProtocol(self, addr):
+        p = protocol.ClientFactory.buildProtocol(self, addr)
+        if self.timeout:
+            timeoutCall = reactor.callLater(self.timeout, p.timeout)
+            self.deferred.addBoth(self._cancelTimeout, timeoutCall)
+        return p
+
+    def _cancelTimeout(self, result, timeoutCall):
+        if timeoutCall.active():
+            timeoutCall.cancel()
+        return result
+
+    def gotHeaders(self, headers):
+        self.response_headers = headers
+        
+    def gotStatus(self, version, status, message):
+        self.version, self.status, self.message = version, status, message
+
+    def page(self, page):
+        if self.waiting:
+            self.waiting = 0
+            self.deferred.callback(page)
+
+    def noPage(self, reason):
+        if self.waiting:
+            self.waiting = 0
+            self.deferred.errback(reason)
+
+    def clientConnectionFailed(self, _, reason):
+        if self.waiting:
+            self.waiting = 0
+            self.deferred.errback(reason)
+
+class PokerRestClient:
+
+    def __init__(self, host, port, path, verbose, timeout):
+        self.verbose = verbose
+        self.received = lambda packets: True;
+        self.queue = defer.succeed(True)
+        self.pendingLongPoll = False
+        self.minLongPollFrequency = 0.01
+        self.longPollFrequency = 0.1
+        self.sentTime = 0
+        self.host = host
+        self.port = port
+        self.path = path
+        self.timer = None
+        self.timeout = timeout
+        self.longPoll()
+
+    def message(self, string):
+        print 'PokerRestClient(%s) %s' % ( self.host + ':' + str(self.port), string )
+
+    def sendPacket(self, packet, data):
+        if self.pendingLongPoll:
+            if self.verbose > 3:
+                self.message('sendPacket PacketPokerLongPollReturn')
+            self.sendPacketData('{ "type": "PacketPokerLongPollReturn" }')
+        self.queue.addCallback(lambda status: self.sendPacketData(data))
+        if packet.type == PACKET_POKER_LONG_POLL:
+            self.pendingLongPoll = True
+
+    def receivePacket(self, data):
+        print "receivePacket", data
+        if self.pendingLongPoll:
+            self.scheduleLongPoll(0)
+        self.pendingLongPoll = False
+        args = simplejson.loads(data, encoding = 'UTF-8')
+        args = pokersite.fromutf8(args)
+        packets = pokersite.args2packets(args)
+        self.received(packets)
+
+    def receiveError(self, data):
+        self.errorPacket(data)
+
+    def errorPacket(self, reason):
+        self.received([ PacketError(message = str(reason)) ])
+    
+    def sendPacketData(self, data):
+        factory = RestClientFactory(self.host, self.port, self.path, data, self.timeout)
+        reactor.connectTCP(self.host, self.port, factory)
+        factory.deferred.addCallbacks(self.receivePacket, self.receiveError)
+        self.queue.addCallback(lambda arg: factory.deferred)
+        self.sentTime = seconds()
+
+    def clearTimeout(self):
+        if self.timer and self.timer.active():
+            self.timer.cancel()
+        self.timer = None
+        
+    def scheduleLongPoll(self, delta):
+        self.clearTimeout()
+        self.timer = reactor.callLater(max(self.minLongPollFrequency, self.longPollFrequency - delta), self.longPoll)
+
+    def longPoll(self):
+        if self.longPollFrequency > 0:
+            delta = seconds() - self.sentTime
+            in_line = len(self.queue.callbacks)
+            if in_line <= 0 and delta > self.longPollFrequency:
+                self.clearTimeout()
+                self.sendPacket(PacketPokerLongPoll(),'{ "type": "PacketPokerLongPoll" }');
+            else:
+                self.scheduleLongPoll(delta)
+        
+class PokerProxyClient(http.HTTPClient):
+    """
+    Used by PokerProxyClientFactory to implement a simple web proxy.
+    """
+
+    def __init__(self, command, rest, version, headers, data, father):
+        self.father = father
+        self.command = command
+        self.rest = rest
+        if "proxy-connection" in headers:
+            del headers["proxy-connection"]
+        headers["connection"] = "close"
+        self.headers = headers
+        self.data = data
+
+    def connectionMade(self):
+        self.sendCommand(self.command, self.rest)
+        for header, value in self.headers.items():
+            self.sendHeader(header, value)
+        self.endHeaders()
+        self.transport.write(self.data)
+
+    def handleStatus(self, version, code, message):
+        self.father.setResponseCode(int(code), message)
+
+    def handleHeader(self, key, value):
+        self.father.setHeader(key, value)
+
+    def handleResponse(self, buffer):
+        self.father.write(buffer)
+        
+    def connectionLost(self, reason):
+        self.father.finish()
+
+class PokerProxyClientFactory(protocol.ClientFactory):
+
+    serial = 0
+    
+    protocol = PokerProxyClient
+
+    def __init__(self, command, rest, version, headers, data, father, verbose, destination):
+        self.father = father
+        self.command = command
+        self.rest = rest
+        self.headers = headers
+        self.data = data
+        self.version = version
+        self.deferred = defer.Deferred()
+        self.verbose = verbose
+        self.noisy = False
+        self.destination = destination
+        PokerProxyClientFactory.serial += 1
+        self.serial = PokerProxyClientFactory.serial
+
+    def message(self, string):
+        print 'PokerProxyRestClient(%d) %s' % ( self.serial, string )
+
+    def doStart(self):
+        if self.verbose >= 3:
+            self.message('START %s => %s' % ( self.data, self.destination ))
+        protocol.ClientFactory.doStart(self)
+
+    def doStop(self):
+        if self.verbose >= 3:
+            self.message('STOP')
+        protocol.ClientFactory.doStop(self)
+
+#    def error(self, string):
+#	self.message("*ERROR* " + str(string))
+
+    def buildProtocol(self, addr):
+        return self.protocol(self.command, self.rest, self.version,
+                             self.headers, self.data, self.father)
+
+    def clientConnectionFailed(self, connector, reason):
+        if not self.deferred.called:
+            self.deferred.errback(reason)
+
+    def clientConnectionLost(self, connector, reason):
+        if not self.deferred.called:
+            if reason.check(error.ConnectionDone):
+                self.deferred.callback(True)
+            else:
+                self.deferred.errback(reason)
Index: tests/test-pokerrestclient.py.in
===================================================================
--- tests/test-pokerrestclient.py.in	(revision 0)
+++ tests/test-pokerrestclient.py.in	(revision 0)
@@ -0,0 +1,216 @@
+...@python@
+# -*- mode: python -*-
+#
+# Copyright (C) 2009 Loic Dachary <[email protected]>
+# Copyright (C) 2009 Johan Euphrosine <[email protected]>
+#
+# This software's license gives you freedom; you can copy, convey,
+# propagate, redistribute and/or modify this program under the terms of
+# the GNU Affero General Public License (AGPL) as published by the Free
+# Software Foundation (FSF), either version 3 of the License, or (at your
+# option) any later version of the AGPL published by the FSF.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program in a file in the toplevel directory called
+# "AGPLv3".  If not, see <http://www.gnu.org/licenses/>.
+#
+import sys, os
+sys.path.insert(0, "@srcdir@/..")
+sys.path.insert(0, "..")
+
+from twisted.trial import unittest, runner, reporter
+from twisted.internet import defer, reactor
+from twisted.internet import defer
+from twisted.python.util import InsensitiveDict
+
+from tests.testmessages import silence_all_messages
+verbose = int(os.environ.get('VERBOSE_T', '-1'))
+if verbose < 0: silence_all_messages()
+
+from tests import testclock
+
+from pokernetwork import  pokerrestclient
+from pokernetwork import pokerservice
+from pokernetwork import pokernetworkconfig
+from pokernetwork import pokermemcache
+from pokernetwork import pokersite
+from pokernetwork.pokerpackets import *
+
+settings_xml_server = """<?xml version="1.0" encoding="ISO-8859-1"?>
+<server verbose="6" ping="300000" autodeal="yes" simultaneous="4" chat="yes" >
+  <delays autodeal="20" round="0" position="0" showdown="0" autodeal_max="1" finish="0" messages="60" />
+
+  <table name="Table1" variant="holdem" betting_structure="100-200-no-limit" seats="10" player_timeout="60" currency_serial="1" />
+  <table name="Table2" variant="holdem" betting_structure="100-200-no-limit" seats="10" player_timeout="60" currency_serial="1" />
+
+  <listen tcp="19481" />
+  <resthost host="127.0.0.1" port="19481" path="/POKER_REST" />
+
+  <cashier acquire_timeout="5" pokerlock_queue_timeout="30" user_create="yes" />
+  <database name="pokernetworktest" host="localhost" user="pokernetworktest" password="pokernetwork"
+            root_user="@MYSQL_TEST_DBROOT@" root_password="@MYSQL_TEST_DBROOT_PASSWORD@" schema="@srcdir@/../../database/schema.sql" command="@MYSQL@" />
+  <path>.. ../@srcdir@ @POKER_ENGINE_PKGSYSCONFDIR@ @POKER_NETWORK_PKGSYSCONFDIR@</path>
+  <users temporary="BOT"/>
+</server>
+"""
+
+class PokerRestClientTestCase(unittest.TestCase):
+      def destroyDb(self, arg = None):
+            if len("@MYSQL_TEST_DBROOT_PASSWORD@") > 0:
+                  os.system("@MYSQL@ -u @MYSQL_TEST_DBROOT@ --password='@MYSQL_TEST_DBROOT_PASSWORD@' -e 'DROP DATABASE IF EXISTS pokernetworktest'")
+            else:
+                  os.system("@MYSQL@ -u @MYSQL_TEST_DBROOT@ -e 'DROP DATABASE IF EXISTS pokernetworktest'")
+      # --------------------------------------------------------------
+      def initServer(self):
+            settings = pokernetworkconfig.Config([])
+            settings.loadFromString(settings_xml_server)
+            self.server_service = pokerservice.PokerService(settings)
+            self.server_service.disconnectAll = lambda: True
+            self.server_service.startService()
+            self.server_site = pokersite.PokerSite(settings, pokerservice.PokerRestTree(self.server_service))
+            self.server_port = reactor.listenTCP(19481, self.server_site, interface="127.0.0.1")
+      # --------------------------------------------------------------
+      def setUp(self):
+            testclock._seconds_reset()
+            pokermemcache.memcache = pokermemcache.MemcacheMockup
+            pokermemcache.memcache_singleton = {}
+            self.destroyDb()
+            self.initServer()
+      # --------------------------------------------------------------
+      def tearDownServer(self):
+            self.server_site.stopFactory()
+            d = self.server_service.stopService()
+            d.addCallback(lambda x: self.server_port.stopListening())
+            return d
+      # --------------------------------------------------------------
+      def tearDown(self):
+            d = self.tearDownServer()
+            d.addCallback(self.destroyDb)
+            d.addCallback(lambda x: reactor.disconnectAll())
+            return d
+      # --------------------------------------------------------------
+      def test01_longPoll(self):
+            client = pokerrestclient.PokerRestClient('127.0.0.1', 19481, '/POKER_REST', verbose=6, timeout=10)
+            self.assertEquals(True, client.pendingLongPoll)
+            self.assertEquals(None, client.timer)
+            return client.queue
+      # --------------------------------------------------------------
+      def test02_longPollReturn(self):
+            client = pokerrestclient.PokerRestClient('127.0.0.1', 19481, '/POKER_REST', verbose=6, timeout=10)
+            message = client.message
+            def checkMessageString(string):
+                  self.assertSubstring('PacketPokerLongPollReturn', string)
+                  message(string)
+            client.message = checkMessageString
+            client.sendPacket(PacketPokerTableSelect(), '{"type": "PacketPokerTableSelect"}')
+            return client.queue
+      # --------------------------------------------------------------
+      def test03_longPollBis(self):
+            client = pokerrestclient.PokerRestClient('127.0.0.1', 19481, '/POKER_REST', verbose=6, timeout=10)
+            client.longPoll()
+            self.assertNotEquals(None, client.timer)
+            return client.queue
+      
+class MockRequest:
+      def finish(self): pass
+      def setResponseCode(self, arg1, arg2): pass
+      def handlerHeader(self, arg1, arg2): pass
+      def setHeader(self, arg1, arg2): pass
+      def write(self, arg1): pass
+
+class MockReason():
+      def check(self, reason): return False
+
+class PokerProxyClientFactoryTestCase(unittest.TestCase):
+      def destroyDb(self, arg = None):
+            if len("@MYSQL_TEST_DBROOT_PASSWORD@") > 0:
+                  os.system("@MYSQL@ -u @MYSQL_TEST_DBROOT@ --password='@MYSQL_TEST_DBROOT_PASSWORD@' -e 'DROP DATABASE IF EXISTS pokernetworktest'")
+            else:
+                  os.system("@MYSQL@ -u @MYSQL_TEST_DBROOT@ -e 'DROP DATABASE IF EXISTS pokernetworktest'")
+      # --------------------------------------------------------------
+      def initServer(self):
+            settings = pokernetworkconfig.Config([])
+            settings.loadFromString(settings_xml_server)
+            self.server_service = pokerservice.PokerService(settings)
+            self.server_service.disconnectAll = lambda: True
+            self.server_service.startService()
+            self.server_site = pokersite.PokerSite(settings, pokerservice.PokerRestTree(self.server_service))
+            self.server_port = reactor.listenTCP(19481, self.server_site, interface="127.0.0.1")
+      # --------------------------------------------------------------
+      def setUp(self):
+            testclock._seconds_reset()
+            pokermemcache.memcache = pokermemcache.MemcacheMockup
+            pokermemcache.memcache_singleton = {}
+            self.destroyDb()
+            self.initServer()
+      # --------------------------------------------------------------
+      def tearDownServer(self):
+            self.server_site.stopFactory()
+            d = self.server_service.stopService()
+            d.addCallback(lambda x: self.server_port.stopListening())
+            return d
+      # --------------------------------------------------------------
+      def tearDown(self):
+            d = self.tearDownServer()
+            d.addCallback(self.destroyDb)
+            d.addCallback(lambda x: reactor.disconnectAll())
+            return d
+      # --------------------------------------------------------------
+      def test01_proxy(self):
+            data = '{"type": "PacketPing"}'
+            headers = InsensitiveDict()
+            headers.setdefault('Content-Length', len(data))
+            headers.setdefault("connection", "close")
+            headers.setdefault("proxy-connection", "foo")
+            host = '127.0.0.1'
+            port = 19481
+            path = '/POKER_REST'
+            factory = pokerrestclient.PokerProxyClientFactory('POST', path, '1.1', headers, data, MockRequest(), 6, host + ':' + str(port) + path)
+            reactor.connectTCP(host, port, factory)
+            factory.deferred.addCallback(self.assertNotEquals, None)
+            return factory.deferred
+      # --------------------------------------------------------------
+      def test02_proxy_failed(self):
+            factory = pokerrestclient.PokerProxyClientFactory("command", "rest", "version", "headers", "data", "father",
+                                                              "verbose", "destination")
+            def errback(reason):
+                  self.assertNotEquals(None, reason)
+            factory.deferred.addErrback(errback)
+            factory.clientConnectionFailed(None, MockReason())
+            return factory.deferred
+      # --------------------------------------------------------------
+      def test03_proxy_lost(self):
+            factory = pokerrestclient.PokerProxyClientFactory("command", "rest", "version", "headers", "data", "father",
+                                                              "verbose", "destination")
+            def errback(reason):
+                  self.assertNotEquals(None, reason)
+            factory.deferred.addErrback(errback)
+            factory.clientConnectionLost(None, MockReason())
+            return factory.deferred
+
+def Run():
+    loader = runner.TestLoader()
+#    loader.methodPrefix = "test01"
+    suite = loader.suiteFactory()
+    suite.addTest(loader.loadClass(PokerRestClientTestCase))
+    suite.addTest(loader.loadClass(PokerProxyClientFactoryTestCase))
+    return runner.TrialRunner(
+        reporter.VerboseTextReporter,
+        tracebackFormat='default',
+        ).run(suite)
+
+if __name__ == '__main__':
+    if Run().wasSuccessful():
+        sys.exit(0)
+    else:
+        sys.exit(1)
+
+# Interpreted by emacs
+# Local Variables:
+# compile-command: "( cd .. ; ./config.status tests/test-pokerrestclient.py ) ; ( cd ../tests ; make COVERAGE_FILES='../pokernetwork/pokerrestclient.py' VERBOSE_T=-1 TESTS='coverage-reset test-pokerrestclient.py coverage-report' check )"
+# End:
Index: configure.ac
===================================================================
--- configure.ac	(revision 6210)
+++ configure.ac	(working copy)
@@ -274,6 +274,7 @@
 	tests/test-leak-exarkun.py
 	tests/test-pokerserver.py
 	tests/test-pokerserver-run-load.py
+	tests/test-pokerrestclient.py
         tests/testcurrency.php
         tests/testpoker.php
         tests/testbirthday.php
Index: Makefile.am
===================================================================
--- Makefile.am	(revision 6210)
+++ Makefile.am	(working copy)
@@ -82,6 +82,7 @@
 	pokernetwork/protocol.py \
 	pokernetwork/proxy.py \
 	pokernetwork/proxyfilter.py \
+	pokernetwork/pokerrestclient.py \
 	pokernetwork/server.py \
 	pokernetwork/user.py \
 	pokernetwork/userstats.py \

Attachment: signature.asc
Description: This is a digitally signed message part

_______________________________________________
Pokersource-users mailing list
[email protected]
https://mail.gna.org/listinfo/pokersource-users

Reply via email to