Added a few notes about why this is difficult to test.

- Reorganized file a little.
- Test requests are now from and to real clients.
This commit is contained in:
Nick Daly 2012-03-22 07:19:58 -05:00
parent bffb2d93b5
commit 2d1e473a9b

View File

@ -1,3 +1,6 @@
#! /usr/bin/python -*- mode: autofill; fill-column: 80 -*-
"""Making Santiago dance, in 4 parts:
- Validating the initial request (playing B).
@ -11,8 +14,33 @@
- Validating the direct response (playing A).
- Validating the indirect response (playing C, B, and A).
FIXME: Can't use the current CPy setup. It never returns, so I can't test
against it.
If I produce a listener that just echoes the parameters, I can validate the response:
import httplib, urllib
params = urllib.urlencode({'@number': 12524, '@type': 'issue', '@action': 'show'})
headers = {"Content-type": "application/x-www-form-urlencoded",
"Accept": "text/plain"}
conn = httplib.HTTPConnection("bugs.python.org")
print params, headers, conn
conn.request("POST", "", params, headers)
response = conn.getresponse()
print response.status, response.reason
data = response.read()
print data
conn.close()
"""
import cherrypy
import unittest
from protocols.http import SantiagoHttpSender, SantiagoHttpListener
import santiago
@ -43,6 +71,29 @@ class SantiagoTest(unittest.TestCase):
self.santiago_a = Santiago(listeners_a, senders_a, hosting_a, consuming_a)
self.santiago_b = Santiago(listeners_b, senders_b, hosting_b, consuming_b)
def serveOnPort(self, port):
"""Start listening for connections on a named port.
Used in testing as a mock listener for responses from a Santiago server.
"""
class RequestReceiver(object):
"""A very basic listener.
It merely records the calling arguments.
"""
@cherrypy.expose
def index(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
self.socket_port = port
self.receiver = RequestReceiver()
cherrypy.quickstart(self.receiver)
if sys.version_info < (2, 7):
"""Add a poor man's forward compatibility."""
@ -53,6 +104,44 @@ class SantiagoTest(unittest.TestCase):
if not a in b:
raise self.ContainsError("%s not in %s" % (a, b))
class TestClientInitialRequest(SantiagoTest):
"""Does the client send a correctly formed request?
In these tests, we're sending requests to a mock listener which merely
records that the requests were well-formed.
"""
def setUp(self):
super(SantiagoTest, self).setUp()
self.serveOnPort(8000)
def test_request(self):
"""Verify that A queues a properly formatted initial request."""
self.santiago_a.request(from_="a", to="b",
client="a", host="b",
service="wiki", reply_to="localhost:9001")
self.assertEqual(self.santiago_a.outgoing_messages,
[{ "from": "a", "to": "b",
"client": "a", "host": "b",
"service": "wiki", "reply-to": "localhost:9001"}])
def test_request(self):
"""Verify that A sends out a properly formatted initial request."""
self.santiago_a.request(from_="a", to="b",
client="a", host="b",
service="wiki", reply_to="localhost:9001")
self.santiago_a.process()
self.assertEqual(self.receiver.kwargs,
[{ "from": "a", "to": "b",
"client": "a", "host": "b",
"service": "wiki", "reply-to": "localhost:9001"}])
class TestServerInitialRequest(SantiagoTest):
"""Test how the Santiago server replies to initial service requests.
@ -68,6 +157,11 @@ class TestServerInitialRequest(SantiagoTest):
untrusted client, B ignores it.
"""
def setUp(self):
super(SantiagoTest, self).setUp()
self.serveOnPort(9000)
def test_acknowledgement(self):
"""If B receives an authorized request, then it replies with a location.
@ -77,7 +171,7 @@ class TestServerInitialRequest(SantiagoTest):
In this case, B will answer with the wiki's location.
"""
self.santiago_b.receive(from_=None, to=None,
self.santiago_b.receive(from_="a", to="b",
client="a", host="b",
service="wiki", reply_to=None)
@ -90,13 +184,13 @@ class TestServerInitialRequest(SantiagoTest):
"locations": ["192.168.0.13"],
"reply-to": "localhost:8000"}])
def test_reject_bad_service(self)
def test_reject_bad_service(self):
"""Does B reject requests for unsupported services?
In this case, B should reply with an empty list of locations.
"""
self.santiago_b.receive(from_=None, to=None,
self.santiago_b.receive(from_="a", to="b",
client="a", host="b",
service="wiki", reply_to=None)
@ -119,7 +213,7 @@ class TestServerInitialRequest(SantiagoTest):
In this case, B will never answer the request.
"""
self.santiago_b.receive(from_=None, to=None,
self.santiago_b.receive(from_="a", to="b",
client="z", host="b",
service="wiki", reply_to=None)
@ -132,7 +226,11 @@ class TestServerInitialRequest(SantiagoTest):
untrusted key connection attempt.
"""
self.fail()
self.santiago_b.receive(from_="a", to="b",
client="z", host="b",
service="wiki", reply_to=None)
self.assertEqual(self.santiago_b.outgoing_messages, [])
def test_reject_bad_source_good_client(self):
"""B is silent when an untrusted key proxies anything for a trusted key.
@ -141,7 +239,11 @@ class TestServerInitialRequest(SantiagoTest):
untrusted key connection attempt.
"""
self.fail()
self.santiago_b.receive(from_="z", to="b",
client="a", host="b",
service="wiki", reply_to=None)
self.assertEqual(self.santiago_b.outgoing_messages, [])
def test_reject_bad_source_bad_client(self):
"""B is silent when untrusted keys proxy anything for untrusted keys.
@ -150,7 +252,11 @@ class TestServerInitialRequest(SantiagoTest):
connection attempt.
"""
self.fail()
self.santiago_b.receive(from_="y", to="b",
client="z", host="b",
service="wiki", reply_to=None)
self.assertEqual(self.santiago_b.outgoing_messages, [])
def test_learn_santaigo(self):
"""Does B learn new Santiago locations from trusted requests?
@ -158,7 +264,7 @@ class TestServerInitialRequest(SantiagoTest):
If A sends B a request with a new Santiago location, B should learn it.
"""
self.santiago_b.receive(from_=None, to=None,
self.santiago_b.receive(from_="a", to="b",
client="a", host="b",
service="wiki", reply_to="localhost:9001")
@ -168,62 +274,13 @@ class TestServerInitialRequest(SantiagoTest):
def test_handle_requests_once(self):
"""Verify that we reply to each request only once."""
self.santiago_b.receive(from_=None, to=None,
self.santiago_b.receive(from_="a", to="b",
client="a", host="b",
service="wiki", reply_to=None)
self.santiago_b.process()
self.assertEqual(self.santiago_b.outgoing_messages, [])
class TestClientInitialRequest(SantiagoTest):
"""Does the client send a correctly formed request?
In these tests, we're sending requests to a mock listener which merely
records that the requests were well-formed.
"""
def setUp(self):
super(SantiagoTest, self).setUp()
import cherrypy
class RequestReceiver(object):
def index(self, *args, **kwargs):
self.args = *args
self.kwargs = **kwargs
index.exposed = True
self.socket_port = 8000
self.receiver = RequestReceiver()
cherrypy.quickstart(self.receiver)
def test_request(self):
"""Verify that A queues a properly formatted initial request."""
self.santiago_a.request(from_="a", to="b",
client="a", host="b",
service="wiki", reply_to="localhost:9001")
self.assertEqual(self.santiago_a.outgoing_messages,
[{ "from": "a", "to": "b",
"client": "a", "host": "b",
"service": "wiki", "reply-to": "localhost:9001"})]
def test_request(self):
"""Verify that A sends out a properly formatted initial request."""
self.santiago_a.request(from_="a", to="b",
client="a", host="b",
service="wiki", reply_to="localhost:9001")
self.santiago_a.process()
self.assertEqual(self.receiver.kwargs,
[{ "from": "a", "to": "b",
"client": "a", "host": "b",
"service": "wiki", "reply-to": "localhost:9001"})]
class TestServerInitialResponse(SantiagoTest):
pass