diff options
author | zsloan | 2018-03-29 10:36:12 -0500 |
---|---|---|
committer | GitHub | 2018-03-29 10:36:12 -0500 |
commit | b215b5fe5c6d13f0ed445106230e1e38db71c918 (patch) | |
tree | 97f1f47b092bef38856ac34c1bd745e471c38311 /test/requests | |
parent | e67e3a76fca0bad4796853eb58140a412922bc9c (diff) | |
parent | e0c706c51c834caa836ecffd27a5d18fc23178ff (diff) | |
download | genenetwork2-b215b5fe5c6d13f0ed445106230e1e38db71c918.tar.gz |
Merge pull request #297 from pjotrp/testing
Testing
Diffstat (limited to 'test/requests')
-rw-r--r-- | test/requests/link_checker.py | 63 | ||||
-rw-r--r-- | test/requests/main_web_functionality.py | 40 | ||||
-rw-r--r-- | test/requests/mapping_tests.py | 43 | ||||
-rw-r--r-- | test/requests/parametrized_test.py | 27 | ||||
-rw-r--r-- | test/requests/run-integration-tests.py | 34 | ||||
-rwxr-xr-x | test/requests/test-website.py | 71 | ||||
-rw-r--r-- | test/requests/test_login_github.py | 47 | ||||
-rw-r--r-- | test/requests/test_login_local.py | 60 | ||||
-rw-r--r-- | test/requests/test_login_orcid.py | 47 | ||||
-rw-r--r-- | test/requests/test_registration.py | 41 |
10 files changed, 473 insertions, 0 deletions
diff --git a/test/requests/link_checker.py b/test/requests/link_checker.py new file mode 100644 index 00000000..256bf6ef --- /dev/null +++ b/test/requests/link_checker.py @@ -0,0 +1,63 @@ +from __future__ import print_function +import re +import requests +from lxml.html import parse +from requests.exceptions import ConnectionError + +def is_root_link(link): + pattern = re.compile("^/$") + return pattern.match(link) + +def is_mailto_link(link): + pattern = re.compile("^mailto:.*") + return pattern.match(link) + +def is_internal_link(link): + pattern = re.compile("^/.*") + return pattern.match(link) + +def get_links(doc): + return filter( + lambda x: not ( + is_root_link(x) + or is_mailto_link(x)) + , map(lambda y: y.get("href") + , doc.cssselect("a"))) + +def verify_link(link): + try: + result = requests.get(link, timeout=20) + if result.status_code == 200: + print(link+" ==> OK") + else: + print("ERROR: link `"+link+"` failed with status " + , result.status_code) + except ConnectionError as ex: + print("ERROR: ", link, ex) + +def check_page(host, start_url): + print("") + print("Checking links in page `"+start_url+"`") + doc = parse(start_url).getroot() + links = get_links(doc) + internal_links = filter(is_internal_link, links) + external_links = filter(lambda x: not is_internal_link(x), links) + external_links.append("http://somenon-existentsite.brr") + for link in internal_links: + verify_link(host+link) + + for link in external_links: + verify_link(link) + +def check_links(args_obj, parser): + print("") + print("Checking links") + host = args_obj.host + + # Check the home page + check_page(host, host) + + # Check traits page + check_page( + host, + host+"/show_trait?trait_id=1435395_s_at&dataset=HC_M2_0606_P") diff --git a/test/requests/main_web_functionality.py b/test/requests/main_web_functionality.py new file mode 100644 index 00000000..7b89b833 --- /dev/null +++ b/test/requests/main_web_functionality.py @@ -0,0 +1,40 @@ +from __future__ import print_function +import re +import requests +from lxml.html import parse +from link_checker import check_page +from requests.exceptions import ConnectionError + +def check_home(url): + doc = parse(url).getroot() + search_button = doc.cssselect("#btsearch") + assert(search_button[0].value == "Search") + print("OK") + +def check_search_page(host): + data = dict( + species="mouse" + , group="BXD" + , type="Hippocampus mRNA" + , dataset="HC_M2_0606_P" + , search_terms_or="" + , search_terms_and="MEAN=(15 16) LRS=(23 46)") + result = requests.get(host+"/search", params=data) + found = result.text.find("/show_trait?trait_id=1435395_s_at&dataset=HC_M2_0606_P") + assert(found >= 0) + print("OK") + check_traits_page(host, "/show_trait?trait_id=1435395_s_at&dataset=HC_M2_0606_P") + +def check_traits_page(host, traits_url): + doc = parse(host+traits_url).getroot() + traits_form = doc.forms[1] + assert(traits_form.fields["corr_dataset"] == "HC_M2_0606_P") + print("OK") + check_page(host, host+traits_url) + +def check_main_web_functionality(args_obj, parser): + print("") + print("Checking main web functionality...") + host = args_obj.host + check_home(host) + check_search_page(host) diff --git a/test/requests/mapping_tests.py b/test/requests/mapping_tests.py new file mode 100644 index 00000000..fd20df11 --- /dev/null +++ b/test/requests/mapping_tests.py @@ -0,0 +1,43 @@ +from __future__ import print_function +import re +import json +import requests +from lxml.html import fromstring + +def get_data(list_item): + try: + value = list_item[1] + except: + value = None + #print("list_item:", list_item, "==>", value) + return value + +def load_data_from_file(): + filename = "../test/data/input/mapping/1435395_s_at_HC_M2_0606_P.json" + file_handle = open(filename, "r") + file_data = json.loads(file_handle.read().encode("utf-8")) + return file_data + +def check_pylmm_tool_selection(host, data): + data["method"] = "pylmm" + page = requests.post(host+"/marker_regression", data=data) + doc = fromstring(page.text) + form = doc.forms[1] + assert form.fields["dataset"] == "HC_M2_0606_P" + assert form.fields["value:BXD1"] == "15.034" # Check value in the file + +def check_R_qtl_tool_selection(host, data): + pass + +def check_CIM_tool_selection(host, data): + pass + +def check_mapping(args_obj, parser): + print("") + print("Checking mapping") + + host = args_obj.host + data = load_data_from_file() + check_pylmm_tool_selection(host, data) + check_R_qtl_tool_selection(host, data) + check_CIM_tool_selection(host, data) diff --git a/test/requests/parametrized_test.py b/test/requests/parametrized_test.py new file mode 100644 index 00000000..abf98fce --- /dev/null +++ b/test/requests/parametrized_test.py @@ -0,0 +1,27 @@ +import logging +import unittest +from elasticsearch import Elasticsearch, TransportError + +class ParametrizedTest(unittest.TestCase): + + def __init__(self, methodName='runTest', gn2_url="http://localhost:5003", es_url="localhost:9200"): + super(ParametrizedTest, self).__init__(methodName=methodName) + self.gn2_url = gn2_url + self.es_url = es_url + + def setUp(self): + self.es = Elasticsearch([self.es_url]) + self.es_cleanup = [] + + es_logger = logging.getLogger("elasticsearch") + es_logger.addHandler( + logging.FileHandler("/tmp/es_TestRegistrationInfo.log")) + es_trace_logger = logging.getLogger("elasticsearch.trace") + es_trace_logger.addHandler( + logging.FileHandler("/tmp/es_TestRegistrationTrace.log")) + + def tearDown(self): + self.es.delete_by_query( + index="users" + , doc_type="local" + , body={"query":{"match":{"email_address":"test@user.com"}}}) diff --git a/test/requests/run-integration-tests.py b/test/requests/run-integration-tests.py new file mode 100644 index 00000000..5e816549 --- /dev/null +++ b/test/requests/run-integration-tests.py @@ -0,0 +1,34 @@ +import sys +from test_login_local import TestLoginLocal +from test_login_orcid import TestLoginOrcid +from test_login_github import TestLoginGithub +from test_registration import TestRegistration +from unittest import TestSuite, TextTestRunner, TestLoader + +test_cases = [ + TestRegistration + , TestLoginLocal + , TestLoginGithub + , TestLoginOrcid +] + +def suite(gn2_url, es_url): + the_suite = TestSuite() + for case in test_cases: + the_suite.addTests(initTest(case, gn2_url, es_url)) + return the_suite + +def initTest(klass, gn2_url, es_url): + loader = TestLoader() + methodNames = loader.getTestCaseNames(klass) + return [klass(mname, gn2_url, es_url) for mname in methodNames] + +def main(gn2_url, es_url): + runner = TextTestRunner() + runner.run(suite(gn2_url, es_url)) + +if __name__ == "__main__": + if len(sys.argv) < 3: + raise Exception("Required arguments missing:\n\tTry running `run-integration-test.py <gn2-url> <es-url>`") + else: + main(sys.argv[1], sys.argv[2]) diff --git a/test/requests/test-website.py b/test/requests/test-website.py new file mode 100755 index 00000000..2bef6eb1 --- /dev/null +++ b/test/requests/test-website.py @@ -0,0 +1,71 @@ +# Run with something like +# +# env GN2_PROFILE=/home/wrk/opt/gn-latest ./bin/genenetwork2 ./etc/default_settings.py -c ../test/requests/test-website.py http://localhost:5003 +# +# Mostly to pick up the Guix GN2_PROFILE and python modules +from __future__ import print_function +import argparse +from link_checker import check_links +from mapping_tests import check_mapping +from main_web_functionality import check_main_web_functionality + +print("Mechanical Rob firing up...") + +def run_all(args_obj, parser): + print("") + print("Running all tests.") + check_main_web_functionality(args_obj, parser) + check_links(args_obj, parser) + check_mapping(args_obj, parser) + # TODO: Add other functions as they are created. + +def print_help(args_obj, parser): + print(parser.format_help()) + +def dummy(args_obj, parser): + print("Not implemented yet.") + + +desc = """ +This is Mechanical-Rob - an automated web server tester for + Genenetwork.org +""" +parser = argparse.ArgumentParser(description=desc) + +parser.add_argument("-d", "--database", metavar="DB", type=str + , default="db_webqtl_s" + , help="Use database (default db_webqtl_s)") + +parser.add_argument("host", metavar="HOST", type=str + , default="http://localhost:5003" + , help="The url to the web server") + +parser.add_argument("-a", "--all", dest="accumulate", action="store_const" + , const=run_all, default=print_help + , help="Runs all tests.") + +parser.add_argument("-l", "--link-checker", dest="accumulate" + , action='store_const', const=check_links, default=print_help + , help="Checks for dead links.") + +parser.add_argument("-f", "--main-functionality", dest="accumulate" + , action='store_const', const=check_main_web_functionality + , default=print_help + , help="Checks for main web functionality.") + +parser.add_argument("-m", "--mapping", dest="accumulate" + , action="store_const", const=check_mapping, default=print_help + , help="Checks for mapping.") + +# parser.add_argument("-n", "--navigation", dest="accumulate" +# , action="store_const", const=check_navigation, default=print_help +# , help="Checks for navigation.") + +# parser.add_argument("-s", "--skip-broken", dest="accumulate" +# , action="store_const", const=dummy, default=print_help +# , help="Skip tests that are known to be broken.") + +args = parser.parse_args() +# print("The arguments object: ", args) + +args.accumulate(args, parser) diff --git a/test/requests/test_login_github.py b/test/requests/test_login_github.py new file mode 100644 index 00000000..1bf4f695 --- /dev/null +++ b/test/requests/test_login_github.py @@ -0,0 +1,47 @@ +import uuid +import requests +from time import sleep +from wqflask import app +from parameterized import parameterized +from parametrized_test import ParametrizedTest + +login_link_text = '<a id="login_in" href="/n/login">Sign in</a>' +logout_link_text = '<a id="login_out" title="Signed in as ." href="/n/logout">Sign out</a>' +uid = str(uuid.uuid4()) + +class TestLoginGithub(ParametrizedTest): + + def setUp(self): + super(TestLoginGithub, self).setUp() + data = { + "user_id": uid + , "name": "A. T. Est User" + , "github_id": 693024 + , "user_url": "https://fake-github.com/atestuser" + , "login_type": "github" + , "organization": "" + , "active": 1 + , "confirmed": 1 + } + self.es.create(index="users", doc_type="local", body=data, id=uid) + sleep(1) + + def tearDown(self): + super(TestLoginGithub, self).tearDown() + self.es.delete(index="users", doc_type="local", id=uid) + + def testLoginUrl(self): + login_button_text = '<a href="https://github.com/login/oauth/authorize?client_id=' + app.config.get("GITHUB_CLIENT_ID") + '&client_secret=' + app.config.get("GITHUB_CLIENT_SECRET") + '" title="Login with GitHub" class="btn btn-info btn-group">Login with Github</a>' + result = requests.get(self.gn2_url+"/n/login") + index = result.content.find(login_button_text) + self.assertTrue(index >= 0, "Should have found `Login with Github` button") + + @parameterized.expand([ + ("1234", login_link_text, "Login should have failed with non-existing user") + , (uid, logout_link_text, "Login should have been successful with existing user") + ]) + def testLogin(self, test_uid, expected, message): + url = self.gn2_url+"/n/login?type=github&uid="+test_uid + result = requests.get(url) + index = result.content.find(expected) + self.assertTrue(index >= 0, message) diff --git a/test/requests/test_login_local.py b/test/requests/test_login_local.py new file mode 100644 index 00000000..808649ca --- /dev/null +++ b/test/requests/test_login_local.py @@ -0,0 +1,60 @@ +import requests +from wqflask import user_manager +from parameterized import parameterized +from parametrized_test import ParametrizedTest + +login_link_text = '<a id="login_in" href="/n/login">Sign in</a>' +logout_link_text = '<a id="login_out" title="Signed in as ." href="/n/logout">Sign out</a>' + +class TestLoginLocal(ParametrizedTest): + + def setUp(self): + super(TestLoginLocal, self).setUp() + self.login_url = self.gn2_url +"/n/login" + data = { + "es_connection": self.es, + "email_address": "test@user.com", + "full_name": "Test User", + "organization": "Test Organisation", + "password": "test_password", + "password_confirm": "test_password" + } + user_manager.basic_info = lambda : { "basic_info": "basic" } + user_manager.RegisterUser(data) + + + @parameterized.expand([ + ( + { + "email_address": "non@existent.email", + "password": "doesitmatter?" + }, login_link_text, "Login should have failed with the wrong user details."), + ( + { + "email_address": "test@user.com", + "password": "test_password" + }, logout_link_text, "Login should have been successful with correct user details and neither import_collections nor remember_me set"), + ( + { + "email_address": "test@user.com", + "password": "test_password", + "import_collections": "y" + }, logout_link_text, "Login should have been successful with correct user details and only import_collections set"), + ( + { + "email_address": "test@user.com", + "password": "test_password", + "remember_me": "y" + }, logout_link_text, "Login should have been successful with correct user details and only remember_me set"), + ( + { + "email_address": "test@user.com", + "password": "test_password", + "remember_me": "y", + "import_collections": "y" + }, logout_link_text, "Login should have been successful with correct user details, and both remember_me, and import_collections set") + ]) + def testLogin(self, data, expected, message): + result = requests.post(self.login_url, data=data) + index = result.content.find(expected) + self.assertTrue(index >= 0, message) diff --git a/test/requests/test_login_orcid.py b/test/requests/test_login_orcid.py new file mode 100644 index 00000000..ea15642e --- /dev/null +++ b/test/requests/test_login_orcid.py @@ -0,0 +1,47 @@ +import uuid +import requests +from time import sleep +from wqflask import app +from parameterized import parameterized +from parametrized_test import ParametrizedTest + +login_link_text = '<a id="login_in" href="/n/login">Sign in</a>' +logout_link_text = '<a id="login_out" title="Signed in as ." href="/n/logout">Sign out</a>' +uid = str(uuid.uuid4()) + +class TestLoginOrcid(ParametrizedTest): + + def setUp(self): + super(TestLoginOrcid, self).setUp() + data = { + "user_id": uid + , "name": "A. T. Est User" + , "orcid": 345872 + , "user_url": "https://fake-orcid.org/atestuser" + , "login_type": "orcid" + , "organization": "" + , "active": 1 + , "confirmed": 1 + } + self.es.create(index="users", doc_type="local", body=data, id=uid) + sleep(1) + + def tearDown(self): + super(TestLoginOrcid, self).tearDown() + self.es.delete(index="users", doc_type="local", id=uid) + + def testLoginUrl(self): + login_button_text = 'a href="https://sandbox.orcid.org/oauth/authorize?response_type=code&scope=/authenticate&show_login=true&client_id=' + app.config.get("ORCID_CLIENT_ID") + '&client_secret=' + app.config.get("ORCID_CLIENT_SECRET") + '" title="Login with ORCID" class="btn btn-info btn-group">Login with ORCID</a>' + result = requests.get(self.gn2_url+"/n/login") + index = result.content.find(login_button_text) + self.assertTrue(index >= 0, "Should have found `Login with ORCID` button") + + @parameterized.expand([ + ("1234", login_link_text, "Login should have failed with non-existing user") + , (uid, logout_link_text, "Login should have been successful with existing user") + ]) + def testLogin(self, test_uid, expected, message): + url = self.gn2_url+"/n/login?type=orcid&uid="+test_uid + result = requests.get(url) + index = result.content.find(expected) + self.assertTrue(index >= 0, message) diff --git a/test/requests/test_registration.py b/test/requests/test_registration.py new file mode 100644 index 00000000..0047e8a6 --- /dev/null +++ b/test/requests/test_registration.py @@ -0,0 +1,41 @@ +import sys +import requests +from parametrized_test import ParametrizedTest + +class TestRegistration(ParametrizedTest): + + def tearDown(self): + for item in self.es_cleanup: + self.es.delete(index="users", doc_type="local", id=item["_id"]) + + def testRegistrationPage(self): + if self.es.ping(): + data = { + "email_address": "test@user.com", + "full_name": "Test User", + "organization": "Test Organisation", + "password": "test_password", + "password_confirm": "test_password" + } + requests.post(self.gn2_url+"/n/register", data) + response = self.es.search( + index="users" + , doc_type="local" + , body={ + "query": {"match": {"email_address": "test@user.com"}}}) + self.assertEqual(len(response["hits"]["hits"]), 1) + else: + self.skipTest("The elasticsearch server is down") + +def main(gn2, es): + import unittest + suite = unittest.TestSuite() + suite.addTest(TestRegistration(methodName="testRegistrationPage", gn2_url=gn2, es_url=es)) + runner = unittest.TextTestRunner() + runner.run(suite) + +if __name__ == "__main__": + if len(sys.argv) < 3: + raise Exception("Required arguments missing") + else: + main(sys.argv[1], sys.argv[2]) |