1
0
Fork 0
mirror of https://github.com/dragonflydb/dragonfly.git synced 2024-12-14 11:58:02 +00:00
dragonflydb-dragonfly/tests/dragonfly/cluster_mgr_test.py
Kostas Kyrimis b19f722011
chore: do not close connections at the end of pytest (#3811)
A common case is that we need to clean up a connection before we exit a test via .close() method. This is needed because otherwise the connection will raise a warning that it is left unclosed. However, remembering to call .close() at each connection at the end of the test is cumbersome! Luckily, fixtures in python can be marked as async which allow us to:

* cache all clients created by DflyInstance.client()
* clean them all at the end of the fixture in one go

---------

Signed-off-by: kostas <kostas@dragonflydb.io>
2024-09-30 09:54:41 +03:00

164 lines
5.5 KiB
Python

import subprocess
import pytest
import redis
from redis import asyncio as aioredis
from .utility import *
from . import dfly_args
BASE_PORT = 30001
async def insert_cluster_data(cluster_client: redis.RedisCluster):
for i in range(1_000):
await cluster_client.set(i, i)
async def check_cluster_data(cluster_client: redis.RedisCluster):
for i in range(1_000):
assert await cluster_client.get(i) == str(i)
def run_cluster_mgr(args):
print(f"Running cluster_mgr.py {args}")
result = subprocess.run(["../tools/cluster_mgr.py", *args])
return result.returncode == 0
@dfly_args({"proactor_threads": 2, "cluster_mode": "yes"})
async def test_cluster_mgr(df_factory):
NODES = 3
masters = [df_factory.create(port=BASE_PORT + i) for i in range(NODES)]
replicas = [df_factory.create(port=BASE_PORT + 100 + i) for i in range(NODES)]
df_factory.start_all([*masters, *replicas])
# Initialize a cluster (all slots belong to node 0)
assert run_cluster_mgr(["--action=config_single_remote", f"--target_port={BASE_PORT}"])
for i in range(1, NODES):
assert run_cluster_mgr(
["--action=attach", f"--target_port={BASE_PORT}", f"--attach_port={BASE_PORT+i}"]
)
# Feed the cluster with data and test that it works correctly
client = aioredis.RedisCluster(decode_responses=True, host="127.0.0.1", port=masters[0].port)
await insert_cluster_data(client)
await check_cluster_data(client)
# Migrate ~half of the slots to node 1
assert run_cluster_mgr(
[
f"--action=migrate",
f"--target_port={BASE_PORT + 1}",
f"--slot_start=8000",
f"--slot_end=16383",
]
)
await check_cluster_data(client)
# Can only detach node 2 (with no assigned slots)
assert not run_cluster_mgr(["--action=detach", f"--target_port={BASE_PORT}"])
assert not run_cluster_mgr(["--action=detach", f"--target_port={BASE_PORT + 1}"])
assert run_cluster_mgr(["--action=detach", f"--target_port={BASE_PORT + 2}"])
await check_cluster_data(client)
# Can't attach non-replica as replica
assert not run_cluster_mgr(
[
f"--action=attach",
f"--target_port={BASE_PORT}",
f"--attach_port={BASE_PORT+2}",
f"--attach_as_replica=True",
]
)
# Reattach node 2 and migrate some slots to it
assert run_cluster_mgr(
["--action=attach", f"--target_port={BASE_PORT}", f"--attach_port={BASE_PORT+2}"]
)
await check_cluster_data(client)
# Slots 7000-8000 belong to node0, while 8001-9000 belong to node1. cluster_mgr doesn't support
# such a migration in a single command.
assert not run_cluster_mgr(
[
f"--action=migrate",
f"--target_port={BASE_PORT + 1}",
f"--slot_start=7000",
f"--slot_end=9000",
]
)
assert run_cluster_mgr(
["--action=migrate", f"--target_port={BASE_PORT + 2}", "--slot_start=0", "--slot_end=2000"]
)
await check_cluster_data(client)
assert run_cluster_mgr(
[
f"--action=migrate",
f"--target_port={BASE_PORT + 2}",
f"--slot_start=8000",
f"--slot_end=10000",
]
)
await check_cluster_data(client)
# Can't attach replica before running REPLICAOF
assert not run_cluster_mgr(
[
f"--action=attach",
f"--attach_as_replica=True",
f"--target_port={BASE_PORT}",
f"--attach_port={replicas[0].port}",
]
)
# Add replicas
replica_clients = [replica.client() for replica in replicas]
for i in range(NODES):
await replica_clients[i].execute_command(f"replicaof localhost {masters[i].port}")
assert run_cluster_mgr(
[
f"--action=attach",
f"--attach_as_replica=True",
f"--target_port={masters[i].port}",
f"--attach_port={replicas[i].port}",
]
)
# Can't take over when target is a master
assert not run_cluster_mgr(["--action=takeover", f"--target_port={masters[i].port}"])
# Take over replica 0
assert run_cluster_mgr(["--action=takeover", f"--target_port={replicas[0].port}"])
await replica_clients[0].execute_command("replicaof no one")
await check_cluster_data(client)
# Revert take over
c_master0 = masters[0].client()
await c_master0.execute_command(f"replicaof localhost {replicas[0].port}")
assert run_cluster_mgr(
[
f"--action=attach",
f"--attach_as_replica=True",
f"--target_port={replicas[0].port}",
f"--attach_port={masters[0].port}",
]
)
assert run_cluster_mgr(["--action=takeover", f"--target_port={masters[0].port}"])
await c_master0.execute_command(f"replicaof no one")
await replica_clients[0].execute_command(f"replicaof localhost {masters[0].port}")
assert run_cluster_mgr(
[
f"--action=attach",
f"--attach_as_replica=True",
f"--target_port={masters[0].port}",
f"--attach_port={replicas[0].port}",
]
)
await check_cluster_data(client)
# Print the config - we don't really verify the output, but at least make sure there's no error
assert run_cluster_mgr(["--action=print_config", f"--target_port={replicas[0].port}"])
# Test detach replicas work
for i in range(NODES):
assert run_cluster_mgr(["--action=detach", f"--target_port={replicas[i].port}"])
await check_cluster_data(client)
await client.close()