Skip to content

Commit

Permalink
Adapt to redis 3.*
Browse files Browse the repository at this point in the history
Co-authored-By: Markus Gärtner <[email protected]>
  • Loading branch information
em92 and mgaertne committed Aug 10, 2024
1 parent 0341ece commit 9e6b63c
Show file tree
Hide file tree
Showing 4 changed files with 214 additions and 1 deletion.
23 changes: 23 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Test

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:

strategy:
matrix:
redis-version: ["2.*", "3.*", "4.*", "5.*"]
os: ["ubuntu-24.04", "ubuntu-22.04", "ubuntu-20.04"]

runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- name: Install redis package
run: sudo python3 -m pip install redis==${{ matrix.redis-version }}
- name: Run test
run: python3 -m unittest discover python/tests/
54 changes: 53 additions & 1 deletion python/minqlx/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
# You should have received a copy of the GNU General Public License
# along with minqlx. If not, see <http://www.gnu.org/licenses/>.

import minqlx
try:
import minqlx
except ImportError:
pass

import redis

# ====================================================================
Expand Down Expand Up @@ -313,3 +317,51 @@ def close(self):
if Redis._pool:
Redis._pool.disconnect()
Redis._pool = None

if redis.VERSION > (3,):
def lrem(self, name, value, count):
return self.r.lrem(name, count, value)

def setex(self, name, value, time):
return self.r.setex(name, time, value)

def zincrby(self, name, value, amount=1):
return self.r.zincrby(name, amount, value)

def zadd(self, name, *args, **kwargs):
if len(args) == 1 and isinstance(args[0], dict):
# redis >= 3.* arguments given
return self.r.zadd(name, *args, **kwargs)

if len(args) > 0 and len(args) % 2 != 0:
raise redis.RedisError("ZADD requires an equal number of values and scores")

mapping = {}
for i in range(0, len(args), 2):
mapping[args[i + 1]] = args[i]

return self.r.zadd(name, mapping, **kwargs)

def msetnx(self, *args, **kwargs):
mapping = {}
if args:
if len(args) != 1 or not isinstance(args[0], dict):
raise redis.RedisError("MSETNX requires **kwargs or a single dict arg")
mapping.update(args[0])

if kwargs:
mapping.update(kwargs)

return self.r.msetnx(mapping)

def mset(self, *args, **kwargs):
mapping = {}
if args:
if len(args) != 1 or not isinstance(args[0], dict):
raise redis.RedisError("MSET requires **kwargs or a single dict arg")
mapping.update(args[0])

if kwargs:
mapping.update(kwargs)

return self.r.mset(mapping)
1 change: 1 addition & 0 deletions python/tests/database.py
137 changes: 137 additions & 0 deletions python/tests/test_database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
from unittest import TestCase
import database
import random
import string
from time import sleep


def random_string():
return "".join([random.choice(string.ascii_letters) for x in range(10)])


class RedisRegressionTestCase(TestCase):
def setUp(self):
self.c = database.Redis(None)
self.c.connect("127.0.0.1:6379")

def test_zadd_01(self):
c = self.c
key = "zadd_01_key_" + random_string()

c.zadd(key, 5, "player1", 6, "player2")
res = dict(c.zrange(key, 0, -1, withscores=True))
self.assertEqual(res["player1"], 5)
self.assertEqual(res["player2"], 6)

c.zadd(key, 2, "player1")
res = dict(c.zrange(key, 0, -1, withscores=True))
self.assertEqual(res["player1"], 2)
self.assertEqual(res["player2"], 6)

c.zadd(key, 3, "player1", xx=True)
res = dict(c.zrange(key, 0, -1, withscores=True))
self.assertEqual(res["player1"], 3)

c.zadd(key, 3, "player_does_not_exist", xx=True)
res = dict(c.zrange(key, 0, -1, withscores=True))
self.assertNotIn("player_does_not_exist", res)

def test_zincrby_01(self):
key = "zincrby_01_key_" + random_string()
c = self.c

c.zincrby(key, "FIELD1")
c.zincrby(key, "FIELD2", 2)
res = dict(c.zrange(key, 0, -1, withscores=True))
self.assertEqual(res["FIELD1"], 1)
self.assertEqual(res["FIELD2"], 2)

c.zincrby(key, "FIELD1")
c.zincrby(key, "FIELD2", 3)
res = dict(c.zrange(key, 0, -1, withscores=True))
self.assertEqual(res["FIELD1"], 2)
self.assertEqual(res["FIELD2"], 5)

def test_lrem_01(self):
key = "lrem_01_key_" + random_string()
c = self.c

c.rpush(
key,
"Cat",
"Dog",
"Horse",
"Cat",
"Dog",
"Cat",
"Monkey",
"Dog",
"Cat",
"Dog",
"Buffalo",
)
c.lrem(key, "Cat", 2)
result = c.lrange(key, 0, -1)
self.assertEqual(
result,
["Dog", "Horse", "Dog", "Cat", "Monkey", "Dog", "Cat", "Dog", "Buffalo"],
)

def test_setex_01(self):
key = "setex_01_key_" + random_string()
c = self.c
test_value = "test value"
timeout = 1

c.setex(key, test_value, timeout)
self.assertEqual(c.get(key), test_value, "Too small timeout value?")
sleep(timeout + 0.5)
self.assertEqual(c.get(key), None)

def test_mset_01(self):
c = self.c
c.mset(field1="example1", field2="example2")
self.assertEqual(["example1", "example2"], c.mget("field1", "field2"))

def test_mset_02(self):
c = self.c
c.mset({"field3": "example1", "field4": "example2"})
self.assertEqual(["example1", "example2"], c.mget("field3", "field4"))

def test_msetnx_01_kwargs(self):
c = self.c
prefix = "msetnx_01_key_" + random_string()
key1 = prefix + "_field1"
key2 = prefix + "_field2"
d = {
key1: "example1",
key2: "example2",
}
c.msetnx(**d)
self.assertEqual(["example1", "example2"], c.mget(key1, key2))

d = {
key1: "value should not be used",
key2: "same here",
}
c.msetnx(**d)
self.assertEqual(["example1", "example2"], c.mget(key1, key2))

def test_msetnx_02_dict(self):
c = self.c
prefix = "msetnx_02_key_" + random_string()
key1 = prefix + "_field1"
key2 = prefix + "_field2"
d = {
key1: "example1",
key2: "example2",
}
c.msetnx(d)
self.assertEqual(["example1", "example2"], c.mget(key1, key2))

d = {
key1: "value should not be used",
key2: "same here",
}
c.msetnx(d)
self.assertEqual(["example1", "example2"], c.mget(key1, key2))

0 comments on commit 9e6b63c

Please sign in to comment.