text: #!/usr/bin/env python3
  # coding: utf-8
  # Copyright 2013 Abram Hindle
  # 
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  # 
  #     http://www.apache.org/licenses/LICENSE-2.0
  # 
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  #
  # run python freetests.py
  
  import unittest
  import httpclient
  import http.server
  import threading
  import socketserver
  import random
  import time
  import urllib.parse
  import json
  
  BASEHOST = '127.0.0.1'
  BASEPORT = 27600 + random.randint(1,100)
  
  
  httpclass = httpclient
  #import mysolution
  #httpclass = mysolution
  
  # Sorry but in Python this comes out of the box!
  class MyHTTPHandler(http.server.BaseHTTPRequestHandler):
      post = None 
      get = None
      def do_POST(self):
          try:
              if (self.post == None):
                  return None
              else:
                  return self.post()
          except Exception as e:
              print("Exception %s\n" % e)
              raise e
  
      def do_GET(self):
          try:
              print("GET %s\n" % self.path)
              if (self.get == None):
                  return None
              else:
                  return self.get()
          except Exception as e:
              print("Exception %s\n" % e)
              raise e
  
  def make_http_server(host = BASEHOST, port = BASEPORT):
      return http.server.HTTPServer( (host, port) , MyHTTPHandler)
  
  # always returns 404
  def nothing_available(self):
      self.send_error(404, "File not found")
      self.end_headers()
      self.wfile.write(bytes("","utf-8"))
  
  # repeats your path back
  def echo_path_get(self):
      self.send_response(200)
      self.send_header("Content-type", "text/plain")
      self.end_headers()
      self.wfile.write(bytes("%s\n" % self.path,"utf-8"))
  
  # repeats your post back as json
  def echo_post(self):
      length = int(self.headers['Content-Length'])
      post_data = urllib.parse.parse_qs(self.rfile.read(length).decode('utf-8'))
      self.send_response(200)
      self.send_header("Content-type", "application/json")
      self.end_headers()
      self.wfile.write(bytes(json.dumps(post_data),"utf-8"))
  
  def header_check(self):
      response = 200
      errors = []
      if 'Host' not in self.headers:
          response = 400
          errors.append("No Host header found")
      self.send_response(response)
      self.send_header("Content-type", "application/json")
      self.end_headers()
      self.wfile.write(bytes(json.dumps(errors),"utf-8"))
  
  def die_on_method(self):
      response = 405
      errors = []
      errors.append("Method Not Allowed")
      if 'Host' not in self.headers:
          errors.append("No Host header found")
      self.send_response(response)
      self.send_header("Content-type", "application/json")
      self.end_headers()
      self.wfile.write(bytes(json.dumps(errors),"utf-8"))
  
  def post_header_check(self):
      response = 200
      errors = []
      if 'Host' not in self.headers:
          response = 400
          errors.append("No Host header found")
      if 'Content-length' not in self.headers:
          response = 400
          errors.append("No Content-Length header found")
      self.send_response(response)
      self.send_header("Content-type", "application/json")
      self.end_headers()
      self.wfile.write(bytes(json.dumps(errors),"utf-8"))
  
  
  
  
  class TestHTTPClient(unittest.TestCase):
      httpd = None
      running = False
  
      @classmethod
      def setUpClass(self):
          '''Cache the httpd server and run it as a thread'''
          if (TestHTTPClient.httpd == None):
              try:
                  self.thread = threading.Thread(target=self.run_server).start()
                  time.sleep(1)
              except Exception as e:
                  print(e)
                  print("setUP: Thread died")
                  raise(e)
  
      @classmethod
      def run_server(self):
          '''run the httpd server in a thread'''
          try:    
              socketserver.TCPServer.allow_reuse_address = True
              http.server.HTTPServer.allow_reuse_address = True
              TestHTTPClient.httpd = make_http_server()
              print("HTTP UP!\n")
              TestHTTPClient.httpd.serve_forever()
              print("HTTP has been shutdown!\n")
          except Exception as e:
              print(e)
              print("run_server: Thread died")
  
  
  
      def test404GET(self):
          '''Test against 404 errors'''
          MyHTTPHandler.get = nothing_available
          http = httpclass.HTTPClient()
          req = http.GET("http://%s:%d/49872398432" % (BASEHOST,BASEPORT) )
          self.assertTrue(req != None, "None Returned!")
          self.assertTrue(req.code == 404)
  
      def test404POST(self):
          '''Test against 404 errors'''
          MyHTTPHandler.post = nothing_available
          http = httpclass.HTTPClient()
          req = http.POST("http://%s:%d/49872398432" % (BASEHOST,BASEPORT) )
          self.assertTrue(req != None, "None Returned!")
          self.assertTrue(req.code == 404)
  
      def testGET(self):
          '''Test HTTP GET'''
          MyHTTPHandler.get = echo_path_get
          http = httpclass.HTTPClient()
          path = "abcdef/gjkd/dsadas"
          url = "http://%s:%d/%s" % (BASEHOST,BASEPORT, path)
          req = http.GET( url )
          self.assertTrue(req != None, "None Returned!")
          self.assertTrue(req.code == 200)
          self.assertTrue(req.body.find(path)>=0, "Data: [%s] " % req.body)
  
      def testGETHeaders(self):
          '''Test HTTP GET Headers'''
          MyHTTPHandler.get = header_check
          MyHTTPHandler.post = die_on_method
          http = httpclass.HTTPClient()
          path = "abcdef/gjkd/dsadas"
          url = "http://%s:%d/%s" % (BASEHOST,BASEPORT, path)
          req = http.GET( url )
          self.assertTrue(req != None, "None Returned!")
          self.assertTrue(req.code == 200)
  
      def testPOSTHeaders(self):
          '''Test HTTP POST Headers'''
          MyHTTPHandler.post = post_header_check
          MyHTTPHandler.get  = die_on_method
          http = httpclass.HTTPClient()
          path = "abcdef/gjkd/dsadas"
          url = "http://%s:%d/%s" % (BASEHOST,BASEPORT, path)
          req = http.POST( url )
          self.assertTrue(req != None, "None Returned!")
          self.assertTrue(req.code == 200,"Code is %s but I wanted a 200 OK" % req.code)
  
          
          
      # consider disabling this test until everything else works
      def testInternetGets(self):
          '''Test HTTP Get in the wild, these webservers are far less
             forgiving'''
          MyHTTPHandler.get = echo_path_get
          http = httpclass.HTTPClient()        
          urls = [
              "http://www.cs.ualberta.ca/",
              "http://softwareprocess.es/static/SoftwareProcess.es.html",
              "http://c2.com/cgi/wiki?CommonLispHyperSpec",
              "http://slashdot.org",
              "http://www.google.com/"
              ]
          for url in urls:
              try:
                  req = http.GET( url )
              except Exception as e:
                  print("An Exception was thrown for %s" % url)
                  self.assertTrue( False, "An Exception was thrown for %s %s" % (url,e))
              self.assertTrue(req != None, "None Returned! %s" % url)
              self.assertTrue(req.code == 200 or 
                              req.code == 301 or
                              req.code == 302,
                              "Code: %s for %s" % (req.code, url))
              if (req.code == 200):
                  self.assertTrue(req.body.find("DOCTYPE")>=0 or 
                                  req.body.find("<body")>=0 , 
                                  "%s Data: [%s] " % (url,req.body))
      
      def testPOST(self):
          '''Test HTTP POST with an echo server'''
          MyHTTPHandler.post = echo_post
          http = httpclass.HTTPClient()
          path = "post_echoer"
          url = "http://%s:%d/%s" % (BASEHOST,BASEPORT, path)
          args = {'a':'aaaaaaaaaaaaa',
                  'b':'bbbbbbbbbbbbbbbbbbbbbb',
                  'c':'c',
                  'd':'012345\r67890\n2321321\n\r'}
          print("Sending POST!")
          req = http.POST( url, args=args )
          self.assertTrue(req != None, "None Returned!")
          self.assertTrue(req.code == 200)
          print("Test Post Body: [%s]" % req.body)
          outargs = json.loads(req.body)
          print(outargs.__class__)
          for key in args:
              self.assertTrue(args[key] == outargs[key][0], "Key [%s] not found" % key)
          for key in outargs:
              self.assertTrue(args[key] == outargs[key][0], "Key [%s] not found" % key)
  
      @classmethod
      def tearDownClass(self):        
          if (TestHTTPClient.httpd!=None):
              print("HTTP Shutdown in tearDown\n")
              TestHTTPClient.httpd.shutdown()
              TestHTTPClient.httpd.server_close()
              time.sleep(1)
  
  def test_test_webserver():
      print("http://%s:%d/dsadsadsadsa\n" % (BASEHOST,BASEPORT) )
      MyHTTPHandler.get = echo_path_get
      MyHTTPHandler.post = echo_post
      httpd = make_http_server()
      try:
          httpd.serve_forever()
      finally:
          httpd.shutdown()
  
  if __name__ == '__main__':
      unittest.main()
  