## ## import unittest import urllib2 from HTMLParser import HTMLParser from xml.etree.ElementTree import parse as parseXml from json import load as loadjson from urlparse import urljoin from base64 import b64encode # # Test the localizaiton REST service. # # SOFTWARE HISTORY # # Date Ticket# Engineer Description # --------- -------- --------- -------------------------- # 08/07/17 5731 bsteffen Initial Creation. baseURL = "http://localhost:9581/services/localization/" testSite = "OAX" testDir = "menus" testFile = "test.xml" username = "test" password = username base64string = b64encode('%s:%s' % (username, password)) authString = "Basic %s" % base64string class ValidHTMLParser(HTMLParser): """Simple HTML parser that performs very minimal validation. This ensures that all start and end tags match, and also that there are some tags. It also accumulates the text of all links in the html file in the link_texts attribute, which can be used for further validation. """ def __init__(self, testcase): HTMLParser.__init__(self) self._testcase = testcase self._tags = [] self._any = False self.link_texts = [] def handle_starttag(self, tag, attrs): self._tags.append(tag) self._any = True def handle_endtag(self, tag): self._testcase.assertNotEquals([], self._tags, "Unstarted end tag " + tag) self._testcase.assertEquals(tag, self._tags.pop()) def handle_data(self, data): if self._tags[-1] == "a": self.link_texts.append(data) def close(self): HTMLParser.close(self) self._testcase.assertTrue(self._any) self._testcase.assertEquals([], self._tags) class AbstractListingTestCase(): """Base test case for testing listings, retrieves data as html, xml, and json. Sub classes should implement assertValidHtml, assertValidXml, and assertValidJson to ensure that the content returned matches what was expected. """ def assertRequestGetsHtml(self, request): response = urllib2.urlopen(request) self.assertEquals(response.headers["Content-Type"], "text/html") body = response.read() parser = ValidHTMLParser(self) parser.feed(body) parser.close() self.assertValidHtml(parser) def assertValidHtml(self, parser): """Intended to be overriden by subclasses to validate HTML content. The argument is a populated instance of ValidHTMLParser. """ pass def test_default(self): request = urllib2.Request(self.url) self.assertRequestGetsHtml(request) def test_last_slash(self): if self.url.endswith("/"): request = urllib2.Request(self.url[:-1]) else: request = urllib2.Request(self.url + "/") self.assertRequestGetsHtml(request) def test_wild_mime(self): request = urllib2.Request(self.url) request.add_header("Accept", "*/*") self.assertRequestGetsHtml(request) request.add_header("Accept", "text/*") self.assertRequestGetsHtml(request) def test_html(self): request = urllib2.Request(self.url) request.add_header("Accept", "text/html") self.assertRequestGetsHtml(request) def test_json(self): request = urllib2.Request(self.url) request.add_header("Accept", "application/json") response = urllib2.urlopen(request) self.assertEquals(response.headers["Content-Type"], "application/json") jsonData = loadjson(response) self.assertValidJson(jsonData) def assertValidJson(self, jsonData): """Intended to be overriden by subclasses to validate JSON content. The argument is a python object as returned from json.load """ pass def test_xml(self): request = urllib2.Request(self.url) request.add_header("Accept", "application/xml") response = urllib2.urlopen(request) self.assertEquals(response.headers["Content-Type"], "application/xml") xmlData = parseXml(response) self.assertValidXml(xmlData) def assertValidXml(self, xmlData): """Intended to be overriden by subclasses to validate XML content. The argument is an ElementTree """ pass def test_delete(self): request = urllib2.Request(self.url) request.get_method = lambda: "DELETE" with self.assertRaises(urllib2.HTTPError) as cm: response = urllib2.urlopen(request) self.assertEqual(405, cm.exception.code) def test_put(self): request = urllib2.Request(self.url) request.get_method = lambda: "PUT" request.add_data("Test Data") with self.assertRaises(urllib2.HTTPError) as cm: response = urllib2.urlopen(request) self.assertEqual(405, cm.exception.code) def test_unacceptable(self): request = urllib2.Request(self.url) request.add_header("Accept", "application/fakemimetype") with self.assertRaises(urllib2.HTTPError) as cm: response = urllib2.urlopen(request) self.assertEqual(406, cm.exception.code) request.add_header("Accept", "fakemimetype/*") with self.assertRaises(urllib2.HTTPError) as cm: response = urllib2.urlopen(request) self.assertEqual(406, cm.exception.code) def test_accept_quality_factor(self): request = urllib2.Request(self.url) request.add_header("Accept", "application/xml; q=0.8, application/json; q=0.2") response = urllib2.urlopen(request) self.assertEquals(response.headers["Content-Type"], "application/xml") xmlData = parseXml(response) self.assertValidXml(xmlData) request.add_header("Accept", "application/xml; q=0.2, application/json; q=0.8") response = urllib2.urlopen(request) self.assertEquals(response.headers["Content-Type"], "application/json") jsonData = loadjson(response) self.assertValidJson(jsonData) request.add_header("Accept", "application/xml, application/json; q=0.8") response = urllib2.urlopen(request) self.assertEquals(response.headers["Content-Type"], "application/xml") xmlData = parseXml(response) self.assertValidXml(xmlData) request.add_header("Accept", "application/fakemimetype, application/json; q=0.8") response = urllib2.urlopen(request) self.assertEquals(response.headers["Content-Type"], "application/json") jsonData = loadjson(response) self.assertValidJson(jsonData) class RootTestCase(AbstractListingTestCase, unittest.TestCase): """Test that the root of the localization service returns listing of localization types.""" def setUp(self): self.url = baseURL def assertValidHtml(self, parser): self.assertIn("common_static/", parser.link_texts) def assertValidJson(self, jsonData): self.assertIn("common_static/", jsonData) def assertValidXml(self, xmlData): root = xmlData.getroot() self.assertEquals(root.tag, "entries") names = [e.text for e in root.findall("entry")] self.assertIn("common_static/", names) class TypeTestCase(AbstractListingTestCase, unittest.TestCase): """Test that common_static will list context levels.""" def setUp(self): self.url = urljoin(baseURL, "common_static/") def assertValidHtml(self, parser): self.assertIn("base/", parser.link_texts) self.assertIn("site/", parser.link_texts) def assertValidJson(self, jsonData): self.assertIn("base/", jsonData) self.assertIn("site/", jsonData) def assertValidXml(self, xmlData): root = xmlData.getroot() self.assertEquals(root.tag, "entries") names = [e.text for e in root.findall("entry")] self.assertIn("base/", names) self.assertIn("site/", names) class LevelTestCase(AbstractListingTestCase, unittest.TestCase): """Test that common_static/site will list sites.""" def setUp(self): self.url = urljoin(baseURL, "common_static/site/") def assertValidHtml(self, parser): self.assertIn(testSite +"/", parser.link_texts) def assertValidJson(self, jsonData): self.assertIn(testSite +"/", jsonData) def assertValidXml(self, xmlData): root = xmlData.getroot() self.assertEquals(root.tag, "entries") names = [e.text for e in root.findall("entry")] self.assertIn(testSite +"/", names) class AbstractFileListingTestCase(AbstractListingTestCase): """Base test case for a file listing""" def assertValidHtml(self, parser): self.assertIn(testDir +"/", parser.link_texts) self.assertEquals(parser.link_texts, sorted(parser.link_texts)) def assertValidJson(self, jsonData): self.assertIn(testDir +"/", jsonData) def assertValidXml(self, xmlData): root = xmlData.getroot() self.assertEquals(root.tag, "files") names = [e.get("name") for e in root.findall("file")] self.assertIn(testDir +"/", names) self.assertEquals(names, sorted(names)) class BaseFileListingTestCase(AbstractFileListingTestCase, unittest.TestCase): """Test that common_static/base lists files""" def setUp(self): self.url = urljoin(baseURL, "common_static/base/") class SiteFileListingTestCase(AbstractFileListingTestCase, unittest.TestCase): """Test that common_static/site// lists files""" def setUp(self): self.url = urljoin(baseURL, "common_static/site/" + testSite + "/") class FileTestCase(unittest.TestCase): """Test retrieval, modification and deletion of an individual.""" def setUp(self): self.url = urljoin(baseURL, "common_static/user/" + username + "/" + testFile) # The file should not exist before the test, but if it does then delete it # This is some of the same functionality we are testing so if setup fails # then the test would probably fail anyway try: request = urllib2.Request(self.url) response = urllib2.urlopen(request) request = urllib2.Request(self.url) request.get_method = lambda: "DELETE" request.add_header("Authorization", authString) request.add_header("If-Match", response.headers["Content-MD5"]) response = urllib2.urlopen(request) except urllib2.HTTPError as e: if e.code != 404: raise e def test_file_operations(self): """Run through a typical set of file interactions and verify everything works correctly.""" request = urllib2.Request(self.url) request.get_method = lambda: "PUT" request.add_data("Test Data") with self.assertRaises(urllib2.HTTPError) as cm: response = urllib2.urlopen(request) self.assertEqual(401, cm.exception.code) request.add_header("Authorization", authString) with self.assertRaises(urllib2.HTTPError) as cm: response = urllib2.urlopen(request) self.assertEqual(409, cm.exception.code) request.add_header("If-Match", "NON_EXISTENT_CHECKSUM") response = urllib2.urlopen(request) request = urllib2.Request(self.url) response = urllib2.urlopen(request) self.assertEquals(response.read(), "Test Data") request = urllib2.Request(self.url + "/") response = urllib2.urlopen(request) self.assertEquals(response.read(), "Test Data") request = urllib2.Request(self.url) request.get_method = lambda: "PUT" request.add_data("Test Data2") request.add_header("If-Match", response.headers["Content-MD5"]) request.add_header("Authorization", authString) response = urllib2.urlopen(request) checksum = response.headers["Content-MD5"] request = urllib2.Request(self.url) response = urllib2.urlopen(request) self.assertEquals(response.read(), "Test Data2") request = urllib2.Request(self.url) request.get_method = lambda: "DELETE" with self.assertRaises(urllib2.HTTPError) as cm: response = urllib2.urlopen(request) self.assertEqual(401, cm.exception.code) request.add_header("Authorization", authString) with self.assertRaises(urllib2.HTTPError) as cm: response = urllib2.urlopen(request) self.assertEqual(409, cm.exception.code) request.add_header("If-Match", checksum) response = urllib2.urlopen(request) request = urllib2.Request(self.url) with self.assertRaises(urllib2.HTTPError) as cm: response = urllib2.urlopen(request) self.assertEqual(404, cm.exception.code) if __name__ == '__main__': unittest.main()