about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--wqflask/tests/base/test_data_set.py10
-rw-r--r--wqflask/tests/base/test_trait.py101
-rw-r--r--wqflask/tests/utility/test_authentication_tools.py193
-rw-r--r--wqflask/tests/utility/test_hmac.py35
-rw-r--r--wqflask/utility/authentication_tools.py41
-rw-r--r--wqflask/utility/hmac.py9
6 files changed, 363 insertions, 26 deletions
diff --git a/wqflask/tests/base/test_data_set.py b/wqflask/tests/base/test_data_set.py
index 94780a5d..dd7f5051 100644
--- a/wqflask/tests/base/test_data_set.py
+++ b/wqflask/tests/base/test_data_set.py
@@ -66,7 +66,7 @@ class TestDataSetTypes(unittest.TestCase):
     @mock.patch('base.data_set.g')
     def test_set_dataset_key_mrna(self, db_mock):
         with app.app_context():
-            db_mock.db.execute.return_value = [1, 2, 3]
+            db_mock.db.execute.return_value.fetchone.return_value = [1, 2, 3]
             redis_mock = mock.Mock()
             redis_mock.get.return_value = self.test_dataset
             data_set = DatasetType(redis_mock)
@@ -84,7 +84,7 @@ class TestDataSetTypes(unittest.TestCase):
     @mock.patch('base.data_set.g')
     def test_set_dataset_key_pheno(self, db_mock):
         with app.app_context():
-            db_mock.db.execute.return_value = [1, 2, 3]
+            db_mock.db.execute.return_value.fetchone.return_value = [1, 2, 3]
             redis_mock = mock.Mock()
             redis_mock.get.return_value = self.test_dataset
             data_set = DatasetType(redis_mock)
@@ -93,7 +93,6 @@ class TestDataSetTypes(unittest.TestCase):
             redis_mock.set.assert_called_once_with(
                 "dataset_structure",
                 '{"Aging-Brain-UCIPublish": "Publish", "AKXDGeno": "Geno", "B139_K_1206_M": "ProbeSet", "AD-cases-controls-MyersGeno": "Geno", "AD-cases-controls-MyersPublish": "Publish", "All Phenotypes": "Publish", "Test": "Publish", "AXBXAPublish": "Publish", "B139_K_1206_R": "ProbeSet", "AXBXAGeno": "Geno"}')
-            expected_db_call = """"""
             db_mock.db.execute.assert_called_with(
                 ("SELECT InfoFiles.GN_AccesionId " +
                  "FROM InfoFiles, PublishFreeze, InbredSet " +
@@ -105,7 +104,7 @@ class TestDataSetTypes(unittest.TestCase):
     @mock.patch('base.data_set.g')
     def test_set_dataset_other_pheno(self, db_mock):
         with app.app_context():
-            db_mock.db.execute.return_value = [1, 2, 3]
+            db_mock.db.execute.return_value.fetchone.return_value = [1, 2, 3]
             redis_mock = mock.Mock()
             redis_mock.get.return_value = self.test_dataset
             data_set = DatasetType(redis_mock)
@@ -114,7 +113,6 @@ class TestDataSetTypes(unittest.TestCase):
             redis_mock.set.assert_called_once_with(
                 "dataset_structure",
                 '{"Aging-Brain-UCIPublish": "Publish", "AKXDGeno": "Geno", "B139_K_1206_M": "ProbeSet", "AD-cases-controls-MyersGeno": "Geno", "AD-cases-controls-MyersPublish": "Publish", "All Phenotypes": "Publish", "Test": "Publish", "AXBXAPublish": "Publish", "B139_K_1206_R": "ProbeSet", "AXBXAGeno": "Geno"}')
-            expected_db_call = """"""
             db_mock.db.execute.assert_called_with(
                 ("SELECT PublishFreeze.Name " +
                  "FROM PublishFreeze, InbredSet " +
@@ -125,7 +123,7 @@ class TestDataSetTypes(unittest.TestCase):
     @mock.patch('base.data_set.g')
     def test_set_dataset_geno(self, db_mock):
         with app.app_context():
-            db_mock.db.execute.return_value = [1, 2, 3]
+            db_mock.db.execute.return_value.fetchone.return_value = [1, 2, 3]
             redis_mock = mock.Mock()
             redis_mock.get.return_value = self.test_dataset
             data_set = DatasetType(redis_mock)
diff --git a/wqflask/tests/base/test_trait.py b/wqflask/tests/base/test_trait.py
new file mode 100644
index 00000000..53b0d440
--- /dev/null
+++ b/wqflask/tests/base/test_trait.py
@@ -0,0 +1,101 @@
+# -*- coding: utf-8 -*-
+"""Tests wqflask/base/trait.py"""
+import unittest
+import mock
+
+from base.trait import GeneralTrait
+from base.trait import retrieve_trait_info
+
+
+class TestResponse:
+    """Mock Test Response after a request"""
+    @property
+    def content(self):
+        """Mock the content from Requests.get(params).content"""
+        return "[1, 2, 3, 4]"
+
+
+class TestNilResponse:
+    """Mock Test Response after a request"""
+    @property
+    def content(self):
+        """Mock the content from Requests.get(params).content"""
+        return "{}"
+
+
+class MockTrait(GeneralTrait):
+    @property
+    def wikidata_alias_fmt(self):
+        return "Mock alias"
+
+
+class TestRetrieveTraitInfo(unittest.TestCase):
+    """Tests for 'retrieve_trait_info'"""
+    def test_retrieve_trait_info_with_empty_dataset(self):
+        """Test that an exception is raised when dataset is empty"""
+        with self.assertRaises(AssertionError):
+            retrieve_trait_info(trait=mock.MagicMock(),
+                                dataset={})
+
+    @mock.patch('base.trait.requests.get')
+    @mock.patch('base.trait.g')
+    def test_retrieve_trait_info_with_empty_trait_info(self,
+                                                       g_mock,
+                                                       requests_mock):
+        """Empty trait info"""
+        requests_mock.return_value = TestNilResponse()
+        with self.assertRaises(KeyError):
+            retrieve_trait_info(trait=mock.MagicMock(),
+                                dataset=mock.MagicMock())
+
+    @mock.patch('base.trait.requests.get')
+    @mock.patch('base.trait.g')
+    def test_retrieve_trait_info_with_non_empty_trait_info(self,
+                                                           g_mock,
+                                                           requests_mock):
+        """Test that attributes are set"""
+        mock_dataset = mock.MagicMock()
+        requests_mock.return_value = TestResponse()
+        type(mock_dataset).display_fields = mock.PropertyMock(
+            return_value=["a", "b", "c", "d"])
+        test_trait = retrieve_trait_info(trait=MockTrait(dataset=mock_dataset),
+                                         dataset=mock_dataset)
+        self.assertEqual(test_trait.a, 1)
+        self.assertEqual(test_trait.b, 2)
+        self.assertEqual(test_trait.c, 3)
+        self.assertEqual(test_trait.d, 4)
+
+    @mock.patch('base.trait.requests.get')
+    @mock.patch('base.trait.g')
+    def test_retrieve_trait_info_utf8_parsing(self,
+                                              g_mock,
+                                              requests_mock):
+        """Test that utf-8 strings are parsed correctly"""
+        utf_8_string = "test_string"
+        mock_dataset = mock.MagicMock()
+        requests_mock.return_value = TestResponse()
+        type(mock_dataset).display_fields = mock.PropertyMock(
+            return_value=["a", "b", "c", "d"])
+        type(mock_dataset).type = 'Publish'
+
+        mock_trait = MockTrait(
+            dataset=mock_dataset,
+            pre_publication_description=utf_8_string
+        )
+        trait_attrs = {
+            "group_code": "test_code",
+            "pre_publication_description": "test_pre_pub",
+            "pre_publication_abbreviation": "ファイルを画面毎に見て行くには、次のコマンドを使います。",
+            "post_publication_description": None,
+            "pubmed_id": None,
+            'year': "2020",
+            "authors": "Jane Doe かいと",
+        }
+        for key, val in list(trait_attrs.items()):
+            setattr(mock_trait, key, val)
+        test_trait = retrieve_trait_info(trait=mock_trait,
+                                         dataset=mock_dataset)
+        self.assertEqual(test_trait.abbreviation,
+                         "ファイルを画面毎に見て行くには、次のコマンドを使います。")
+        self.assertEqual(test_trait.authors,
+                         "Jane Doe かいと")
diff --git a/wqflask/tests/utility/test_authentication_tools.py b/wqflask/tests/utility/test_authentication_tools.py
new file mode 100644
index 00000000..99c74245
--- /dev/null
+++ b/wqflask/tests/utility/test_authentication_tools.py
@@ -0,0 +1,193 @@
+"""Tests for authentication tools"""
+import unittest
+import mock
+
+from utility.authentication_tools import check_resource_availability
+from utility.authentication_tools import add_new_resource
+
+
+class TestResponse:
+    """Mock Test Response after a request"""
+    @property
+    def content(self):
+        """Mock the content from Requests.get(params).content"""
+        return '["foo"]'
+
+
+class TestUser:
+    """Mock user"""
+    @property
+    def user_id(self):
+        """Mockes user id. Used in Flask.g.user_session.user_id"""
+        return "Jane"
+
+
+class TestUserSession:
+    """Mock user session"""
+    @property
+    def user_session(self):
+        """Mock user session. Mocks Flask.g.user_session object"""
+        return TestUser()
+
+
+def mock_add_resource(resource_ob, update=False):
+    return resource_ob
+
+
+class TestCheckResourceAvailability(unittest.TestCase):
+    """Test methods related to checking the resource availability"""
+    @mock.patch('utility.authentication_tools.add_new_resource')
+    @mock.patch('utility.authentication_tools.Redis')
+    @mock.patch('utility.authentication_tools.g')
+    @mock.patch('utility.authentication_tools.get_resource_id')
+    def test_check_resource_availability_default_mask(
+            self,
+            resource_id_mock,
+            g_mock,
+            redis_mock,
+            add_new_resource_mock):
+        """Test the resource availability with default mask"""
+        resource_id_mock.return_value = 1
+        g_mock.return_value = mock.Mock()
+        redis_mock.smembers.return_value = []
+        test_dataset = mock.MagicMock()
+        type(test_dataset).type = mock.PropertyMock(return_value="Test")
+        add_new_resource_mock.return_value = {"default_mask": 2}
+        self.assertEqual(check_resource_availability(test_dataset), 2)
+
+    @mock.patch('utility.authentication_tools.requests.get')
+    @mock.patch('utility.authentication_tools.add_new_resource')
+    @mock.patch('utility.authentication_tools.Redis')
+    @mock.patch('utility.authentication_tools.g')
+    @mock.patch('utility.authentication_tools.get_resource_id')
+    def test_check_resource_availability_non_default_mask(
+            self,
+            resource_id_mock,
+            g_mock,
+            redis_mock,
+            add_new_resource_mock,
+            requests_mock):
+        """Test the resource availability with default mask"""
+        resource_id_mock.return_value = 1
+        g_mock.return_value = mock.Mock()
+        redis_mock.smembers.return_value = []
+        add_new_resource_mock.return_value = {"default_mask": 2}
+        requests_mock.return_value = TestResponse()
+        test_dataset = mock.MagicMock()
+        type(test_dataset).type = mock.PropertyMock(return_value="Test")
+        self.assertEqual(check_resource_availability(test_dataset),
+                         ['foo'])
+
+    @mock.patch('utility.authentication_tools.webqtlConfig.SUPER_PRIVILEGES',
+                "SUPERUSER")
+    @mock.patch('utility.authentication_tools.requests.get')
+    @mock.patch('utility.authentication_tools.add_new_resource')
+    @mock.patch('utility.authentication_tools.Redis')
+    @mock.patch('utility.authentication_tools.g', TestUserSession())
+    @mock.patch('utility.authentication_tools.get_resource_id')
+    def test_check_resource_availability_of_super_user(
+            self,
+            resource_id_mock,
+            redis_mock,
+            add_new_resource_mock,
+            requests_mock):
+        """Test the resource availability if the user is the super user"""
+        resource_id_mock.return_value = 1
+        redis_mock.smembers.return_value = ["Jane"]
+        add_new_resource_mock.return_value = {"default_mask": 2}
+        requests_mock.return_value = TestResponse()
+        test_dataset = mock.MagicMock()
+        type(test_dataset).type = mock.PropertyMock(return_value="Test")
+        self.assertEqual(check_resource_availability(test_dataset),
+                         "SUPERUSER")
+
+    @mock.patch('utility.authentication_tools.webqtlConfig.DEFAULT_PRIVILEGES',
+                "John Doe")
+    def test_check_resource_availability_string_dataset(self):
+        """Test the resource availability if the dataset is a string"""
+        self.assertEqual(check_resource_availability("Test"),
+                         "John Doe")
+
+    @mock.patch('utility.authentication_tools.webqtlConfig.DEFAULT_PRIVILEGES',
+                "John Doe")
+    def test_check_resource_availability_temp(self):
+        """Test the resource availability if the dataset is a string"""
+        test_dataset = mock.MagicMock()
+        type(test_dataset).type = mock.PropertyMock(return_value="Temp")
+        self.assertEqual(check_resource_availability(test_dataset),
+                         "John Doe")
+
+
+class TestAddNewResource(unittest.TestCase):
+    """Test cases for add_new_resource method"""
+    @mock.patch('utility.authentication_tools.webqtlConfig.DEFAULT_PRIVILEGES',
+                "John Doe")
+    @mock.patch('utility.authentication_tools.add_resource', mock_add_resource)
+    @mock.patch('utility.authentication_tools.get_group_code')
+    def test_add_new_resource_if_publish_datatype(self, group_code_mock):
+        """Test add_new_resource if dataset type is 'publish'"""
+        group_code_mock.return_value = "Test"
+        test_dataset = mock.MagicMock()
+        type(test_dataset).type = mock.PropertyMock(return_value="Publish")
+        type(test_dataset).id = mock.PropertyMock(return_value=10)
+        expected_value = {
+            "owner_id": "none",
+            "default_mask": "John Doe",
+            "group_masks": {},
+            "name": "Test_None",
+            "data": {
+                "dataset": 10,
+                "trait": None
+            },
+            "type": "dataset-publish"
+        }
+        self.assertEqual(add_new_resource(test_dataset),
+                         expected_value)
+
+    @mock.patch('utility.authentication_tools.webqtlConfig.DEFAULT_PRIVILEGES',
+                "John Doe")
+    @mock.patch('utility.authentication_tools.add_resource', mock_add_resource)
+    @mock.patch('utility.authentication_tools.get_group_code')
+    def test_add_new_resource_if_geno_datatype(self, group_code_mock):
+        """Test add_new_resource if dataset type is 'geno'"""
+        group_code_mock.return_value = "Test"
+        test_dataset = mock.MagicMock()
+        type(test_dataset).name = mock.PropertyMock(return_value="Geno")
+        type(test_dataset).type = mock.PropertyMock(return_value="Geno")
+        type(test_dataset).id = mock.PropertyMock(return_value=20)
+        expected_value = {
+            "owner_id": "none",
+            "default_mask": "John Doe",
+            "group_masks": {},
+            "name": "Geno",
+            "data": {
+                "dataset": 20,
+            },
+            "type": "dataset-geno"
+        }
+        self.assertEqual(add_new_resource(test_dataset),
+                         expected_value)
+
+    @mock.patch('utility.authentication_tools.webqtlConfig.DEFAULT_PRIVILEGES',
+                "John Doe")
+    @mock.patch('utility.authentication_tools.add_resource', mock_add_resource)
+    @mock.patch('utility.authentication_tools.get_group_code')
+    def test_add_new_resource_if_other_datatype(self, group_code_mock):
+        """Test add_new_resource if dataset type is not 'geno' or 'publish'"""
+        group_code_mock.return_value = "Test"
+        test_dataset = mock.MagicMock()
+        type(test_dataset).name = mock.PropertyMock(return_value="Geno")
+        type(test_dataset).type = mock.PropertyMock(return_value="other")
+        type(test_dataset).id = mock.PropertyMock(return_value=20)
+        expected_value = {
+            "owner_id": "none",
+            "default_mask": "John Doe",
+            "group_masks": {},
+            "name": "Geno",
+            "data": {
+                "dataset": 20,
+            },
+            "type": "dataset-probeset"
+        }
+        self.assertEqual(add_new_resource(test_dataset),
+                         expected_value)
diff --git a/wqflask/tests/utility/test_hmac.py b/wqflask/tests/utility/test_hmac.py
new file mode 100644
index 00000000..c7927685
--- /dev/null
+++ b/wqflask/tests/utility/test_hmac.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+"""Test hmac utility functions"""
+
+import unittest
+import mock
+
+from utility.hmac import data_hmac
+from utility.hmac import url_for_hmac
+from utility.hmac import hmac_creation
+
+
+class TestHmacUtil(unittest.TestCase):
+    """Test Utility method for hmac creation"""
+
+    def test_hmac_creation(self):
+        """Test hmac creation with a utf-8 string"""
+        self.assertEqual(hmac_creation("ファイ"), "21fa1d935bbbb07a7875")
+
+    def test_data_hmac(self):
+        """Test data_hmac fn with a utf-8 string"""
+        self.assertEqual(data_hmac("ファイ"), "ファイ:21fa1d935bbbb07a7875")
+
+    @mock.patch("utility.hmac.url_for")
+    def test_url_for_hmac_with_plain_url(self, mock_url):
+        """Test url_for_hmac without params"""
+        mock_url.return_value = "https://mock_url.com/ファイ/"
+        self.assertEqual(url_for_hmac("ファイ"),
+                         "https://mock_url.com/ファイ/?hm=a62896a50d9ffcff7deb")
+
+    @mock.patch("utility.hmac.url_for")
+    def test_url_for_hmac_with_param_in_url(self, mock_url):
+        """Test url_for_hmac with params"""
+        mock_url.return_value = "https://mock_url.com/?ファイ=1"
+        self.assertEqual(url_for_hmac("ファイ"),
+                         "https://mock_url.com/?ファイ=1&hm=b2128fb28bc32da3b5b7")
diff --git a/wqflask/utility/authentication_tools.py b/wqflask/utility/authentication_tools.py
index 3553b92b..239b08e3 100644
--- a/wqflask/utility/authentication_tools.py
+++ b/wqflask/utility/authentication_tools.py
@@ -1,4 +1,6 @@
 from __future__ import absolute_import, print_function, division
+import logging
+from flask import Flask, g, redirect, url_for
 
 import json
 import requests
@@ -9,33 +11,31 @@ from utility import hmac
 from utility.redis_tools import get_redis_conn, get_resource_info, get_resource_id, add_resource
 Redis = get_redis_conn()
 
-from flask import Flask, g, redirect, url_for
 
-import logging
-logger = logging.getLogger(__name__ )
+logger = logging.getLogger(__name__)
+
 
 def check_resource_availability(dataset, trait_id=None):
 
-    #At least for now assume temporary entered traits are accessible
-    if type(dataset) == str:
-        return webqtlConfig.DEFAULT_PRIVILEGES
-    if dataset.type == "Temp":
+    # At least for now assume temporary entered traits are accessible
+    if type(dataset) == str or dataset.type == "Temp":
         return webqtlConfig.DEFAULT_PRIVILEGES
 
     resource_id = get_resource_id(dataset, trait_id)
 
-    if resource_id: #ZS: This should never be false, but it's technically possible if a non-Temp dataset somehow had a type other than Publish/ProbeSet/Geno
+    if resource_id:  # ZS: This should never be false, but it's technically possible if a non-Temp dataset somehow had a type other than Publish/ProbeSet/Geno
         resource_info = get_resource_info(resource_id)
-        if not resource_info: #ZS: If resource isn't already in redis, add it with default privileges
+        if not resource_info:  # ZS: If resource isn't already in redis, add it with default privileges
             resource_info = add_new_resource(dataset, trait_id)
 
-    #ZS: Check if super-user - we should probably come up with some way to integrate this into the proxy
+    # ZS: Check if super-user - we should probably come up with some way to integrate this into the proxy
     if g.user_session.user_id in Redis.smembers("super_users"):
-       return webqtlConfig.SUPER_PRIVILEGES
+        return webqtlConfig.SUPER_PRIVILEGES
 
     response = None
 
-    the_url = "http://localhost:8080/available?resource={}&user={}".format(resource_id, g.user_session.user_id)
+    the_url = "http://localhost:8080/available?resource={}&user={}".format(
+        resource_id, g.user_session.user_id)
     try:
         response = json.loads(requests.get(the_url).content)
     except:
@@ -43,18 +43,19 @@ def check_resource_availability(dataset, trait_id=None):
 
     return response
 
+
 def add_new_resource(dataset, trait_id=None):
     resource_ob = {
-        'owner_id'    : "none", # webqtlConfig.DEFAULT_OWNER_ID,
+        'owner_id': "none",  # webqtlConfig.DEFAULT_OWNER_ID,
         'default_mask': webqtlConfig.DEFAULT_PRIVILEGES,
-        'group_masks' : {}
+        'group_masks': {}
     }
 
     if dataset.type == "Publish":
         resource_ob['name'] = get_group_code(dataset) + "_" + str(trait_id)
         resource_ob['data'] = {
             'dataset': dataset.id,
-            'trait'  : trait_id
+            'trait': trait_id
         }
         resource_ob['type'] = 'dataset-publish'
     elif dataset.type == "Geno":
@@ -74,15 +75,19 @@ def add_new_resource(dataset, trait_id=None):
 
     return resource_info
 
+
 def get_group_code(dataset):
-    results = g.db.execute("SELECT InbredSetCode from InbredSet where Name='{}'".format(dataset.group.name)).fetchone()
+    results = g.db.execute("SELECT InbredSetCode from InbredSet where Name='{}'".format(
+        dataset.group.name)).fetchone()
     if results[0]:
         return results[0]
     else:
         return ""
 
+
 def check_admin(resource_id=None):
-    the_url = "http://localhost:8080/available?resource={}&user={}".format(resource_id, g.user_session.user_id)
+    the_url = "http://localhost:8080/available?resource={}&user={}".format(
+        resource_id, g.user_session.user_id)
     try:
         response = json.loads(requests.get(the_url).content)['admin']
     except:
@@ -96,6 +101,7 @@ def check_admin(resource_id=None):
     else:
         return "not-admin"
 
+
 def check_owner(dataset=None, trait_id=None, resource_id=None):
     if resource_id:
         resource_info = get_resource_info(resource_id)
@@ -110,6 +116,7 @@ def check_owner(dataset=None, trait_id=None, resource_id=None):
 
     return False
 
+
 def check_owner_or_admin(dataset=None, trait_id=None, resource_id=None):
     if not resource_id:
         if dataset.type == "Temp":
diff --git a/wqflask/utility/hmac.py b/wqflask/utility/hmac.py
index b08be97e..fd75803e 100644
--- a/wqflask/utility/hmac.py
+++ b/wqflask/utility/hmac.py
@@ -7,11 +7,11 @@ from flask import url_for
 
 from wqflask import app
 
+
 def hmac_creation(stringy):
     """Helper function to create the actual hmac"""
 
     secret = app.config['SECRET_HMAC_CODE']
-
     hmaced = hmac.new(secret, stringy, hashlib.sha1)
     hm = hmaced.hexdigest()
     # ZS: Leaving the below comment here to ask Pjotr about
@@ -20,10 +20,12 @@ def hmac_creation(stringy):
     hm = hm[:20]
     return hm
 
+
 def data_hmac(stringy):
-    """Takes arbitray data string and appends :hmac so we know data hasn't been tampered with"""
+    """Takes arbitrary data string and appends :hmac so we know data hasn't been tampered with"""
     return stringy + ":" + hmac_creation(stringy)
 
+
 def url_for_hmac(endpoint, **values):
     """Like url_for but adds an hmac at the end to insure the url hasn't been tampered with"""
 
@@ -36,5 +38,6 @@ def url_for_hmac(endpoint, **values):
         combiner = "?"
     return url + combiner + "hm=" + hm
 
+
 app.jinja_env.globals.update(url_for_hmac=url_for_hmac,
-                             data_hmac=data_hmac)
\ No newline at end of file
+                             data_hmac=data_hmac)