def setUp(self): # set the signal handler for deadlock self.sig_handler = SignalHandler(self.fail) DUMMY_DATA['Stats']['lname'] = 'test-lname' (self.address, self.port) = get_availaddr() self.stats_httpd_server = ThreadingServerManager(MyStatsHttpd, (self.address, self.port)) self.stats_httpd = self.stats_httpd_server.server self.stats_httpd_server.run() self.client = http.client.HTTPConnection(self.address, self.port) self.client._http_vsn_str = 'HTTP/1.0\n' self.client.connect()
class TestHttpHandler(unittest.TestCase): """Tests for HttpHandler class""" def setUp(self): # set the signal handler for deadlock self.sig_handler = SignalHandler(self.fail) DUMMY_DATA['Stats']['lname'] = 'test-lname' (self.address, self.port) = get_availaddr() self.stats_httpd_server = ThreadingServerManager(MyStatsHttpd, (self.address, self.port)) self.stats_httpd = self.stats_httpd_server.server self.stats_httpd_server.run() self.client = http.client.HTTPConnection(self.address, self.port) self.client._http_vsn_str = 'HTTP/1.0\n' self.client.connect() def tearDown(self): self.client.close() self.stats_httpd_server.shutdown() # reset the signal handler self.sig_handler.reset() @unittest.skipUnless(xml_parser, "skipping the test using XMLParser") def test_do_GET(self): self.assertTrue(type(self.stats_httpd.httpd) is list) self.assertEqual(len(self.stats_httpd.httpd), 1) self.assertEqual((self.address, self.port), self.stats_httpd.http_addrs[0]) def check_XML_URL_PATH(path=''): url_path = '%s/%s' % (stats_httpd.XML_URL_PATH, path) url_path = urllib.parse.quote(url_path) self.client.putrequest('GET', url_path) self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.getheader("Content-type"), "text/xml") self.assertGreater(int(response.getheader("Content-Length")), 0) self.assertEqual(response.status, 200) xml_doctype = response.readline().decode() xsl_doctype = response.readline().decode() self.assertGreater(len(xml_doctype), 0) self.assertGreater(len(xsl_doctype), 0) root = xml.etree.ElementTree.parse(response).getroot() self.assertGreater(root.tag.find('statistics'), 0) schema_loc = '{%s}schemaLocation' % XMLNS_XSI # check the path of XSD self.assertEqual(root.attrib[schema_loc], stats_httpd.XSD_NAMESPACE + ' ' + stats_httpd.XSD_URL_PATH) # check the path of XSL self.assertTrue(xsl_doctype.startswith( '<?xml-stylesheet type="text/xsl" href="' + stats_httpd.XSL_URL_PATH + '"?>')) # check whether the list of 'identifier' attributes in # root is same as the list of item names in DUMMY_DATA id_list = [ elm.attrib['identifier'] for elm in root ] item_list = [ it for it in \ stats_httpd.item_name_list(DUMMY_DATA, path) \ if len(it.split('/')) > 1 ] self.assertEqual(id_list, item_list) for elem in root: attr = elem.attrib value = isc.cc.data.find(DUMMY_DATA, attr['identifier']) # No 'value' attribute should be found in the 'item' # element when datatype of the value is list or dict. if type(value) is list or type(value) is dict: self.assertFalse('value' in attr) # The value of the 'value' attribute should be checked # after casting it to string type if datatype of the # value is int or float. Because attr['value'] returns # string type even if its value is int or float. elif type(value) is int or type(value) is float: self.assertEqual(attr['value'], str(value)) else: self.assertEqual(attr['value'], value) # URL is '/bind10/statistics/xml' check_XML_URL_PATH() for path in stats_httpd.item_name_list(DUMMY_DATA, ''): check_XML_URL_PATH(path) def check_XSD_URL_PATH(): url_path = stats_httpd.XSD_URL_PATH url_path = urllib.parse.quote(url_path) self.client.putrequest('GET', url_path) self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.getheader("Content-type"), "text/xml") self.assertGreater(int(response.getheader("Content-Length")), 0) self.assertEqual(response.status, 200) root = xml.etree.ElementTree.parse(response).getroot() url_xmlschema = '{%s}' % XMLNS_XSD self.assertGreater(root.tag.find('schema'), 0) self.assertTrue(hasattr(root, 'attrib')) self.assertTrue('targetNamespace' in root.attrib) self.assertEqual(root.attrib['targetNamespace'], stats_httpd.XSD_NAMESPACE) # URL is '/bind10/statistics/xsd' check_XSD_URL_PATH() def check_XSL_URL_PATH(): url_path = stats_httpd.XSL_URL_PATH url_path = urllib.parse.quote(url_path) self.client.putrequest('GET', url_path) self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.getheader("Content-type"), "text/xml") self.assertGreater(int(response.getheader("Content-Length")), 0) self.assertEqual(response.status, 200) root = xml.etree.ElementTree.parse(response).getroot() url_trans = '{%s}' % XMLNS_XSL url_xhtml = '{%s}' % XMLNS_XHTML self.assertEqual(root.tag, url_trans + 'stylesheet') # URL is '/bind10/statistics/xsl' check_XSL_URL_PATH() # 302 redirect self.client._http_vsn_str = 'HTTP/1.1' self.client.putrequest('GET', '/') self.client.putheader('Host', self.address) self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 302) self.assertEqual(response.getheader('Location'), "http://%s:%d%s/" % (self.address, self.port, stats_httpd.XML_URL_PATH)) # 404 NotFound (random path) self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', '/path/to/foo/bar') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 404) self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', '/bind10/foo') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 404) self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', '/bind10/statistics/foo') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 404) self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', stats_httpd.XML_URL_PATH + 'Auth') # with no slash self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 404) # 200 ok self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', stats_httpd.XML_URL_PATH + '/') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 200) self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', stats_httpd.XML_URL_PATH + '/#foo') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 200) self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', stats_httpd.XML_URL_PATH + '/?foo=bar') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 200) # 404 NotFound (too long path) self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', stats_httpd.XML_URL_PATH + '/Init/boot_time/a') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 404) # 404 NotFound (nonexistent module name) self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', stats_httpd.XML_URL_PATH + '/Foo') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 404) self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', stats_httpd.XSD_URL_PATH + '/Foo') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 404) self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', stats_httpd.XSL_URL_PATH + '/Foo') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 404) # 404 NotFound (nonexistent item name) self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', stats_httpd.XML_URL_PATH + '/Foo/bar') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 404) self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', stats_httpd.XSD_URL_PATH + '/Foo/bar') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 404) self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', stats_httpd.XSL_URL_PATH + '/Foo/bar') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 404) # 404 NotFound (existent module but nonexistent item name) self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', stats_httpd.XML_URL_PATH + '/Auth/bar') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 404) self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', stats_httpd.XSD_URL_PATH + '/Auth/bar') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 404) self.client._http_vsn_str = 'HTTP/1.0' self.client.putrequest('GET', stats_httpd.XSL_URL_PATH + '/Auth/bar') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 404) def test_do_GET_failed1(self): # failure case (Stats is down, so rpc_call() results in an exception) # Note: this should eventually be RPCRecipientMissing. self.stats_httpd._rpc_answers.append( isc.cc.session.SessionTimeout('timeout')) # request XML self.client.putrequest('GET', stats_httpd.XML_URL_PATH + '/') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 500) # request XSD self.client.putrequest('GET', stats_httpd.XSD_URL_PATH) self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 200) # request XSL self.client.putrequest('GET', stats_httpd.XSL_URL_PATH) self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 200) def test_do_GET_failed2(self): # failure case(Stats replies an error) self.stats_httpd._rpc_answers.append( RPCError(1, "specified arguments are incorrect: I have an error.")) # request XML self.client.putrequest('GET', stats_httpd.XML_URL_PATH + '/') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 404) # request XSD self.stats_httpd._rpc_answers.append( RPCError(1, "specified arguments are incorrect: I have an error.")) self.client.putrequest('GET', stats_httpd.XSD_URL_PATH) self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 200) # request XSL self.stats_httpd._rpc_answers.append( RPCError(1, "specified arguments are incorrect: I have an error.")) self.client.putrequest('GET', stats_httpd.XSL_URL_PATH) self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 200) def test_do_HEAD(self): self.client.putrequest('HEAD', stats_httpd.XML_URL_PATH + '/') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 200) self.client.putrequest('HEAD', '/path/to/foo/bar') self.client.endheaders() response = self.client.getresponse() self.assertEqual(response.status, 404) @unittest.skipUnless(lxml_etree, "skipping XML validation with XSD") def test_xml_validation_with_xsd(self): """Tests for XML validation with XSD. If lxml is not installed, this tests would be skipped.""" def request_xsd(): url_path = stats_httpd.XSD_URL_PATH url_path = urllib.parse.quote(url_path) self.client.putrequest('GET', url_path) self.client.endheaders() xsd_doc = self.client.getresponse() xsd_doc = lxml_etree.parse(xsd_doc) return lxml_etree.XMLSchema(xsd_doc) def request_xmldoc(path=''): url_path = '%s/%s' % (stats_httpd.XML_URL_PATH, path) url_path = urllib.parse.quote(url_path) self.client.putrequest('GET', url_path) self.client.endheaders() xml_doc = self.client.getresponse() return lxml_etree.parse(xml_doc) # request XSD and XML xsd = request_xsd() xml_doc = request_xmldoc() # do validation self.assertTrue(xsd.validate(xml_doc)) # validate each paths in DUMMY_DATA for path in stats_httpd.item_name_list(DUMMY_DATA, ''): # request XML xml_doc = request_xmldoc(path) # do validation self.assertTrue(xsd.validate(xml_doc))