diff options
-rw-r--r-- | gn3/commands.py | 29 | ||||
-rw-r--r-- | tests/unit/test_commands.py | 43 |
2 files changed, 72 insertions, 0 deletions
diff --git a/gn3/commands.py b/gn3/commands.py index 50b6d29..9692f62 100644 --- a/gn3/commands.py +++ b/gn3/commands.py @@ -1,9 +1,13 @@ """Procedures used to work with the various bio-informatics cli commands""" +from datetime import datetime from typing import Dict from typing import List from typing import Optional +from uuid import uuid4 +from redis.client import Redis # Used only in type hinting +from gn3.exceptions import RedisConnectionError from gn3.file_utils import lookup_file from gn3.file_utils import jsonfile_to_dict @@ -40,3 +44,28 @@ def compose_gemma_cmd( cmd += (" " " ".join([f" {arg}" for arg in gemma_args])) return cmd + + +def queue_cmd(cmd: str, conn: Redis) -> str: + """Given a command CMD, and a redis connection CONN, queue it in Redis +with an initial status of 'queued'. The following status codes are +supported: + + queued: Unprocessed; Still in the queue + running: Still running + success: Successful completion + error: Erroneous completion + + """ + if not conn.ping(): + raise RedisConnectionError + unique_id = ("cmd::" + f"{datetime.now().strftime('%Y-%m-%d%H-%M%S-%M%S-')}" + f"{str(uuid4())}") + for key, value in {"cmd": cmd, + "result": "", + "status": "queued"}.items(): + conn.hset(key, value, unique_id) + conn.rpush("GN2::job-queue", + unique_id) + return unique_id diff --git a/tests/unit/test_commands.py b/tests/unit/test_commands.py index a319332..a1ac6eb 100644 --- a/tests/unit/test_commands.py +++ b/tests/unit/test_commands.py @@ -2,8 +2,21 @@ import os import unittest +from dataclasses import dataclass +from datetime import datetime +from typing import Callable from unittest import mock from gn3.commands import compose_gemma_cmd +from gn3.commands import queue_cmd +from gn3.exceptions import RedisConnectionError + + +@dataclass +class MockRedis: + """Mock Redis connection""" + ping: Callable + hset: mock.MagicMock + rpush: mock.MagicMock class TestCommands(unittest.TestCase): @@ -27,3 +40,33 @@ class TestCommands(unittest.TestCase): "-g /tmp/genofile.txt " "-p /tmp/gf13Ad0tRX/phenofile.txt" " -gk")) + + def test_queue_cmd_exception_raised_when_redis_is_down(self): + """Test that the correct error is raised when Redis is unavailable""" + self.assertRaises(RedisConnectionError, + queue_cmd, + "ls", + MockRedis(ping=lambda: False, + hset=mock.MagicMock(), + rpush=mock.MagicMock())) + + @mock.patch("gn3.commands.datetime") + @mock.patch("gn3.commands.uuid4") + def test_queue_cmd_right_correct_calls_to_redis(self, mock_uuid4, + mock_datetime): + """Test that the cmd is queued properly""" + mock_uuid4.return_value = 1234 + mock_datetime.now.return_value = datetime.fromisoformat('2021-02-12 ' + '17:32:24.' + '859097') + mock_redis_conn = MockRedis(ping=lambda: True, + hset=mock.MagicMock(), + rpush=mock.MagicMock()) + actual_unique_id = "cmd::2021-02-1217-3224-3224-1234" + self.assertEqual(queue_cmd("ls", mock_redis_conn), actual_unique_id) + mock_redis_conn.hset.assert_has_calls( + [mock.call("cmd", "ls", actual_unique_id), + mock.call("result", "", actual_unique_id), + mock.call("status", "queued", actual_unique_id)]) + mock_redis_conn.rpush.assert_has_calls( + [mock.call("GN2::job-queue", actual_unique_id)]) |