From 955304f337f75bfb7afa85c4a814e4adda6c3fd1 Mon Sep 17 00:00:00 2001 From: asherpasha Date: Wed, 8 Dec 2021 12:57:59 -0500 Subject: [PATCH 1/2] Added unit tests for eFP Image service. --- .github/workflows/bar-api.yml | 2 +- api/resources/efp_image.py | 15 ++++++-- api/utils/bar_utils.py | 2 +- docs/requirements.txt | 2 +- tests/resources/test_efp_image.py | 64 +++++++++++++++++++++++++++++++ tests/utils/test_bar_utils.py | 5 +++ 6 files changed, 83 insertions(+), 7 deletions(-) diff --git a/.github/workflows/bar-api.yml b/.github/workflows/bar-api.yml index df6166a5..5222361f 100644 --- a/.github/workflows/bar-api.yml +++ b/.github/workflows/bar-api.yml @@ -58,4 +58,4 @@ jobs: - name: "Upload coverage to Codecov" uses: codecov/codecov-action@v2 with: - fail_ci_if_error: true + fail_ci_if_error: false diff --git a/api/resources/efp_image.py b/api/resources/efp_image.py index 1f7c98f5..60c760da 100644 --- a/api/resources/efp_image.py +++ b/api/resources/efp_image.py @@ -14,7 +14,9 @@ class eFPImageList(Resource): def get(self): """This end point returns the list of species available""" - species = ["efp_arabidopsis"] # This are the only species available so far + # This are the only species available so far + # If this is updated, update get request and test as well + species = ["efp_arabidopsis"] return BARUtils.success_exit(species) @@ -46,7 +48,7 @@ def get(self, efp="", view="", mode="", gene_1="", gene_2=""): """This end point returns eFP images.""" # list of allowed eFPs # See endpoint able - efp_list = ["efp_arabidopsis"] + species = ["efp_arabidopsis"] # Escape input data efp = escape(efp) @@ -56,7 +58,7 @@ def get(self, efp="", view="", mode="", gene_1="", gene_2=""): gene_2 = escape(gene_2) # Validate values - if efp not in efp_list: + if efp not in species: return BARUtils.error_exit("Invalid eFP."), 400 # Validate view @@ -100,7 +102,12 @@ def get(self, efp="", view="", mode="", gene_1="", gene_2=""): # File is not found if match is None: - return BARUtils.error_exit("Failed to retrieve image. Data for the given gene may not exist."), 500 + return ( + BARUtils.error_exit( + "Failed to retrieve image. Data for the given gene may not exist." + ), + 500, + ) efp_file_link = ( "https://bar.utoronto.ca/~asher/python3/" + efp + "/output/" + match[1] diff --git a/api/utils/bar_utils.py b/api/utils/bar_utils.py index c6861e81..a5a8cea7 100644 --- a/api/utils/bar_utils.py +++ b/api/utils/bar_utils.py @@ -95,7 +95,7 @@ def is_efp_view_name(efp_view): :param efp_view: string view name :return: True if valid """ - if efp_view and re.search(r"[a-z1-9_]{1,20}", efp_view, re.I): + if efp_view and re.search(r"^[a-z1-9_]{1,20}$", efp_view, re.I): return True else: return False diff --git a/docs/requirements.txt b/docs/requirements.txt index eeb1665d..c74e6c05 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -2,7 +2,7 @@ alabaster==0.7.12 Babel==2.9.1 beautifulsoup4==4.10.0 certifi==2021.10.8 -charset-normalizer==2.0.9 +charset-normalizer==2.0.8 docutils==0.17.1 furo==2021.11.23 idna==3.3 diff --git a/tests/resources/test_efp_image.py b/tests/resources/test_efp_image.py index 87c6d0fe..18369385 100644 --- a/tests/resources/test_efp_image.py +++ b/tests/resources/test_efp_image.py @@ -13,3 +13,67 @@ def test_get_efp_image_list(self): response = self.app_client.get("/efp_image/") expected = {"wasSuccessful": True, "data": ["efp_arabidopsis"]} self.assertEqual(response.json, expected) + + def test_get_efp_image(self): + """This function test eFP image endpoint get request + :return: + """ + # A very basic test for Arabidopsis requests + # https://bar.utoronto.ca/api/efp_image/efp_arabidopsis/Developmental_Map/Absolute/At1g01010 + response = self.app_client.get( + "/efp_image/efp_arabidopsis/Developmental_Map/Absolute/At1g01010" + ) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content_type, "image/png") + self.assertEqual(response.content_length, 190879) + + # A very basic test for Arabidopsis requests + # https://bar.utoronto.ca/api/efp_image/efp_arabidopsis/Developmental_Map/Compare/At1g01010/At1g01030 + response = self.app_client.get( + "/efp_image/efp_arabidopsis/Developmental_Map/Compare/At1g01010/At1g01030" + ) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.content_type, "image/png") + self.assertEqual(response.content_length, 193587) + + # Test for invalid species: + response = self.app_client.get( + "/efp_image/abc/Developmental_Map/Absolute/At1g01010" + ) + expected = {"wasSuccessful": False, "error": "Invalid eFP."} + self.assertEqual(response.json, expected) + + # Test for eFP view name + response = self.app_client.get( + "/efp_image/efp_arabidopsis/ab.!c/Absolute/At1g01010" + ) + expected = {"wasSuccessful": False, "error": "Invalid eFP View name."} + self.assertEqual(response.json, expected) + + # Test for eFP mode + response = self.app_client.get("/efp_image/efp_arabidopsis/Root/abc/At1g01010") + expected = {"wasSuccessful": False, "error": "Invalid eFP mode."} + self.assertEqual(response.json, expected) + + # Test for gene 1 using Arabidopsis + response = self.app_client.get( + "/efp_image/efp_arabidopsis/Root/Absolute/At1g0101X" + ) + expected = {"wasSuccessful": False, "error": "Gene 1 is invalid."} + self.assertEqual(response.json, expected) + + response = self.app_client.get( + "/efp_image/efp_arabidopsis/Developmental_Map/Absolute/At1g01011" + ) + expected = { + "wasSuccessful": False, + "error": "Failed to retrieve image. Data for the given gene may not exist.", + } + self.assertEqual(response.json, expected) + + # Test for gene 2 using Arabidopsis + response = self.app_client.get( + "/efp_image/efp_arabidopsis/Root/Compare/At1g01010/Abc" + ) + expected = {"wasSuccessful": False, "error": "Gene 2 is invalid."} + self.assertEqual(response.json, expected) diff --git a/tests/utils/test_bar_utils.py b/tests/utils/test_bar_utils.py index ac9ab76b..f7d06e64 100644 --- a/tests/utils/test_bar_utils.py +++ b/tests/utils/test_bar_utils.py @@ -28,6 +28,11 @@ def test_is_arabidopsis_gene_valid(self): result = BARUtils.is_arabidopsis_gene_valid("At1g01010.11") self.assertFalse(result) + def test_is_tomato_gene_valid(self): + # For some reason, coverage is saying that we need this test + result = BARUtils.is_tomato_gene_valid("Solyc04g014530") + self.assertTrue(result) + def test_is_integer(self): # Valid result result = BARUtils.is_integer("5") From 563903accb8812860df03c17d680b5d9683e2892 Mon Sep 17 00:00:00 2001 From: asherpasha Date: Sat, 11 Dec 2021 13:12:48 -0500 Subject: [PATCH 2/2] eFP Image end point is now cached. --- api/resources/api_manager.py | 10 +-- api/resources/efp_image.py | 103 +++++++++++++++++++----------- api/utils/bar_utils.py | 13 ++++ docs/requirements.txt | 4 +- requirements.txt | 2 +- tests/resources/test_efp_image.py | 24 +++++-- 6 files changed, 106 insertions(+), 50 deletions(-) diff --git a/api/resources/api_manager.py b/api/resources/api_manager.py index cdeced3b..2180c9b9 100644 --- a/api/resources/api_manager.py +++ b/api/resources/api_manager.py @@ -44,22 +44,22 @@ def send_email_notification(): for line in f: recipient = line port = 465 - key = os.environ.get('EMAIL_PASS_KEY') + key = os.environ.get("EMAIL_PASS_KEY") cipher_suite = Fernet(key) - with open(os.environ.get('EMAIL_PASS_FILE'), "rb") as f: + with open(os.environ.get("EMAIL_PASS_FILE"), "rb") as f: for line in f: encrypted_key = line uncipher_text = cipher_suite.decrypt(encrypted_key) password = bytes(uncipher_text).decode("utf-8") context = create_default_context() - smtp_server = 'smtp.gmail.com' - sender_email = 'bar.summarization@gmail.com' + smtp_server = "smtp.gmail.com" + sender_email = "bar.summarization@gmail.com" subject = "[Bio-Analytic Resource] New API key request" text = """\ There is a new API key request. You can approve or reject it at http://bar.utoronto.ca/~bpereira/webservices/bar-request-manager/build/index.html """ - m_text = MIMEText(text, _subtype='plain', _charset='UTF-8') + m_text = MIMEText(text, _subtype="plain", _charset="UTF-8") msg = MIMEMultipart() msg["From"] = sender_email msg["To"] = recipient diff --git a/api/resources/efp_image.py b/api/resources/efp_image.py index 60c760da..66b66abf 100644 --- a/api/resources/efp_image.py +++ b/api/resources/efp_image.py @@ -1,5 +1,8 @@ +import base64 import re import requests +import random +import redis.connection from flask_restx import Namespace, Resource from markupsafe import escape from flask import send_from_directory @@ -78,46 +81,72 @@ def get(self, efp="", view="", mode="", gene_1="", gene_2=""): return BARUtils.error_exit("Gene 2 is invalid."), 400 # Check if request is cached - - # If request is not cached, run the search - # Run eFP. Note, this is currently running from home directory - efp_url = ( - "https://bar.utoronto.ca/~asher/python3/" - + efp - + "/cgi-bin/efpWeb.cgi?dataSource=" - + view - + "&mode=" - + mode - + "&primaryGene=" - + gene_1 - + "&secondaryGene=" - + gene_2 - + "&grey_low=None&grey_stddev=None" - ) - efp_html = requests.get(efp_url) - - # Now search for something like