2023-02-14 11:19:33 +00:00
|
|
|
import os
|
|
|
|
import pytest
|
2023-05-13 07:44:25 +00:00
|
|
|
import redis
|
2023-06-18 18:14:28 +00:00
|
|
|
import asyncio
|
2023-05-13 07:44:25 +00:00
|
|
|
from redis import asyncio as aioredis
|
|
|
|
|
2023-09-28 07:11:11 +00:00
|
|
|
from . import dfly_multi_test_args, dfly_args
|
|
|
|
from .instance import DflyStartException
|
2023-09-18 07:23:49 +00:00
|
|
|
from .utility import batch_fill_data, gen_test_data, EnvironCntx
|
2022-10-31 14:39:20 +00:00
|
|
|
|
|
|
|
|
2023-07-17 10:13:12 +00:00
|
|
|
@dfly_multi_test_args({"keys_output_limit": 512}, {"keys_output_limit": 1024})
|
2022-10-31 14:39:20 +00:00
|
|
|
class TestKeys:
|
2023-03-24 15:22:14 +00:00
|
|
|
async def test_max_keys(self, async_client: aioredis.Redis, df_server):
|
2023-07-17 10:13:12 +00:00
|
|
|
max_keys = df_server["keys_output_limit"]
|
2023-03-24 15:22:14 +00:00
|
|
|
pipe = async_client.pipeline()
|
|
|
|
batch_fill_data(pipe, gen_test_data(max_keys * 3))
|
|
|
|
await pipe.execute()
|
|
|
|
keys = await async_client.keys()
|
2023-07-17 10:13:12 +00:00
|
|
|
assert len(keys) in range(max_keys, max_keys + 512)
|
|
|
|
|
2023-02-14 11:19:33 +00:00
|
|
|
|
|
|
|
@pytest.fixture(scope="function")
|
|
|
|
def export_dfly_password() -> str:
|
2023-07-17 10:13:12 +00:00
|
|
|
pwd = "flypwd"
|
2023-09-18 07:23:49 +00:00
|
|
|
with EnvironCntx(DFLY_PASSWORD=pwd):
|
|
|
|
yield pwd
|
2023-07-17 10:13:12 +00:00
|
|
|
|
2023-02-14 11:19:33 +00:00
|
|
|
|
|
|
|
async def test_password(df_local_factory, export_dfly_password):
|
2023-09-18 10:52:56 +00:00
|
|
|
with df_local_factory.create() as dfly:
|
|
|
|
# Expect password form environment variable
|
|
|
|
with pytest.raises(redis.exceptions.AuthenticationError):
|
|
|
|
async with aioredis.Redis(port=dfly.port) as client:
|
|
|
|
await client.ping()
|
|
|
|
async with aioredis.Redis(password=export_dfly_password, port=dfly.port) as client:
|
2023-09-18 07:23:49 +00:00
|
|
|
await client.ping()
|
2023-02-14 11:19:33 +00:00
|
|
|
|
|
|
|
# --requirepass should take precedence over environment variable
|
2023-07-17 10:13:12 +00:00
|
|
|
requirepass = "requirepass"
|
2023-09-18 10:52:56 +00:00
|
|
|
with df_local_factory.create(requirepass=requirepass) as dfly:
|
|
|
|
# Expect password form flag
|
|
|
|
with pytest.raises(redis.exceptions.AuthenticationError):
|
|
|
|
async with aioredis.Redis(port=dfly.port, password=export_dfly_password) as client:
|
|
|
|
await client.ping()
|
|
|
|
async with aioredis.Redis(password=requirepass, port=dfly.port) as client:
|
2023-09-18 07:23:49 +00:00
|
|
|
await client.ping()
|
2023-06-18 18:14:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
Make sure that multi-hop transactions can't run OOO.
|
|
|
|
"""
|
|
|
|
|
|
|
|
MULTI_HOPS = """
|
|
|
|
for i = 0, ARGV[1] do
|
|
|
|
redis.call('INCR', KEYS[1])
|
|
|
|
end
|
|
|
|
"""
|
|
|
|
|
2023-07-17 10:13:12 +00:00
|
|
|
|
2023-06-18 18:14:28 +00:00
|
|
|
@dfly_args({"proactor_threads": 1})
|
|
|
|
async def test_txq_ooo(async_client: aioredis.Redis, df_server):
|
|
|
|
async def task1(k, h):
|
|
|
|
c = aioredis.Redis(port=df_server.port)
|
|
|
|
for _ in range(100):
|
|
|
|
await c.eval(MULTI_HOPS, 1, k, h)
|
|
|
|
|
|
|
|
async def task2(k, n):
|
|
|
|
c = aioredis.Redis(port=df_server.port)
|
|
|
|
for _ in range(100):
|
|
|
|
pipe = c.pipeline(transaction=False)
|
|
|
|
pipe.lpush(k, 1)
|
|
|
|
for _ in range(n):
|
|
|
|
pipe.blpop(k, 0.001)
|
|
|
|
await pipe.execute()
|
|
|
|
|
2023-07-17 10:13:12 +00:00
|
|
|
await asyncio.gather(
|
|
|
|
task1("i1", 2), task1("i2", 3), task2("l1", 2), task2("l1", 2), task2("l1", 5)
|
|
|
|
)
|
2023-09-13 10:02:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_arg_from_environ_overwritten_by_cli(df_local_factory):
|
2023-09-18 07:23:49 +00:00
|
|
|
with EnvironCntx(DFLY_port="6378"):
|
2023-09-18 10:52:56 +00:00
|
|
|
with df_local_factory.create(port=6377):
|
|
|
|
client = aioredis.Redis(port=6377)
|
|
|
|
await client.ping()
|
2023-09-13 10:02:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_arg_from_environ(df_local_factory):
|
2023-09-18 07:23:49 +00:00
|
|
|
with EnvironCntx(DFLY_requirepass="pass"):
|
2023-09-18 10:52:56 +00:00
|
|
|
with df_local_factory.create() as dfly:
|
|
|
|
# Expect password from environment variable
|
|
|
|
with pytest.raises(redis.exceptions.AuthenticationError):
|
|
|
|
client = aioredis.Redis(port=dfly.port)
|
|
|
|
await client.ping()
|
2023-09-13 10:02:38 +00:00
|
|
|
|
2023-09-18 10:52:56 +00:00
|
|
|
client = aioredis.Redis(password="pass", port=dfly.port)
|
2023-09-18 07:23:49 +00:00
|
|
|
await client.ping()
|
2023-09-13 10:02:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_unknown_dfly_env(df_local_factory, export_dfly_password):
|
2023-09-18 07:23:49 +00:00
|
|
|
with EnvironCntx(DFLY_abcdef="xyz"):
|
|
|
|
with pytest.raises(DflyStartException):
|
|
|
|
dfly = df_local_factory.create()
|
|
|
|
dfly.start()
|
2023-09-29 15:16:06 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_restricted_commands(df_local_factory):
|
|
|
|
# Restrict GET and SET, then verify non-admin clients are blocked from
|
|
|
|
# using these commands, though admin clients can use them.
|
|
|
|
with df_local_factory.create(restricted_commands="get,set", admin_port=1112) as server:
|
|
|
|
async with aioredis.Redis(port=server.port) as client:
|
|
|
|
with pytest.raises(redis.exceptions.ResponseError):
|
|
|
|
await client.get("foo")
|
|
|
|
|
|
|
|
with pytest.raises(redis.exceptions.ResponseError):
|
|
|
|
await client.set("foo", "bar")
|
|
|
|
|
|
|
|
async with aioredis.Redis(port=server.admin_port) as admin_client:
|
|
|
|
await admin_client.get("foo")
|
|
|
|
await admin_client.set("foo", "bar")
|