Make devel/test.py less repetitive.
authorEmil Mikulic <emikulic@gmail.com>
Mon, 17 Jan 2011 13:51:56 +0000 (00:51 +1100)
committerEmil Mikulic <emikulic@gmail.com>
Sun, 28 Apr 2013 10:41:30 +0000 (20:41 +1000)
devel/test.py

index 6a282d6..cb36822 100755 (executable)
@@ -2,6 +2,7 @@
 import unittest
 import socket
 import signal
+import re
 
 class Conn:
     def __init__(self):
@@ -10,11 +11,19 @@ class Conn:
         self.s.connect(("0.0.0.0", self.port))
         # connect throws socket.error on connection refused
 
-    def get(self, req):
+    def get(self, url, http_ver=None, endl="\n",
+            req_hdrs={"User-Agent": "test.py"}):
+        req = "GET "+url
+        if http_ver is not None:
+            req += " HTTP/"+http_ver
+        req += "\n"
+        for k,v in req_hdrs.items():
+            req += k+": "+v+endl
+        req += endl # end of request
         self.s.send(req)
         ret = ""
         while True:
-            signal.alarm(1)
+            signal.alarm(1) # don't wait forever
             r = self.s.recv(65536)
             signal.alarm(0)
             if r == "":
@@ -23,6 +32,20 @@ class Conn:
                 ret += r
         return ret
 
+def parse(resp):
+    """
+    Parse response into status line, headers and body.
+    """
+    pos = resp.index("\r\n\r\n") # throws exception on failure
+    head = resp[:pos]
+    body = resp[pos+4:]
+    status,head = head.split("\r\n", 1)
+    hdrs = {}
+    for line in head.split("\r\n"):
+        k, v = line.split(": ", 1)
+        hdrs[k] = v
+    return (status, hdrs, body)
+
 class TestCases(unittest.TestCase):
     def assertContains(self, body, *strings):
         for s in strings:
@@ -43,41 +66,78 @@ class TestCases(unittest.TestCase):
             "You requested an invalid URI: %s\n"%path,
             'Generated by darkhttpd')
 
-    # FIXME: failing
-    #def testIndex_HTTP_0_9(self):
-    #    body = Conn().get("GET /\n\n")
-    #    self.assertIsIndex(body)
+def nerf(s):
+    return re.sub("[^a-zA-Z0-9]", "_", s)
+
+def makeCase(name, url, hdr_checker=None, body_checker=None,
+             req_hdrs={"User-Agent": "test.py"},
+             http_ver=None, endl="\n"):
+    def do_test(self):
+        resp = Conn().get(url, http_ver, endl, req_hdrs)
+        if http_ver is None:
+            status = ""
+            hdrs = {}
+            body = resp
+        else:
+            status, hdrs, body = parse(resp)
+
+        if hdr_checker is not None and http_ver is not None:
+            hdr_checker(self, hdrs)
+
+        if body_checker is not None:
+            body_checker(self, body)
+
+        # FIXME: check status
+        if http_ver is not None:
+            prefix = "HTTP/1.1 " # should 1.0 stay 1.0?
+            self.assertTrue(status.startswith(prefix),
+                msg="%s at start of %s"%(repr(prefix), repr(status)))
+
+    v = http_ver
+    if v is None:
+        v = "0.9"
+    test_name = "_".join([
+        "test",
+        nerf(name),
+        nerf("HTTP"+v),
+        {"\n":"LF", "\r\n":"CRLF"}[endl],
+    ])
+    setattr(TestCases, test_name, do_test)
+
+def makeCases(name, url, hdr_checker=None, body_checker=None,
+              req_hdrs={"User-Agent": "test.py"}):
+    # FIXME: 0.9 is broken
+    #for http_ver in [None, "1.0", "1.1"]:
+    for http_ver in ["1.0", "1.1"]:
+        for endl in ["\n", "\r\n"]:
+            makeCase(name, url, hdr_checker, body_checker,
+                     req_hdrs, http_ver, endl)
 
-    def testIndex_HTTP_1_0(self):
-        body = Conn().get("GET / HTTP/1.0\n\n")
-        self.assertIsIndex(body, "/")
+makeCases("index", "/", None,
+    lambda self,body: self.assertIsIndex(body, "/"))
 
-    def testUpDirValid(self):
-        body = Conn().get("GET /dir/../ HTTP/1.0\n\n")
-        self.assertIsIndex(body, "/dir/../")
+makeCases("up dir", "/dir/../", None,
+    lambda self,body: self.assertIsIndex(body, "/dir/../"))
 
-    def testExtraneousSlashes(self):
-        body = Conn().get("GET //dir///..//// HTTP/1.0\n\n")
-        self.assertIsIndex(body, "//dir///..////")
+makeCases("extra slashes", "//dir///..////", None,
+    lambda self,body: self.assertIsIndex(body, "//dir///..////"))
 
-    def testWithoutTrailingSlash(self):
-        body = Conn().get("GET /dir/.. HTTP/1.0\n\n")
-        self.assertIsIndex(body, "/dir/..")
+makeCases("no trailing slash", "/dir/..", None,
+    lambda self,body: self.assertIsIndex(body, "/dir/.."))
 
-    def testWithoutLeadingSlashFails(self):
-        body = Conn().get("GET dir/../ HTTP/1.0\n\n")
-        self.assertIsInvalid(body, "dir/../")
+makeCases("no leading slash", "dir/../", None,
+    lambda self,body: self.assertIsInvalid(body, "dir/../"))
 
-    def testUpDirInvalid(self):
-        body = Conn().get("GET /../ HTTP/1.0\n\n")
-        self.assertIsInvalid(body, "/../")
+makeCases("invalid up dir", "/../", None,
+    lambda self,body: self.assertIsInvalid(body, "/../"))
 
-    def testUpDirInvalidFancy(self):
-        body = Conn().get("GET /dir/../../ HTTP/1.0\n\n")
-        self.assertIsInvalid(body, "/dir/../../")
+makeCases("fancy invalid up dir", "/./dir/./../../", None,
+    lambda self,body: self.assertIsInvalid(body, "/./dir/./../../"))
 
 if __name__ == '__main__':
     unittest.main()
-    #print Conn().get("GET /xyz/../ HTTP/1.0")
+    #x = Conn().get("/xyz/../", "1.0")
+    #y = parse(x)
+    #print repr(y)
 
 # vim:set ts=4 sw=4 et: