about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--gn3/commands.py29
-rw-r--r--tests/unit/test_commands.py43
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)])