From 135397b858526c16a1874f9eda9076d57b5cbfe2 Mon Sep 17 00:00:00 2001 From: rjmurray Date: Wed, 20 Nov 2024 11:50:18 +0000 Subject: [PATCH] Adding unit tests + snyk vuln --- plugins/redis/.CHECKSUM | 12 +- plugins/redis/bin/komand_redis | 4 +- plugins/redis/help.md | 194 ++++++++++-------- .../redis/komand_redis/actions/get/schema.py | 2 +- .../komand_redis/actions/hash_get/action.py | 3 +- .../komand_redis/actions/hmget/action.py | 16 +- .../redis/komand_redis/actions/set/schema.py | 2 +- .../redis/komand_redis/connection/schema.py | 3 + plugins/redis/plugin.spec.yaml | 42 +++- plugins/redis/requirements.txt | 1 + plugins/redis/setup.py | 2 +- plugins/redis/unit_test/delete.py | 29 +++ .../unit_test/expected/delete_exp.json.exp | 3 + .../redis/unit_test/expected/get_exp.json.exp | 4 + .../unit_test/expected/hash_get_exp.json.exp | 8 + .../unit_test/expected/hash_set_exp.json.exp | 3 + .../unit_test/expected/hincrby_exp.json.exp | 3 + .../unit_test/expected/hmget_exp.json.exp | 5 + .../unit_test/expected/hmset_exp.json.exp | 3 + .../unit_test/expected/keys_exp.json.exp | 4 + .../unit_test/expected/list_get_exp.json.exp | 4 + .../unit_test/expected/list_push_exp.json.exp | 3 + .../redis/unit_test/expected/set_exp.json.exp | 3 + plugins/redis/unit_test/get.py | 29 +++ plugins/redis/unit_test/hash_get.py | 29 +++ plugins/redis/unit_test/hash_set.py | 29 +++ plugins/redis/unit_test/hincrby.py | 29 +++ plugins/redis/unit_test/hmget.py | 29 +++ plugins/redis/unit_test/hmset.py | 29 +++ .../redis/unit_test/inputs/delete.json.exp | 3 + plugins/redis/unit_test/inputs/get.json.exp | 3 + .../redis/unit_test/inputs/hash_get.json.exp | 3 + .../redis/unit_test/inputs/hash_set.json.exp | 8 + .../redis/unit_test/inputs/hincrby.json.exp | 5 + plugins/redis/unit_test/inputs/hmget.json.exp | 9 + plugins/redis/unit_test/inputs/hmset.json.exp | 8 + plugins/redis/unit_test/inputs/keys.json.exp | 3 + .../redis/unit_test/inputs/list_get.json.exp | 4 + .../redis/unit_test/inputs/list_push.json.exp | 4 + plugins/redis/unit_test/inputs/set.json.exp | 5 + plugins/redis/unit_test/keys.py | 29 +++ plugins/redis/unit_test/list_get.py | 29 +++ plugins/redis/unit_test/list_push.py | 29 +++ plugins/redis/unit_test/set.py | 29 +++ plugins/redis/unit_test/util.py | 76 +++++++ 45 files changed, 670 insertions(+), 104 deletions(-) create mode 100644 plugins/redis/unit_test/delete.py create mode 100644 plugins/redis/unit_test/expected/delete_exp.json.exp create mode 100644 plugins/redis/unit_test/expected/get_exp.json.exp create mode 100644 plugins/redis/unit_test/expected/hash_get_exp.json.exp create mode 100644 plugins/redis/unit_test/expected/hash_set_exp.json.exp create mode 100644 plugins/redis/unit_test/expected/hincrby_exp.json.exp create mode 100644 plugins/redis/unit_test/expected/hmget_exp.json.exp create mode 100644 plugins/redis/unit_test/expected/hmset_exp.json.exp create mode 100644 plugins/redis/unit_test/expected/keys_exp.json.exp create mode 100644 plugins/redis/unit_test/expected/list_get_exp.json.exp create mode 100644 plugins/redis/unit_test/expected/list_push_exp.json.exp create mode 100644 plugins/redis/unit_test/expected/set_exp.json.exp create mode 100644 plugins/redis/unit_test/get.py create mode 100644 plugins/redis/unit_test/hash_get.py create mode 100644 plugins/redis/unit_test/hash_set.py create mode 100644 plugins/redis/unit_test/hincrby.py create mode 100644 plugins/redis/unit_test/hmget.py create mode 100644 plugins/redis/unit_test/hmset.py create mode 100644 plugins/redis/unit_test/inputs/delete.json.exp create mode 100644 plugins/redis/unit_test/inputs/get.json.exp create mode 100644 plugins/redis/unit_test/inputs/hash_get.json.exp create mode 100644 plugins/redis/unit_test/inputs/hash_set.json.exp create mode 100644 plugins/redis/unit_test/inputs/hincrby.json.exp create mode 100644 plugins/redis/unit_test/inputs/hmget.json.exp create mode 100644 plugins/redis/unit_test/inputs/hmset.json.exp create mode 100644 plugins/redis/unit_test/inputs/keys.json.exp create mode 100644 plugins/redis/unit_test/inputs/list_get.json.exp create mode 100644 plugins/redis/unit_test/inputs/list_push.json.exp create mode 100644 plugins/redis/unit_test/inputs/set.json.exp create mode 100644 plugins/redis/unit_test/keys.py create mode 100644 plugins/redis/unit_test/list_get.py create mode 100644 plugins/redis/unit_test/list_push.py create mode 100644 plugins/redis/unit_test/set.py create mode 100644 plugins/redis/unit_test/util.py diff --git a/plugins/redis/.CHECKSUM b/plugins/redis/.CHECKSUM index 596c3c560d..b998d6d30b 100644 --- a/plugins/redis/.CHECKSUM +++ b/plugins/redis/.CHECKSUM @@ -1,7 +1,7 @@ { - "spec": "26ec465ad678c031feb5630dbbc52c5a", - "manifest": "9bd2e18ba974d692067c68666b0f6b58", - "setup": "7a35f74c2f09fd47854184525fc022c7", + "spec": "e7f620b0384a972f398c48517675bb8b", + "manifest": "bcbee882883b3bbc53d23c28bd6b860d", + "setup": "c8ba0398d017459776ab5d8547c2cec8", "schemas": [ { "identifier": "delete/schema.py", @@ -9,7 +9,7 @@ }, { "identifier": "get/schema.py", - "hash": "fa7e9712a440e26c1d376336f48b8339" + "hash": "2418731519a2321c938a28e583e704af" }, { "identifier": "hash_get/schema.py", @@ -45,11 +45,11 @@ }, { "identifier": "set/schema.py", - "hash": "68c01da8a0ade66abe0976837036aa99" + "hash": "f66301278673270476bc92beb2e90fe3" }, { "identifier": "connection/schema.py", - "hash": "0ac54ef147901f5446083fc96b7f572c" + "hash": "9eaaa3df08bbb42bb41cddb928260b07" } ] } \ No newline at end of file diff --git a/plugins/redis/bin/komand_redis b/plugins/redis/bin/komand_redis index ea92438435..9f80c260e6 100755 --- a/plugins/redis/bin/komand_redis +++ b/plugins/redis/bin/komand_redis @@ -7,7 +7,7 @@ from sys import argv Name = "Redis" Vendor = "rapid7" Version = "1.0.2" -Description = "The Redis plugin allows you to add, update, and manage data in a Redis database" +Description = "Redis is an in-memory data structure project implementing a distributed, in-memory key-value database with optional durability. Redis supports different kinds of abstract data structures, such as strings, lists, maps, sets, sorted sets, HyperLogLogs, bitmaps, streams, and spatial indexes.\nThis package allows you to interact with the [Redis](https://redis.io/) database API" def main(): @@ -23,6 +23,8 @@ def main(): monkey.patch_all() import insightconnect_plugin_runtime + import sys + sys.path.append(os.path.abspath("../")) from komand_redis import connection, actions, triggers, tasks class ICONRedis(insightconnect_plugin_runtime.Plugin): diff --git a/plugins/redis/help.md b/plugins/redis/help.md index 0cab4ed596..65ce557191 100644 --- a/plugins/redis/help.md +++ b/plugins/redis/help.md @@ -1,6 +1,6 @@ # Description -The Redis plugin allows you to add, update, and manage data in a Redis database +Redis is an in-memory data structure project implementing a distributed, in-memory key-value database with optional durability. Redis supports different kinds of abstract data structures, such as strings, lists, maps, sets, sorted sets, HyperLogLogs, bitmaps, streams, and spatial indexes.\nThis package allows you to interact with the [Redis](https://redis.io/) database API # Key Features @@ -22,16 +22,16 @@ The connection configuration accepts the following parameters: |Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|db|integer|0|True|DB to use usually (0-15)|None|None|None|None| -|host|string|None|True|Host, e.g. 10.4.4.4|None|None|None|None| -|port|integer|6379|True|Port|None|None|None|None| +|db|integer|0|True|DB to use usually (0-15)|None|10|None|None| +|host|string|None|True|Host, e.g. 10.4.4.4|None|10.4.4.4|None|None| +|port|integer|6379|True|Port|None|6379|None|None| Example input: ``` { "db": 0, - "host": "", + "host": "10.4.4.4", "port": 6379 } ``` @@ -49,13 +49,13 @@ This action is used to delete a key |Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|key|string|None|True|Key to delete|None|None|None|None| +|key|string|None|True|Key to delete|None|example:1234:session|None|None| Example input: ``` { - "key": "" + "key": "example:1234:session" } ``` @@ -63,31 +63,31 @@ Example input: |Name|Type|Required|Description|Example| | :--- | :--- | :--- | :--- | :--- | -|count|integer|False|Number of keys deleted|None| +|count|integer|False|Number of keys deleted|1| Example output: ``` { - "count": 0 + "count": 1 } ``` #### Get - -This action is used to get a key + +This action is used to get a key. Get will return a value at `key` if found, otherwise found will be false ##### Input |Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|key|string|None|True|Key to get|None|None|None|None| +|key|string|None|True|Key to get|None|example:1234:active|None|None| Example input: ``` { - "key": "" + "key": "example:1234:active" } ``` @@ -95,33 +95,33 @@ Example input: |Name|Type|Required|Description|Example| | :--- | :--- | :--- | :--- | :--- | -|found|boolean|False|True if found|None| -|value|string|False|Value|None| +|found|boolean|False|True if found|True| +|value|string|False|Value|True| Example output: ``` { "found": true, - "value": "" + "value": true } ``` #### Hash Get -This action is used to get key's hash +This action is used to return all hash values at `key`. If no hash values are found `false` is returned. ##### Input |Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|key|string|None|True|Key to get|None|None|None|None| +|key|string|None|True|Key to get|None|user:profile|None|None| Example input: ``` { - "key": "" + "key": "user:profile" } ``` @@ -129,37 +129,47 @@ Example input: |Name|Type|Required|Description|Example| | :--- | :--- | :--- | :--- | :--- | -|found|boolean|False|True if found|None| -|values|object|False|Values|None| +|found|boolean|False|True if found|True| +|values|object|False|Values|{'name': 'Example Name', 'email': 'Example.email@example.com', 'age': '30'}| Example output: ``` { "found": true, - "values": {} + "values": { + "age": "30", + "email": "Example.email@example.com", + "name": "Example Name" + } } ``` #### Hash Set -This action is used to set key's hash +This action is used to set a given key to a key:value object. All values must be strings. +There is an optional expiration timeout which will auto remove the key when `expire` seconds have passed + ##### Input |Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|expire|integer|None|False|Expiration in seconds|None|None|None|None| -|key|string|None|True|Key|None|None|None|None| -|values|object|None|True|Object hash field:value to set|None|None|None|None| +|expire|integer|None|False|Expiration in seconds|None|100|None|None| +|key|string|None|True|Key|None|user:1234|None|None| +|values|object|None|True|Object hash field:value to set|None|{'name': 'John Doe', 'email': 'johndoe@example.com', 'age': '30'}|None|None| Example input: ``` { - "expire": 0, - "key": "", - "values": {} + "expire": 100, + "key": "user:1234", + "values": { + "age": "30", + "email": "johndoe@example.com", + "name": "John Doe" + } } ``` @@ -167,34 +177,35 @@ Example input: |Name|Type|Required|Description|Example| | :--- | :--- | :--- | :--- | :--- | -|reply|string|False|Reply (usually OK)|None| +|reply|string|False|Reply (usually OK)|OK| Example output: ``` { - "reply": "" + "reply": "OK" } ``` #### Hash Increment By -This action is used to increments the number stored at field in the hash stored at key by increment +This action is used to increments the number stored at field in the hash stored at key by increment. +If key does not exist, a new key holding a hash is created. If field does not exist the value is set to 0 before the operation is performed ##### Input |Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|field|string|None|True|Field to increment|None|None|None|None| -|key|string|None|True|Key to lookup|None|None|None|None| -|value|integer|0|True|How much to increment by|None|None|None|None| +|field|string|None|True|Field to increment|None|login_count|None|None| +|key|string|None|True|Key to lookup|None|user:profile:123|None|None| +|value|integer|0|True|How much to increment by|None|1|None|None| Example input: ``` { - "field": "", - "key": "", + "field": "login_count", + "key": "user:profile:123", "value": 0 } ``` @@ -203,13 +214,13 @@ Example input: |Name|Type|Required|Description|Example| | :--- | :--- | :--- | :--- | :--- | -|result|integer|False|Result returned after operation is ran|None| +|result|integer|False|Result returned after operation is ran|1| Example output: ``` { - "result": 0 + "result": 1 } ``` @@ -221,19 +232,20 @@ This action is used to returns the values associated with the specified fields i |Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|fields|[]string|None|False|Fields to retrieve values from|None|None|None|None| -|get_all|boolean|False|True|Get all values|None|None|None|None| -|key|string|None|True|Key to get|None|None|None|None| +|fields|[]string|None|False|Fields to retrieve values from|None|["name", "email"]|None|None| +|get_all|boolean|False|True|Get all values|None|False|None|None| +|key|string|None|True|Key to get|None|user:profile:123|None|None| Example input: ``` { "fields": [ - "" + "name", + "email" ], "get_all": false, - "key": "" + "key": "user:profile:123" } ``` @@ -241,35 +253,43 @@ Example input: |Name|Type|Required|Description|Example| | :--- | :--- | :--- | :--- | :--- | -|values|object|False|Values returned from HMGET|None| +|values|object|False|Values returned from HMGET|{'name': 'Ryan Test', 'email': 'Ryan.test@example.com'}| Example output: ``` { - "values": {} + "values": { + "email": "Ryan.test@example.com", + "name": "Ryan Test" + } } ``` #### Hash Multi Set -This action is used to sets the specified fields to their respective values in the hash stored at key +This action is used to sets the specified fields to their respective values in the hash stored at key. +This command overwrites any specified fields already existing in the hash. If key does not exist, a new key holding a hash is created ##### Input |Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|expire|integer|None|False|Expiration in seconds|None|None|None|None| -|key|string|None|True|Key|None|None|None|None| -|values|object|None|True|Object hash field:value to set|None|None|None|None| +|expire|integer|None|False|Expiration in seconds|None|100|None|None| +|key|string|None|True|Key|None|user:profile:123|None|None| +|values|object|None|True|Object hash field:value to set|None|{'name': 'Test Name', 'email': 'Test.Name@example.com', 'age': '30'}|None|None| Example input: ``` { - "expire": 0, - "key": "", - "values": {} + "expire": 100, + "key": "user:profile:123", + "values": { + "age": "30", + "email": "Test.Name@example.com", + "name": "Test Name" + } } ``` @@ -277,7 +297,7 @@ Example input: |Name|Type|Required|Description|Example| | :--- | :--- | :--- | :--- | :--- | -|reply|boolean|False|Reply (usually OK)|None| +|reply|boolean|False|Reply (usually OK)|True| Example output: @@ -295,13 +315,13 @@ This action is used to return keys matching pattern |Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|pattern|string|None|True|Pattern, e.g. *o*|None|None|None|None| +|pattern|string|None|True|Pattern, e.g. *o*|None|example:*:session|None|None| Example input: ``` { - "pattern": "" + "pattern": "example:*:session" } ``` @@ -309,16 +329,18 @@ Example input: |Name|Type|Required|Description|Example| | :--- | :--- | :--- | :--- | :--- | -|count|integer|False|Count of keys found|None| -|keys|[]string|False|Keys returned|None| +|count|integer|False|Count of keys found|1| +|keys|[]string|False|Keys returned|["example:1234:session", "example:5678:session", "example:abcd:session"]| Example output: ``` { - "count": 0, + "count": 1, "keys": [ - "" + "example:1234:session", + "example:5678:session", + "example:abcd:session" ] } ``` @@ -331,15 +353,15 @@ This action is used to get all elements in a list |Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|count|integer|1000|False|Max results to return|None|None|None|None| -|key|string|None|True|Key to get|None|None|None|None| +|count|integer|1000|False|Max results to return|None|1000|None|None| +|key|string|None|True|Key to get|None|user:task_list:123|None|None| Example input: ``` { "count": 1000, - "key": "" + "key": "user:task_list:123" } ``` @@ -347,8 +369,8 @@ Example input: |Name|Type|Required|Description|Example| | :--- | :--- | :--- | :--- | :--- | -|found|boolean|False|True if found|None| -|values|[]string|False|Values|None| +|found|boolean|False|True if found|True| +|values|[]string|False|Values|["task1", "task2", "task3", "task4"]| Example output: @@ -356,7 +378,10 @@ Example output: { "found": true, "values": [ - "" + "task1", + "task2", + "task3", + "task4" ] } ``` @@ -369,17 +394,17 @@ This action is used to list key's push |Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|expire|integer|None|False|Expiration in seconds|None|None|None|None| -|key|string|None|True|Key|None|None|None|None| -|value|string|None|True|Value to append|None|None|None|None| +|expire|integer|None|False|Expiration in seconds|None|100|None|None| +|key|string|None|True|Key|None|user:task_list:123|None|None| +|value|string|None|True|Value to append|None|Complete monthly report|None|None| Example input: ``` { - "expire": 0, - "key": "", - "value": "" + "expire": 100, + "key": "user:task_list:123", + "value": "Complete monthly report" } ``` @@ -387,35 +412,36 @@ Example input: |Name|Type|Required|Description|Example| | :--- | :--- | :--- | :--- | :--- | -|reply|string|False|Reply (usually OK)|None| +|reply|string|False|Reply (usually OK)|OK| Example output: ``` { - "reply": "" + "reply": "OK" } ``` #### Set - -This action is used to set a key + +This action is used to set a key to a string value. +There is an optional expiration timeout which will auto remove the key when `expire` seconds have passed ##### Input |Name|Type|Default|Required|Description|Enum|Example|Placeholder|Tooltip| | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | -|expire|integer|None|False|Expiration in seconds|None|None|None|None| -|key|string|None|True|Key to set|None|None|None|None| -|value|string|None|True|Value to set|None|None|None|None| +|expire|integer|None|False|Expiration in seconds|None|100|None|None| +|key|string|None|True|Key to set|None|example:1234:session|None|None| +|value|string|None|True|Value to set|None|active|None|None| Example input: ``` { - "expire": 0, - "key": "", - "value": "" + "expire": 100, + "key": "example:1234:session", + "value": "active" } ``` @@ -423,13 +449,13 @@ Example input: |Name|Type|Required|Description|Example| | :--- | :--- | :--- | :--- | :--- | -|reply|string|False|Reply (usually OK)|None| +|reply|string|False|Reply (usually OK)|OK| Example output: ``` { - "reply": "" + "reply": "OK" } ``` ### Triggers diff --git a/plugins/redis/komand_redis/actions/get/schema.py b/plugins/redis/komand_redis/actions/get/schema.py index 40dc7bf6cd..20dd699f99 100755 --- a/plugins/redis/komand_redis/actions/get/schema.py +++ b/plugins/redis/komand_redis/actions/get/schema.py @@ -4,7 +4,7 @@ class Component: - DESCRIPTION = "Get a key" + DESCRIPTION = "This action is used to get a key. It will return the key at `value` if found, otherwise found will be false" class Input: diff --git a/plugins/redis/komand_redis/actions/hash_get/action.py b/plugins/redis/komand_redis/actions/hash_get/action.py index 86304c1b92..5ab1e9ec8e 100755 --- a/plugins/redis/komand_redis/actions/hash_get/action.py +++ b/plugins/redis/komand_redis/actions/hash_get/action.py @@ -13,7 +13,8 @@ def __init__(self): def run(self, params={}): """Run action""" values = self.connection.redis.hgetall(params["key"]) - found = not not values + found = bool(values) + if values: v = {} for key, val in values.items(): diff --git a/plugins/redis/komand_redis/actions/hmget/action.py b/plugins/redis/komand_redis/actions/hmget/action.py index 1f8ed77ba1..80f1096cf2 100755 --- a/plugins/redis/komand_redis/actions/hmget/action.py +++ b/plugins/redis/komand_redis/actions/hmget/action.py @@ -21,18 +21,22 @@ def run(self, params={}): try: if get_all: result = self.connection.redis.hgetall(key) + if result: + v = {} + for key, val in result.items(): + v[key.decode("utf-8")] = val.decode("utf-8") + result = v else: result = self.connection.redis.hmget(key, fields) + if result: + v = {} + for item in range(0, len(result)): + v[fields[item]] = result[item].decode("utf-8") + result = v except Exception as e: self.logger.error("An error occurred while running HMSET: ", e) raise - if result: - v = {} - for key, val in result.items(): - v[key.decode("utf-8")] = val.decode("utf-8") - result = v - return {"values": result} def test(self): diff --git a/plugins/redis/komand_redis/actions/set/schema.py b/plugins/redis/komand_redis/actions/set/schema.py index 42320e369f..affff14905 100755 --- a/plugins/redis/komand_redis/actions/set/schema.py +++ b/plugins/redis/komand_redis/actions/set/schema.py @@ -4,7 +4,7 @@ class Component: - DESCRIPTION = "Set a key" + DESCRIPTION = "This action is used to set a key to a string value. There is an optional expiration timeout which will auto remove the key when `expire` seconds have passed" class Input: diff --git a/plugins/redis/komand_redis/connection/schema.py b/plugins/redis/komand_redis/connection/schema.py index ea682c5242..2bb50652dd 100755 --- a/plugins/redis/komand_redis/connection/schema.py +++ b/plugins/redis/komand_redis/connection/schema.py @@ -17,17 +17,20 @@ class ConnectionSchema(insightconnect_plugin_runtime.Input): "properties": { "db": { "type": "integer", + "title": "DB", "description": "DB to use usually (0-15)", "default": 0, "order": 3 }, "host": { "type": "string", + "title": "Host", "description": "Host, e.g. 10.4.4.4", "order": 1 }, "port": { "type": "integer", + "title": "Port", "description": "Port", "default": 6379, "order": 2 diff --git a/plugins/redis/plugin.spec.yaml b/plugins/redis/plugin.spec.yaml index 4bb14e7c03..b65ca71b83 100644 --- a/plugins/redis/plugin.spec.yaml +++ b/plugins/redis/plugin.spec.yaml @@ -3,7 +3,7 @@ extension: plugin products: [insightconnect] name: redis title: Redis -description: The Redis plugin allows you to add, update, and manage data in a Redis database +description: Redis is an in-memory data structure project implementing a distributed, in-memory key-value database with optional durability. Redis supports different kinds of abstract data structures, such as strings, lists, maps, sets, sorted sets, HyperLogLogs, bitmaps, streams, and spatial indexes.\nThis package allows you to interact with the [Redis](https://redis.io/) database API version: 1.0.2 connection_version: 1 vendor: rapid7 @@ -42,19 +42,25 @@ version_history: - "0.1.0 - Initial plugin" connection: host: + title: Host type: string description: Host, e.g. 10.4.4.4 required: true + example: 10.4.4.4 port: + title: Port type: integer description: Port default: 6379 required: true + example: 6379 db: + title: DB type: integer description: DB to use usually (0-15) default: 0 required: true + example: 10 actions: delete: title: Delete @@ -72,9 +78,10 @@ actions: type: integer description: Number of keys deleted required: false + example: 1 set: title: Set - description: Set a key + description: This action is used to set a key to a string value. There is an optional expiration timeout which will auto remove the key when `expire` seconds have passed input: key: title: Key @@ -100,9 +107,10 @@ actions: type: string description: Reply (usually OK) required: false + example: OK get: title: Get - description: Get a key + description: This action is used to get a key. It will return the key at `value` if found, otherwise found will be false input: key: title: Key @@ -116,11 +124,13 @@ actions: type: boolean description: True if found required: false + example: true value: title: Value type: string description: Value required: false + example: true keys: title: Keys description: Return keys matching pattern @@ -137,11 +147,13 @@ actions: type: integer description: Count of keys found required: false + example: 1 keys: title: Keys type: '[]string' description: Keys returned required: false + example: [ "example:1234:session", "example:5678:session", "example:abcd:session" ] hash_set: title: Hash Set description: Set key's hash @@ -170,6 +182,7 @@ actions: type: string description: Reply (usually OK) required: false + example: OK hash_get: title: Hash Get description: Get key's hash @@ -179,17 +192,20 @@ actions: type: string description: Key to get required: true + example: user:profile output: found: title: Found type: boolean description: True if found required: false + example: true values: title: Values type: object description: Values required: false + example: { "name": "Example Name", "email": "Example.email@example.com", "age": "30" } list_push: title: List Push description: List key's push @@ -199,22 +215,26 @@ actions: type: string description: Key required: true + example: user:task_list:123 value: title: Value type: string description: Value to append required: true + example: Complete monthly report expire: title: Expire type: integer description: Expiration in seconds required: false + example: 100 output: reply: title: Reply type: string description: Reply (usually OK) required: false + example: OK list_get: title: List Get description: Get all elements in a list @@ -224,23 +244,27 @@ actions: type: string description: Key to get required: true + example: user:task_list:123 count: title: Count type: integer description: Max results to return default: 1000 required: false + example: 1000 output: found: title: Found type: boolean description: True if found required: false + example: true values: title: Values type: '[]string' description: Values required: false + example: ["task1", "task2", "task3", "task4"] hmset: title: Hash Multi Set description: Sets the specified fields to their respective values in the hash @@ -251,22 +275,26 @@ actions: type: string description: Key required: true + example: user:profile:123 values: title: Values type: object description: Object hash field:value to set required: true + example: { "name": "Test Name", "email": "Test.Name@example.com", "age": "30"} expire: title: Expire type: integer description: Expiration in seconds required: false + example: 100 output: reply: title: Reply type: boolean description: Reply (usually OK) required: false + example: true hmget: title: Hash Multi Get description: Returns the values associated with the specified fields in the hash @@ -277,23 +305,27 @@ actions: type: string description: Key to get required: true + example: user:profile:123 fields: title: Fields type: '[]string' description: Fields to retrieve values from required: false + example: ["name", "email"] get_all: title: Get All type: boolean description: Get all values required: true default: false + example: false output: values: title: Values type: object description: Values returned from HMGET required: false + example: { "name": "Ryan Test", "email": "Ryan.test@example.com" } hincrby: title: Hash Increment By description: Increments the number stored at field in the hash stored at key by @@ -304,20 +336,24 @@ actions: description: Key to lookup type: string required: true + example: user:profile:123 field: title: Field description: Field to increment type: string required: true + example: login_count value: title: Value description: How much to increment by type: integer required: true default: 0 + example: 1 output: result: title: Result description: Result returned after operation is ran type: integer required: false + example: 1 diff --git a/plugins/redis/requirements.txt b/plugins/redis/requirements.txt index e44bb3b808..b74557ab84 100755 --- a/plugins/redis/requirements.txt +++ b/plugins/redis/requirements.txt @@ -2,3 +2,4 @@ # All dependencies must be version-pinned, eg. requests==1.2.0 # See: https://pip.pypa.io/en/stable/user_guide/#requirements-files redis==4.3.6 +parameterized==0.9.0 \ No newline at end of file diff --git a/plugins/redis/setup.py b/plugins/redis/setup.py index 62371a4d45..2480e7f7cd 100644 --- a/plugins/redis/setup.py +++ b/plugins/redis/setup.py @@ -4,7 +4,7 @@ setup(name="redis-rapid7-plugin", version="1.0.2", - description="The Redis plugin allows you to add, update, and manage data in a Redis database", + description="Redis is an in-memory data structure project implementing a distributed, in-memory key-value database with optional durability. Redis supports different kinds of abstract data structures, such as strings, lists, maps, sets, sorted sets, HyperLogLogs, bitmaps, streams, and spatial indexes.\nThis package allows you to interact with the [Redis](https://redis.io/) database API", author="rapid7", author_email="", url="", diff --git a/plugins/redis/unit_test/delete.py b/plugins/redis/unit_test/delete.py new file mode 100644 index 0000000000..015794d2ab --- /dev/null +++ b/plugins/redis/unit_test/delete.py @@ -0,0 +1,29 @@ +import os +import sys + +sys.path.append(os.path.abspath("../")) + +from util import Util +from unittest import TestCase +from unittest.mock import MagicMock, patch +from jsonschema import validate +from komand_redis.actions.delete import Delete + + +class TestDelete(TestCase): + def setUp(self) -> None: + self.action = None + + @patch("redis.StrictRedis", return_value=Util.mock_redis()) + def mocked_connector(mocked_redis: MagicMock) -> None: + self.action = Util.default_connector(Delete()) + + mocked_connector() + + def test_delete(self): + input_param = Util.load_json("inputs/delete.json.exp") + expect = Util.load_json("expected/delete_exp.json.exp") + actual = self.action.run(input_param) + validate(input_param, self.action.input.schema) + self.assertEqual(expect, actual) + validate(actual, self.action.output.schema) diff --git a/plugins/redis/unit_test/expected/delete_exp.json.exp b/plugins/redis/unit_test/expected/delete_exp.json.exp new file mode 100644 index 0000000000..f98bb3067d --- /dev/null +++ b/plugins/redis/unit_test/expected/delete_exp.json.exp @@ -0,0 +1,3 @@ +{ + "count": 10 +} \ No newline at end of file diff --git a/plugins/redis/unit_test/expected/get_exp.json.exp b/plugins/redis/unit_test/expected/get_exp.json.exp new file mode 100644 index 0000000000..a054e19b23 --- /dev/null +++ b/plugins/redis/unit_test/expected/get_exp.json.exp @@ -0,0 +1,4 @@ +{ + "found": false, + "value": "" +} \ No newline at end of file diff --git a/plugins/redis/unit_test/expected/hash_get_exp.json.exp b/plugins/redis/unit_test/expected/hash_get_exp.json.exp new file mode 100644 index 0000000000..d7eea42346 --- /dev/null +++ b/plugins/redis/unit_test/expected/hash_get_exp.json.exp @@ -0,0 +1,8 @@ +{ + "found": true, + "values": { + "age": "20", + "email": "Test@example.com", + "name": "Test User" + } +} \ No newline at end of file diff --git a/plugins/redis/unit_test/expected/hash_set_exp.json.exp b/plugins/redis/unit_test/expected/hash_set_exp.json.exp new file mode 100644 index 0000000000..cc2b36c602 --- /dev/null +++ b/plugins/redis/unit_test/expected/hash_set_exp.json.exp @@ -0,0 +1,3 @@ +{ + "reply": "OK" +} \ No newline at end of file diff --git a/plugins/redis/unit_test/expected/hincrby_exp.json.exp b/plugins/redis/unit_test/expected/hincrby_exp.json.exp new file mode 100644 index 0000000000..48777f7ede --- /dev/null +++ b/plugins/redis/unit_test/expected/hincrby_exp.json.exp @@ -0,0 +1,3 @@ +{ + "result": 0 +} \ No newline at end of file diff --git a/plugins/redis/unit_test/expected/hmget_exp.json.exp b/plugins/redis/unit_test/expected/hmget_exp.json.exp new file mode 100644 index 0000000000..e3291c2cc7 --- /dev/null +++ b/plugins/redis/unit_test/expected/hmget_exp.json.exp @@ -0,0 +1,5 @@ +{ + "values": { + "login_count": "0" + } +} \ No newline at end of file diff --git a/plugins/redis/unit_test/expected/hmset_exp.json.exp b/plugins/redis/unit_test/expected/hmset_exp.json.exp new file mode 100644 index 0000000000..2d0e54827b --- /dev/null +++ b/plugins/redis/unit_test/expected/hmset_exp.json.exp @@ -0,0 +1,3 @@ +{ + "reply": true +} \ No newline at end of file diff --git a/plugins/redis/unit_test/expected/keys_exp.json.exp b/plugins/redis/unit_test/expected/keys_exp.json.exp new file mode 100644 index 0000000000..4da820ef66 --- /dev/null +++ b/plugins/redis/unit_test/expected/keys_exp.json.exp @@ -0,0 +1,4 @@ +{ + "count": 2, + "keys": ["count", "keys"] +} \ No newline at end of file diff --git a/plugins/redis/unit_test/expected/list_get_exp.json.exp b/plugins/redis/unit_test/expected/list_get_exp.json.exp new file mode 100644 index 0000000000..6667163977 --- /dev/null +++ b/plugins/redis/unit_test/expected/list_get_exp.json.exp @@ -0,0 +1,4 @@ +{ + "found": false, + "values": [] +} \ No newline at end of file diff --git a/plugins/redis/unit_test/expected/list_push_exp.json.exp b/plugins/redis/unit_test/expected/list_push_exp.json.exp new file mode 100644 index 0000000000..cc2b36c602 --- /dev/null +++ b/plugins/redis/unit_test/expected/list_push_exp.json.exp @@ -0,0 +1,3 @@ +{ + "reply": "OK" +} \ No newline at end of file diff --git a/plugins/redis/unit_test/expected/set_exp.json.exp b/plugins/redis/unit_test/expected/set_exp.json.exp new file mode 100644 index 0000000000..cc2b36c602 --- /dev/null +++ b/plugins/redis/unit_test/expected/set_exp.json.exp @@ -0,0 +1,3 @@ +{ + "reply": "OK" +} \ No newline at end of file diff --git a/plugins/redis/unit_test/get.py b/plugins/redis/unit_test/get.py new file mode 100644 index 0000000000..9606969cc6 --- /dev/null +++ b/plugins/redis/unit_test/get.py @@ -0,0 +1,29 @@ +import os +import sys + +sys.path.append(os.path.abspath("../")) + +from util import Util +from unittest import TestCase +from unittest.mock import MagicMock, patch +from jsonschema import validate +from komand_redis.actions.get import Get + + +class TestGet(TestCase): + def setUp(self) -> None: + self.action = None + + @patch("redis.StrictRedis", return_value=Util.mock_redis()) + def mocked_connector(mocked_redis: MagicMock) -> None: + self.action = Util.default_connector(Get()) + + mocked_connector() + + def test_get(self): + input_param = Util.load_json("inputs/get.json.exp") + expect = Util.load_json("expected/get_exp.json.exp") + actual = self.action.run(input_param) + validate(input_param, self.action.input.schema) + self.assertEqual(expect, actual) + validate(actual, self.action.output.schema) diff --git a/plugins/redis/unit_test/hash_get.py b/plugins/redis/unit_test/hash_get.py new file mode 100644 index 0000000000..a03dbbf0a0 --- /dev/null +++ b/plugins/redis/unit_test/hash_get.py @@ -0,0 +1,29 @@ +import os +import sys + +sys.path.append(os.path.abspath("../")) + +from util import Util +from unittest import TestCase +from unittest.mock import MagicMock, patch +from jsonschema import validate +from komand_redis.actions.hash_get import HashGet + + +class TestHashGet(TestCase): + def setUp(self) -> None: + self.action = None + + @patch("redis.StrictRedis", return_value=Util.mock_redis()) + def mocked_connector(mocked_redis: MagicMock) -> None: + self.action = Util.default_connector(HashGet()) + + mocked_connector() + + def test_hash_get(self): + input_param = Util.load_json("inputs/hash_get.json.exp") + expect = Util.load_json("expected/hash_get_exp.json.exp") + actual = self.action.run(input_param) + validate(input_param, self.action.input.schema) + self.assertEqual(expect, actual) + validate(actual, self.action.output.schema) diff --git a/plugins/redis/unit_test/hash_set.py b/plugins/redis/unit_test/hash_set.py new file mode 100644 index 0000000000..a824fd7215 --- /dev/null +++ b/plugins/redis/unit_test/hash_set.py @@ -0,0 +1,29 @@ +import os +import sys + +sys.path.append(os.path.abspath("../")) + +from util import Util +from unittest import TestCase +from unittest.mock import MagicMock, patch +from jsonschema import validate +from komand_redis.actions.hash_set import HashSet + + +class TestHashSet(TestCase): + def setUp(self) -> None: + self.action = None + + @patch("redis.StrictRedis", return_value=Util.mock_redis()) + def mocked_connector(mocked_redis: MagicMock) -> None: + self.action = Util.default_connector(HashSet()) + + mocked_connector() + + def test_hash_set(self): + input_param = Util.load_json("inputs/hash_set.json.exp") + expect = Util.load_json("expected/hash_set_exp.json.exp") + actual = self.action.run(input_param) + validate(input_param, self.action.input.schema) + self.assertEqual(expect, actual) + validate(actual, self.action.output.schema) diff --git a/plugins/redis/unit_test/hincrby.py b/plugins/redis/unit_test/hincrby.py new file mode 100644 index 0000000000..67643637ed --- /dev/null +++ b/plugins/redis/unit_test/hincrby.py @@ -0,0 +1,29 @@ +import os +import sys + +sys.path.append(os.path.abspath("../")) + +from util import Util +from unittest import TestCase +from unittest.mock import MagicMock, patch +from jsonschema import validate +from komand_redis.actions.hincrby import Hincrby + + +class TestHincrby(TestCase): + def setUp(self) -> None: + self.action = None + + @patch("redis.StrictRedis", return_value=Util.mock_redis()) + def mocked_connector(mocked_redis: MagicMock) -> None: + self.action = Util.default_connector(Hincrby()) + + mocked_connector() + + def test_hincrby(self): + input_param = Util.load_json("inputs/hincrby.json.exp") + expect = Util.load_json("expected/hincrby_exp.json.exp") + actual = self.action.run(input_param) + validate(input_param, self.action.input.schema) + self.assertEqual(expect, actual) + validate(actual, self.action.output.schema) diff --git a/plugins/redis/unit_test/hmget.py b/plugins/redis/unit_test/hmget.py new file mode 100644 index 0000000000..02d5f025d5 --- /dev/null +++ b/plugins/redis/unit_test/hmget.py @@ -0,0 +1,29 @@ +import os +import sys + +sys.path.append(os.path.abspath("../")) + +from util import Util +from unittest import TestCase +from unittest.mock import MagicMock, patch +from jsonschema import validate +from komand_redis.actions.hmget import Hmget + + +class TestHmget(TestCase): + def setUp(self) -> None: + self.action = None + + @patch("redis.StrictRedis", return_value=Util.mock_redis()) + def mocked_connector(mocked_redis: MagicMock) -> None: + self.action = Util.default_connector(Hmget()) + + mocked_connector() + + def test_hmget(self): + input_param = Util.load_json("inputs/hmget.json.exp") + expect = Util.load_json("expected/hmget_exp.json.exp") + actual = self.action.run(input_param) + validate(input_param, self.action.input.schema) + self.assertEqual(expect, actual) + validate(actual, self.action.output.schema) diff --git a/plugins/redis/unit_test/hmset.py b/plugins/redis/unit_test/hmset.py new file mode 100644 index 0000000000..176f65de05 --- /dev/null +++ b/plugins/redis/unit_test/hmset.py @@ -0,0 +1,29 @@ +import os +import sys + +sys.path.append(os.path.abspath("../")) + +from util import Util +from unittest import TestCase +from unittest.mock import MagicMock, patch +from jsonschema import validate +from komand_redis.actions.hmset import Hmset + + +class TestHmset(TestCase): + def setUp(self) -> None: + self.action = None + + @patch("redis.StrictRedis", return_value=Util.mock_redis()) + def mocked_connector(mocked_redis: MagicMock) -> None: + self.action = Util.default_connector(Hmset()) + + mocked_connector() + + def test_hmset(self): + input_param = Util.load_json("inputs/hmset.json.exp") + expect = Util.load_json("expected/hmset_exp.json.exp") + actual = self.action.run(input_param) + validate(input_param, self.action.input.schema) + self.assertEqual(expect, actual) + validate(actual, self.action.output.schema) diff --git a/plugins/redis/unit_test/inputs/delete.json.exp b/plugins/redis/unit_test/inputs/delete.json.exp new file mode 100644 index 0000000000..a9a315195a --- /dev/null +++ b/plugins/redis/unit_test/inputs/delete.json.exp @@ -0,0 +1,3 @@ +{ + "key": "user:1234" +} \ No newline at end of file diff --git a/plugins/redis/unit_test/inputs/get.json.exp b/plugins/redis/unit_test/inputs/get.json.exp new file mode 100644 index 0000000000..a9a315195a --- /dev/null +++ b/plugins/redis/unit_test/inputs/get.json.exp @@ -0,0 +1,3 @@ +{ + "key": "user:1234" +} \ No newline at end of file diff --git a/plugins/redis/unit_test/inputs/hash_get.json.exp b/plugins/redis/unit_test/inputs/hash_get.json.exp new file mode 100644 index 0000000000..a9a315195a --- /dev/null +++ b/plugins/redis/unit_test/inputs/hash_get.json.exp @@ -0,0 +1,3 @@ +{ + "key": "user:1234" +} \ No newline at end of file diff --git a/plugins/redis/unit_test/inputs/hash_set.json.exp b/plugins/redis/unit_test/inputs/hash_set.json.exp new file mode 100644 index 0000000000..0983a3aae0 --- /dev/null +++ b/plugins/redis/unit_test/inputs/hash_set.json.exp @@ -0,0 +1,8 @@ +{ + "key": "user:1234", + "values": { + "age": "30", + "email": "johndoe@example.com", + "name": "John Doe" + } +} \ No newline at end of file diff --git a/plugins/redis/unit_test/inputs/hincrby.json.exp b/plugins/redis/unit_test/inputs/hincrby.json.exp new file mode 100644 index 0000000000..7a3b7844a3 --- /dev/null +++ b/plugins/redis/unit_test/inputs/hincrby.json.exp @@ -0,0 +1,5 @@ +{ + "field": "login_count", + "key": "user:profile:123", + "value": 0 +} \ No newline at end of file diff --git a/plugins/redis/unit_test/inputs/hmget.json.exp b/plugins/redis/unit_test/inputs/hmget.json.exp new file mode 100644 index 0000000000..e0abbf680b --- /dev/null +++ b/plugins/redis/unit_test/inputs/hmget.json.exp @@ -0,0 +1,9 @@ +{ + "fields": + [ + "name", + "email" + ], + "get_all": true, + "key": "user:profile:123" +} \ No newline at end of file diff --git a/plugins/redis/unit_test/inputs/hmset.json.exp b/plugins/redis/unit_test/inputs/hmset.json.exp new file mode 100644 index 0000000000..11da552b8c --- /dev/null +++ b/plugins/redis/unit_test/inputs/hmset.json.exp @@ -0,0 +1,8 @@ +{ + "key": "user:4567", + "values": { + "age": "30", + "email": "johndoe@example.com", + "name": "John Doe" + } +} \ No newline at end of file diff --git a/plugins/redis/unit_test/inputs/keys.json.exp b/plugins/redis/unit_test/inputs/keys.json.exp new file mode 100644 index 0000000000..2df16132b0 --- /dev/null +++ b/plugins/redis/unit_test/inputs/keys.json.exp @@ -0,0 +1,3 @@ +{ + "pattern": "example:*:session" +} \ No newline at end of file diff --git a/plugins/redis/unit_test/inputs/list_get.json.exp b/plugins/redis/unit_test/inputs/list_get.json.exp new file mode 100644 index 0000000000..11c0708da1 --- /dev/null +++ b/plugins/redis/unit_test/inputs/list_get.json.exp @@ -0,0 +1,4 @@ +{ + "key": "user:4567", + "count": 1000 +} \ No newline at end of file diff --git a/plugins/redis/unit_test/inputs/list_push.json.exp b/plugins/redis/unit_test/inputs/list_push.json.exp new file mode 100644 index 0000000000..6594c5936d --- /dev/null +++ b/plugins/redis/unit_test/inputs/list_push.json.exp @@ -0,0 +1,4 @@ +{ + "key": "user:task_list:123", + "value": "Complete monthly report" +} \ No newline at end of file diff --git a/plugins/redis/unit_test/inputs/set.json.exp b/plugins/redis/unit_test/inputs/set.json.exp new file mode 100644 index 0000000000..114dddd421 --- /dev/null +++ b/plugins/redis/unit_test/inputs/set.json.exp @@ -0,0 +1,5 @@ +{ + "key": "example:1234:session", + "expire": 10, + "value": "active" +} \ No newline at end of file diff --git a/plugins/redis/unit_test/keys.py b/plugins/redis/unit_test/keys.py new file mode 100644 index 0000000000..d935878679 --- /dev/null +++ b/plugins/redis/unit_test/keys.py @@ -0,0 +1,29 @@ +import os +import sys + +sys.path.append(os.path.abspath("../")) + +from util import Util +from unittest import TestCase +from unittest.mock import MagicMock, patch +from jsonschema import validate +from komand_redis.actions.keys import Keys + + +class TestKeys(TestCase): + def setUp(self) -> None: + self.action = None + + @patch("redis.StrictRedis", return_value=Util.mock_redis()) + def mocked_connector(mocked_redis: MagicMock) -> None: + self.action = Util.default_connector(Keys()) + + mocked_connector() + + def test_keys(self): + input_param = Util.load_json("inputs/keys.json.exp") + expect = Util.load_json("expected/keys_exp.json.exp") + actual = self.action.run(input_param) + validate(input_param, self.action.input.schema) + self.assertEqual(expect, actual) + validate(actual, self.action.output.schema) diff --git a/plugins/redis/unit_test/list_get.py b/plugins/redis/unit_test/list_get.py new file mode 100644 index 0000000000..d041b3c6ea --- /dev/null +++ b/plugins/redis/unit_test/list_get.py @@ -0,0 +1,29 @@ +import os +import sys + +sys.path.append(os.path.abspath("../")) + +from util import Util +from unittest import TestCase +from unittest.mock import MagicMock, patch +from jsonschema import validate +from komand_redis.actions.list_get import ListGet + + +class TestListGet(TestCase): + def setUp(self) -> None: + self.action = None + + @patch("redis.StrictRedis", return_value=Util.mock_redis()) + def mocked_connector(mocked_redis: MagicMock) -> None: + self.action = Util.default_connector(ListGet()) + + mocked_connector() + + def test_list_get(self): + input_param = Util.load_json("inputs/list_get.json.exp") + expect = Util.load_json("expected/list_get_exp.json.exp") + actual = self.action.run(input_param) + validate(input_param, self.action.input.schema) + self.assertEqual(expect, actual) + validate(actual, self.action.output.schema) diff --git a/plugins/redis/unit_test/list_push.py b/plugins/redis/unit_test/list_push.py new file mode 100644 index 0000000000..fcce9f7b80 --- /dev/null +++ b/plugins/redis/unit_test/list_push.py @@ -0,0 +1,29 @@ +import os +import sys + +sys.path.append(os.path.abspath("../")) + +from util import Util +from unittest import TestCase +from unittest.mock import MagicMock, patch +from jsonschema import validate +from komand_redis.actions.list_push import ListPush + + +class TestListPush(TestCase): + def setUp(self) -> None: + self.action = None + + @patch("redis.StrictRedis", return_value=Util.mock_redis()) + def mocked_connector(mocked_redis: MagicMock) -> None: + self.action = Util.default_connector(ListPush()) + + mocked_connector() + + def test_list_push(self): + input_param = Util.load_json("inputs/list_push.json.exp") + expect = Util.load_json("expected/list_push_exp.json.exp") + actual = self.action.run(input_param) + validate(input_param, self.action.input.schema) + self.assertEqual(expect, actual) + validate(actual, self.action.output.schema) diff --git a/plugins/redis/unit_test/set.py b/plugins/redis/unit_test/set.py new file mode 100644 index 0000000000..bc48fe4363 --- /dev/null +++ b/plugins/redis/unit_test/set.py @@ -0,0 +1,29 @@ +import os +import sys + +sys.path.append(os.path.abspath("../")) + +from util import Util +from unittest import TestCase +from unittest.mock import MagicMock, patch +from jsonschema import validate +from komand_redis.actions.set import Set + + +class TestSet(TestCase): + def setUp(self) -> None: + self.action = None + + @patch("redis.StrictRedis", return_value=Util.mock_redis()) + def mocked_connector(mocked_redis: MagicMock) -> None: + self.action = Util.default_connector(Set()) + + mocked_connector() + + def test_set(self): + input_param = Util.load_json("inputs/set.json.exp") + expect = Util.load_json("expected/set_exp.json.exp") + actual = self.action.run(input_param) + validate(input_param, self.action.input.schema) + self.assertEqual(expect, actual) + validate(actual, self.action.output.schema) diff --git a/plugins/redis/unit_test/util.py b/plugins/redis/unit_test/util.py new file mode 100644 index 0000000000..62191a7d13 --- /dev/null +++ b/plugins/redis/unit_test/util.py @@ -0,0 +1,76 @@ +import json +import logging +import os.path +import sys + +sys.path.append(os.path.abspath("../")) +from komand_redis.connection import Connection +from komand_redis.connection.schema import Input + + +class Util: + @staticmethod + def default_connector(action): + default_connection = Connection() + default_connection.logger = logging.getLogger("connection logger") + params = {"host": "127.0.0.1", "port": 8080, "db": 0} + default_connection.connect(params) + action.connection = default_connection + action.logger = logging.getLogger("action logger") + return action + + @staticmethod + def load_json(filename): + with open((os.path.join(os.path.dirname(os.path.realpath(__file__)), filename))) as file: + return json.loads(file.read()) + + @staticmethod + def mock_redis(): + class MockResponse: + def __init__(self): + pass + + @staticmethod + def delete(key_name: str): + return 10 + + @staticmethod + def hgetall(key_name: str): + return {b"age": b"20", b"email": b"Test@example.com", b"name": b"Test User"} + + @staticmethod + def hmset(key_name: str, key_name2: dict): + # Differentiate between hmset and hash_set action + if key_name == "user:4567": + return True + elif key_name == "user:1234": + return "OK" + + @staticmethod + def hincrby(key_name: str, key_name2: str, key_name3: str): + return 0 + + @staticmethod + def keys(key_name: str): + return {b"count": 2, b"keys": [b"count", b"keys"]} + + @staticmethod + def lrange(key_name: str, key_name2: int, key_name3: int): + return [] + + @staticmethod + def setex(key_name: str, key_name2: str, key_name3: str): + return "OK" + + @staticmethod + def rpush(key_name: str, *values: any): + return "OK" + + @staticmethod + def get(params: str): + if params == "test": + return True + if params == "key": + return "" + + return MockResponse()