diff options
Diffstat (limited to 'tests/integration')
-rw-r--r-- | tests/integration/conftest.py | 24 | ||||
-rw-r--r-- | tests/integration/test_correlation.py | 8 | ||||
-rw-r--r-- | tests/integration/test_gemma.py | 14 | ||||
-rw-r--r-- | tests/integration/test_general.py | 8 | ||||
-rw-r--r-- | tests/integration/test_partial_correlations.py | 225 | ||||
-rw-r--r-- | tests/integration/test_wgcna.py | 3 |
6 files changed, 280 insertions, 2 deletions
diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py new file mode 100644 index 0000000..be927a4 --- /dev/null +++ b/tests/integration/conftest.py @@ -0,0 +1,24 @@ +"""Module that holds fixtures for integration tests""" +import pytest + +from gn3.app import create_app +from gn3.db_utils import database_connector + +@pytest.fixture(scope="session") +def client(): + """Create a test client fixture for tests""" + # Do some setup + app = create_app() + app.config.update({"TESTING": True}) + app.testing = True + yield app.test_client() + # Do some teardown/cleanup + + +@pytest.fixture +def db_conn(): + """Create a db connection fixture for tests""" + ## Update this to use temp db once that is in place + conn = database_connector() + yield conn + conn.close() diff --git a/tests/integration/test_correlation.py b/tests/integration/test_correlation.py index bdd9bce..d52ab01 100644 --- a/tests/integration/test_correlation.py +++ b/tests/integration/test_correlation.py @@ -1,6 +1,7 @@ """module contains integration tests for correlation""" from unittest import TestCase from unittest import mock +import pytest from gn3.app import create_app @@ -10,6 +11,7 @@ class CorrelationIntegrationTest(TestCase): def setUp(self): self.app = create_app().test_client() + @pytest.mark.integration_test @mock.patch("gn3.api.correlation.compute_all_sample_correlation") def test_sample_r_correlation(self, mock_compute_samples): """Test /api/correlation/sample_r/{method}""" @@ -61,6 +63,7 @@ class CorrelationIntegrationTest(TestCase): self.assertEqual(response.status_code, 200) self.assertEqual(response.get_json(), api_response) + @pytest.mark.integration_test @mock.patch("gn3.api.correlation.compute_all_lit_correlation") @mock.patch("gn3.api.correlation.database_connector") def test_lit_correlation(self, database_connector, mock_compute_corr): @@ -68,7 +71,9 @@ class CorrelationIntegrationTest(TestCase): mock_compute_corr.return_value = [] - database_connector.return_value = (mock.Mock(), mock.Mock()) + database_connector.return_value = mock.Mock() + database_connector.return_value.__enter__ = mock.Mock() + database_connector.return_value.__exit__ = mock.Mock() post_data = {"1426678_at": "68031", "1426679_at": "68036", @@ -80,6 +85,7 @@ class CorrelationIntegrationTest(TestCase): self.assertEqual(mock_compute_corr.call_count, 1) self.assertEqual(response.status_code, 200) + @pytest.mark.integration_test @mock.patch("gn3.api.correlation.compute_tissue_correlation") def test_tissue_correlation(self, mock_tissue_corr): """Test api/correlation/tissue_corr/{corr_method}""" diff --git a/tests/integration/test_gemma.py b/tests/integration/test_gemma.py index f871173..0515539 100644 --- a/tests/integration/test_gemma.py +++ b/tests/integration/test_gemma.py @@ -7,6 +7,8 @@ from dataclasses import dataclass from typing import Callable from unittest import mock +import pytest + from gn3.app import create_app @@ -30,6 +32,7 @@ class GemmaAPITest(unittest.TestCase): "TMPDIR": "/tmp" }).test_client() + @pytest.mark.integration_test @mock.patch("gn3.api.gemma.run_cmd") def test_get_version(self, mock_run_cmd): """Test that the correct response is returned""" @@ -38,6 +41,7 @@ class GemmaAPITest(unittest.TestCase): self.assertEqual(response.get_json(), {"status": 0, "output": "v1.9"}) self.assertEqual(response.status_code, 200) + @pytest.mark.integration_test @mock.patch("gn3.api.gemma.redis.Redis") def test_check_cmd_status(self, mock_redis): """Test that you can check the status of a given command""" @@ -52,6 +56,7 @@ class GemmaAPITest(unittest.TestCase): name="cmd::2021-02-1217-3224-3224-1234", key="status") self.assertEqual(response.get_json(), {"status": "test"}) + @pytest.mark.integration_test @mock.patch("gn3.api.gemma.queue_cmd") @mock.patch("gn3.computations.gemma.get_hash_of_files") @mock.patch("gn3.api.gemma.jsonfile_to_dict") @@ -94,6 +99,7 @@ class GemmaAPITest(unittest.TestCase): "unique_id": "my-unique-id" }) + @pytest.mark.integration_test @mock.patch("gn3.api.gemma.queue_cmd") @mock.patch("gn3.computations.gemma.get_hash_of_files") @mock.patch("gn3.api.gemma.jsonfile_to_dict") @@ -137,6 +143,7 @@ class GemmaAPITest(unittest.TestCase): "unique_id": "my-unique-id" }) + @pytest.mark.integration_test @mock.patch("gn3.api.gemma.queue_cmd") @mock.patch("gn3.computations.gemma.get_hash_of_files") @mock.patch("gn3.api.gemma.jsonfile_to_dict") @@ -187,6 +194,7 @@ class GemmaAPITest(unittest.TestCase): "output_file": "hash-output.json" }) + @pytest.mark.integration_test @mock.patch("gn3.api.gemma.queue_cmd") @mock.patch("gn3.computations.gemma.get_hash_of_files") @mock.patch("gn3.api.gemma.jsonfile_to_dict") @@ -240,6 +248,7 @@ class GemmaAPITest(unittest.TestCase): "output_file": "hash-output.json" }) + @pytest.mark.integration_test @mock.patch("gn3.api.gemma.queue_cmd") @mock.patch("gn3.computations.gemma.get_hash_of_files") @mock.patch("gn3.api.gemma.jsonfile_to_dict") @@ -292,6 +301,7 @@ class GemmaAPITest(unittest.TestCase): "output_file": "hash-output.json" }) + @pytest.mark.integration_test @mock.patch("gn3.api.gemma.queue_cmd") @mock.patch("gn3.computations.gemma.get_hash_of_files") @mock.patch("gn3.api.gemma.jsonfile_to_dict") @@ -346,6 +356,7 @@ class GemmaAPITest(unittest.TestCase): "output_file": "hash-output.json" }) + @pytest.mark.integration_test @mock.patch("gn3.api.gemma.queue_cmd") @mock.patch("gn3.computations.gemma.get_hash_of_files") @mock.patch("gn3.api.gemma.jsonfile_to_dict") @@ -401,6 +412,7 @@ class GemmaAPITest(unittest.TestCase): "output_file": "hash-output.json" }) + @pytest.mark.integration_test @mock.patch("gn3.api.gemma.queue_cmd") @mock.patch("gn3.computations.gemma.get_hash_of_files") @mock.patch("gn3.api.gemma.jsonfile_to_dict") @@ -465,6 +477,7 @@ class GemmaAPITest(unittest.TestCase): "output_file": "hash-output.json" }) + @pytest.mark.integration_test @mock.patch("gn3.api.gemma.queue_cmd") @mock.patch("gn3.computations.gemma.get_hash_of_files") @mock.patch("gn3.api.gemma.jsonfile_to_dict") @@ -530,6 +543,7 @@ class GemmaAPITest(unittest.TestCase): "output_file": "hash-output.json" }) + @pytest.mark.integration_test @mock.patch("gn3.api.gemma.queue_cmd") @mock.patch("gn3.computations.gemma.get_hash_of_files") @mock.patch("gn3.api.gemma.jsonfile_to_dict") diff --git a/tests/integration/test_general.py b/tests/integration/test_general.py index 8fc2b43..9d87449 100644 --- a/tests/integration/test_general.py +++ b/tests/integration/test_general.py @@ -1,8 +1,10 @@ """Integration tests for some 'general' API endpoints""" import os import unittest - from unittest import mock + +import pytest + from gn3.app import create_app @@ -11,6 +13,7 @@ class GeneralAPITest(unittest.TestCase): def setUp(self): self.app = create_app().test_client() + @pytest.mark.integration_test def test_metadata_endpoint_exists(self): """Test that /metadata/upload exists""" response = self.app.post("/api/metadata/upload/d41d86-e4ceEo") @@ -19,6 +22,7 @@ class GeneralAPITest(unittest.TestCase): {"status": 128, "error": "Please provide a file!"}) + @pytest.mark.integration_test @mock.patch("gn3.api.general.extract_uploaded_file") def test_metadata_file_upload(self, mock_extract_upload): """Test correct upload of file""" @@ -37,6 +41,7 @@ class GeneralAPITest(unittest.TestCase): {"status": 0, "token": "d41d86-e4ceEo"}) + @pytest.mark.integration_test def test_metadata_file_wrong_upload(self): """Test that incorrect upload return correct status code""" response = self.app.post("/api/metadata/upload/d41d86-e4ceEo", @@ -47,6 +52,7 @@ class GeneralAPITest(unittest.TestCase): {"status": 128, "error": "gzip failed to unpack file"}) + @pytest.mark.integration_test @mock.patch("gn3.api.general.run_cmd") def test_run_r_qtl(self, mock_run_cmd): """Test correct upload of file""" diff --git a/tests/integration/test_partial_correlations.py b/tests/integration/test_partial_correlations.py new file mode 100644 index 0000000..4bf352a --- /dev/null +++ b/tests/integration/test_partial_correlations.py @@ -0,0 +1,225 @@ +"""Test partial correlations""" +from unittest import mock + +import pytest + +from gn3.computations.partial_correlations import partial_correlations_entry + +@pytest.mark.integration_test +@pytest.mark.parametrize( + "post_data", ( + None, {}, { + "primary_trait": None, + "control_traits": None, + "method": None, + "target_db": None + }, { + "primary_trait": None, + "control_traits": None, + "method": None, + "target_db": "a_db" + }, { + "primary_trait": None, + "control_traits": None, + "method": "a_method", + "target_db": None + }, { + "primary_trait": None, + "control_traits": None, + "method": "a_method", + "target_db": "a_db" + }, { + "primary_trait": None, + "control_traits": ["a_trait", "another"], + "method": None, + "target_db": None + }, { + "primary_trait": None, + "control_traits": ["a_trait", "another"], + "method": None, + "target_db": "a_db" + }, { + "primary_trait": None, + "control_traits": ["a_trait", "another"], + "method": "a_method", + "target_db": None + }, { + "primary_trait": None, + "control_traits": ["a_trait", "another"], + "method": "a_method", + "target_db": "a_db" + }, { + "primary_trait": "a_trait", + "control_traits": None, + "method": None, + "target_db": None + }, { + "primary_trait": "a_trait", + "control_traits": None, + "method": None, + "target_db": "a_db" + }, { + "primary_trait": "a_trait", + "control_traits": None, + "method": "a_method", + "target_db": None + }, { + "primary_trait": "a_trait", + "control_traits": None, + "method": "a_method", + "target_db": "a_db" + }, { + "primary_trait": "a_trait", + "control_traits": ["a_trait", "another"], + "method": None, + "target_db": None + }, { + "primary_trait": "a_trait", + "control_traits": ["a_trait", "another"], + "method": None, + "target_db": "a_db" + }, { + "primary_trait": "a_trait", + "control_traits": ["a_trait", "another"], + "method": "a_method", + "target_db": None + })) +def test_partial_correlation_api_with_missing_request_data(client, post_data): + """ + Test /api/correlations/partial endpoint with various expected request data + missing. + """ + response = client.post("/api/correlation/partial", json=post_data) + assert ( + response.status_code == 400 and response.is_json and + response.json.get("status") == "error") + +@pytest.mark.integration_test +@pytest.mark.slow +@pytest.mark.parametrize( + "post_data", + ({# ProbeSet + "primary_trait": {"dataset": "a_dataset", "trait_name": "a_name"}, + "control_traits": [ + {"dataset": "a_dataset", "trait_name": "a_name"}, + {"dataset": "a_dataset2", "trait_name": "a_name2"}], + "method": "a_method", + "target_db": "a_db" + }, {# Publish + "primary_trait": { + "dataset": "a_Publish_dataset", "trait_name": "a_name"}, + "control_traits": [ + {"dataset": "a_dataset", "trait_name": "a_name"}, + {"dataset": "a_dataset2", "trait_name": "a_name2"}], + "method": "a_method", + "target_db": "a_db" + }, {# Geno + "primary_trait": {"dataset": "a_Geno_dataset", "trait_name": "a_name"}, + "control_traits": [ + {"dataset": "a_dataset", "trait_name": "a_name"}, + {"dataset": "a_dataset2", "trait_name": "a_name2"}], + "method": "a_method", + "target_db": "a_db" + }, {# Temp + "primary_trait": {"dataset": "a_Temp_dataset", "trait_name": "a_name"}, + "control_traits": [ + {"dataset": "a_dataset", "trait_name": "a_name"}, + {"dataset": "a_dataset2", "trait_name": "a_name2"}], + "method": "a_method", + "target_db": "a_db" + })) +def test_partial_correlation_api_with_non_existent_primary_traits( + client, post_data, mocker): + """ + Check that the system responds appropriately in the case where the user + makes a request with a non-existent primary trait. + """ + mocker.patch("gn3.api.correlation.redis.Redis", mock.MagicMock()) + response = client.post("/api/correlation/partial", json=post_data) + assert ( + response.status_code == 200 and response.is_json and + response.json.get("status") == "success") + +@pytest.mark.integration_test +@pytest.mark.slow +@pytest.mark.parametrize( + "post_data", + ({# ProbeSet + "primary_trait": { + "dataset": "UCLA_BXDBXH_CARTILAGE_V2", + "trait_name": "ILM103710672"}, + "control_traits": [ + {"dataset": "a_dataset", "trait_name": "a_name"}, + {"dataset": "a_dataset2", "trait_name": "a_name2"}], + "method": "a_method", + "target_db": "a_db" + }, {# Publish + "primary_trait": {"dataset": "BXDPublish", "trait_name": "BXD_12557"}, + "control_traits": [ + {"dataset": "a_dataset", "trait_name": "a_name"}, + {"dataset": "a_dataset2", "trait_name": "a_name2"}], + "method": "a_method", + "target_db": "a_db" + }, {# Geno + "primary_trait": {"dataset": "AKXDGeno", "trait_name": "D4Mit16"}, + "control_traits": [ + {"dataset": "a_dataset", "trait_name": "a_name"}, + {"dataset": "a_dataset2", "trait_name": "a_name2"}], + "method": "a_method", + "target_db": "a_db" + } + # Temp -- the data in the database for these is ephemeral, making it + # difficult to test for this + )) +def test_partial_correlation_api_with_non_existent_control_traits(client, post_data, mocker): + """ + Check that the system responds appropriately in the case where the user + makes a request with a non-existent control traits. + + The code repetition here is on purpose - valuing clarity over succinctness. + """ + mocker.patch("gn3.api.correlation.redis.Redis", mock.MagicMock()) + response = client.post("/api/correlation/partial", json=post_data) + assert ( + response.status_code == 200 and response.is_json and + response.json.get("status") == "success") + +@pytest.mark.integration_test +@pytest.mark.slow +@pytest.mark.parametrize( + "primary,controls,method,target", ( + (# Probeset + "UCLA_BXDBXH_CARTILAGE_V2::ILM103710672", ( + "UCLA_BXDBXH_CARTILAGE_V2::nonExisting01", + "UCLA_BXDBXH_CARTILAGE_V2::nonExisting02", + "UCLA_BXDBXH_CARTILAGE_V2::ILM380019"), + "Genetic Correlation, Pearson's r", "BXDPublish"), + (# Publish + "BXDPublish::17937", ( + "BXDPublish::17940", + "BXDPublish::nonExisting03"), + "Genetic Correlation, Spearman's rho", "BXDPublish"), + (# Geno + "AKXDGeno::D4Mit16", ( + "AKXDGeno::D1Mit170", + "AKXDGeno::nonExisting04", + "AKXDGeno::D1Mit135", + "AKXDGeno::nonExisting05", + "AKXDGeno::nonExisting06"), + "SGO Literature Correlation", "BXDPublish") + ) + # Temp -- the data in the database for these is ephemeral, making it + # difficult to test for these without a temp database with the temp + # traits data set to something we are in control of + ) + +def test_part_corr_api_with_mix_of_existing_and_non_existing_control_traits( + db_conn, primary, controls, method, target): + """ + Check that calling the function with a mix of existing and missing control + traits raises an warning. + """ + criteria = 10 + with pytest.warns(UserWarning): + partial_correlations_entry( + db_conn, primary, controls, method, criteria, target) diff --git a/tests/integration/test_wgcna.py b/tests/integration/test_wgcna.py index 078449d..5880b40 100644 --- a/tests/integration/test_wgcna.py +++ b/tests/integration/test_wgcna.py @@ -3,6 +3,8 @@ from unittest import TestCase from unittest import mock +import pytest + from gn3.app import create_app @@ -12,6 +14,7 @@ class WgcnaIntegrationTest(TestCase): def setUp(self): self.app = create_app().test_client() + @pytest.mark.integration_test @mock.patch("gn3.api.wgcna.call_wgcna_script") def test_wgcna_endpoint(self, mock_wgcna_script): """test /api/wgcna/run_wgcna endpoint""" |