about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2022-06-15 08:05:11 +0300
committerFrederick Muriuki Muriithi2022-06-15 08:05:11 +0300
commit6760d322637a3d875242a66e9c1a784866d7df1d (patch)
tree9c789b3f25cb1b1c04dc7974f9aab0ffcb6acdf4
parentc2fa70ec8503d10b990575a547036bfd70a53825 (diff)
downloadgn-uploader-6760d322637a3d875242a66e9c1a784866d7df1d.tar.gz
Setup test fixtures and initial tests for web-UI
-rw-r--r--guix.scm3
-rw-r--r--manifest.scm3
-rw-r--r--qc_app/entry.py4
-rw-r--r--tests/conftest.py30
-rw-r--r--tests/qc_app/test_entry.py55
-rw-r--r--tests/qc_app/test_parse.py12
-rw-r--r--tests/test_instance_dir/config.py11
7 files changed, 113 insertions, 5 deletions
diff --git a/guix.scm b/guix.scm
index 35911ae..0c78fc1 100644
--- a/guix.scm
+++ b/guix.scm
@@ -36,8 +36,7 @@
 	   python-pytest
 	   python-hypothesis))
     (propagated-inputs
-     (list python-rq
-	   python-magic))
+     (list redis))
     (synopsis "GeneNetwork Quality Control Application")
     (description
      "GeneNetwork qc is a quality control application for the data files that
diff --git a/manifest.scm b/manifest.scm
index 42d95bb..407834a 100644
--- a/manifest.scm
+++ b/manifest.scm
@@ -1,5 +1,6 @@
 (specifications->manifest
- (list "python"
+ (list "redis"
+       "python"
        "python-mypy"
        "python-redis"
        "python-flask"
diff --git a/qc_app/entry.py b/qc_app/entry.py
index d876bb7..7f67a33 100644
--- a/qc_app/entry.py
+++ b/qc_app/entry.py
@@ -24,7 +24,7 @@ def errors(request) -> Tuple[str, ...]:
     def __filetype_error__():
         return (
             ("Invalid file type provided.",)
-            if request.form["filetype"] not in ("average", "standard-error")
+            if request.form.get("filetype") not in ("average", "standard-error")
             else tuple())
 
     def __file_missing_error__():
@@ -76,10 +76,10 @@ def zip_file_errors(filepath, upload_dir) -> Tuple[str, ...]:
 @entrybp.route("/", methods=["GET", "POST"])
 def upload_file():
     """Enables uploading the files"""
-    upload_dir = app.config["UPLOAD_FOLDER"]
     if request.method == "GET":
         return render_template("index.html")
 
+    upload_dir = app.config["UPLOAD_FOLDER"]
     request_errors = errors(request)
     if request_errors:
         for error in request_errors:
diff --git a/tests/conftest.py b/tests/conftest.py
index 6ef5374..70bbd37 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1,10 +1,40 @@
 """Set up fixtures for tests"""
+import os
+import socket
+import subprocess
+from contextlib import closing
 
 import pytest
 
+from qc_app import create_app
 from quality_control.parsing import strain_names
 
 @pytest.fixture(scope="session")
 def strains():
     """Parse the strains once every test session"""
     return strain_names("etc/strains.csv")
+
+def is_port_in_use(port: int) -> bool:
+    "Check whether `port` is in use"
+    with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sckt:
+        return sckt.connect_ex(("localhost", port)) == 0
+
+@pytest.fixture(scope="session")
+def redis_server():
+    "Fixture to launch a new redis instance and return appropriate URI"
+    port = next(# pylint: disable=[stop-iteration-return]
+        port for port in range(6379,65535) if not is_port_in_use(port))
+    redis_path = f"{os.getenv('GUIX_ENVIRONMENT')}/bin/redis-server"
+    command = [redis_path, "--port", str(port)]
+    process = subprocess.Popen(command) # pylint: disable=[consider-using-with]
+    yield f"redis://localhost:{port}"
+    process.kill()
+
+@pytest.fixture(scope="module")
+def client(redis_server): # pylint: disable=[redefined-outer-name]
+    "Fixture for test client"
+    app = create_app(f"{os.path.abspath('.')}/tests/test_instance_dir")
+    app.config.update({
+        "REDIS_URL": redis_server
+    })
+    yield app.test_client()
diff --git a/tests/qc_app/test_entry.py b/tests/qc_app/test_entry.py
new file mode 100644
index 0000000..d2908ee
--- /dev/null
+++ b/tests/qc_app/test_entry.py
@@ -0,0 +1,55 @@
+"""Test the entry module in the web-ui"""
+import io
+
+def test_basic_elements_present_in_index_page(client):
+    """
+    GIVEN: A flask application testing client
+    WHEN: the index page is requested with the "POST" method and no datat
+    THEN: verify that the response contains error notifications
+    """
+    response = client.get("/")
+    assert response.status_code == 200
+    ## form present
+    assert b'<form action="/"' in response.data
+    assert b'method="POST"' in response.data
+    assert b'enctype="multipart/form-data"' in response.data
+    assert b'</form>' in response.data
+    ## filetype elements
+    assert b'<input type="radio" name="filetype"' in response.data
+    assert b'id="filetype_standard_error"' in response.data
+    assert b'id="filetype_average"' in response.data
+    ## file upload elements
+    assert b'<label for="file_upload">select file</label>' in response.data
+    assert b'<input type="file" name="qc_text_file"' in response.data
+    assert b'id="file_upload"' in response.data
+    ## submit button
+    assert b'<input type="submit" value="upload file"' in response.data
+
+def test_post_notifies_errors_if_no_data_is_provided(client):
+    response = client.post("/", data={})
+    assert (
+        b'<span class="alert alert-error">Invalid file type provided.</span>'
+        in response.data)
+    assert (
+        b'<span class="alert alert-error">No file was uploaded.</span>'
+        in response.data)
+
+def test_post_with_correct_data(client):
+    """
+    GIVEN: A flask application testing client
+    WHEN: the index page is requested with the "POST" method and with the
+          appropriate data provided
+    THEN: ....
+    """
+    with open("tests/test_data/no_data_errors.tsv", "br") as test_file:
+        response = client.post(
+            "/", data={
+                "filetype": "average",
+                "qc_text_file": (io.BytesIO(test_file.read()), "no_data_errors.tsv")
+            })
+
+    assert response.status_code == 302
+    assert b'Redirecting...' in response.data
+    assert (
+        b'/parse/parse?filename=no_data_errors.tsv&amp;filetype=average'
+        in response.data)
diff --git a/tests/qc_app/test_parse.py b/tests/qc_app/test_parse.py
new file mode 100644
index 0000000..41d2c26
--- /dev/null
+++ b/tests/qc_app/test_parse.py
@@ -0,0 +1,12 @@
+import pytest
+
+def test_parse_with_existing_file(client, monkeypatch):
+    monkeypatch.setattr(
+        "qc_app.jobs.uuid4", lambda : "934c55d8-396e-4959-90e1-2698e9205758")
+    resp = client.get(
+        "/parse/parse?filename=no_data_errors.tsv&filetype=average")
+    print(resp.status)
+    print(resp.data)
+    assert resp.status_code == 302
+    assert b'Redirecting...' in resp.data
+    assert b'/parse/status/934c55d8-396e-4959-90e1-2698e9205758' in resp.data
diff --git a/tests/test_instance_dir/config.py b/tests/test_instance_dir/config.py
new file mode 100644
index 0000000..2ee569b
--- /dev/null
+++ b/tests/test_instance_dir/config.py
@@ -0,0 +1,11 @@
+"""
+The tests configuration file.
+"""
+
+import os
+
+LOG_LEVEL = os.getenv("LOG_LEVEL", "WARNING")
+SECRET_KEY = b"<Please! Please! Please! Change This!>"
+UPLOAD_FOLDER = "/tmp/qc_app_files"
+REDIS_URL = "redis://"
+JOBS_TTL_SECONDS = 600 # 10 minutes