Fix SHOW REPLICATION ROLE and SHOW REPLICAS (#376)
This commit is contained in:
parent
8e3ab1ad0f
commit
21ad5d4328
@ -450,7 +450,7 @@ Callback HandleReplicationQuery(ReplicationQuery *repl_query, const Parameters &
|
|||||||
return callback;
|
return callback;
|
||||||
}
|
}
|
||||||
case ReplicationQuery::Action::SHOW_REPLICATION_ROLE: {
|
case ReplicationQuery::Action::SHOW_REPLICATION_ROLE: {
|
||||||
callback.header = {"replication mode"};
|
callback.header = {"replication role"};
|
||||||
callback.fn = [handler = ReplQueryHandler{interpreter_context->db}] {
|
callback.fn = [handler = ReplQueryHandler{interpreter_context->db}] {
|
||||||
auto mode = handler.ShowReplicationRole();
|
auto mode = handler.ShowReplicationRole();
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
@ -516,7 +516,6 @@ Callback HandleReplicationQuery(ReplicationQuery *repl_query, const Parameters &
|
|||||||
typed_replica.emplace_back(TypedValue("async"));
|
typed_replica.emplace_back(TypedValue("async"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
typed_replica.emplace_back(TypedValue(static_cast<int64_t>(replica.sync_mode)));
|
|
||||||
if (replica.timeout) {
|
if (replica.timeout) {
|
||||||
typed_replica.emplace_back(TypedValue(*replica.timeout));
|
typed_replica.emplace_back(TypedValue(*replica.timeout));
|
||||||
} else {
|
} else {
|
||||||
|
@ -5,3 +5,7 @@ target_link_libraries(memgraph__e2e__replication__constraints gflags mgclient mg
|
|||||||
|
|
||||||
add_executable(memgraph__e2e__replication__read_write_benchmark read_write_benchmark.cpp)
|
add_executable(memgraph__e2e__replication__read_write_benchmark read_write_benchmark.cpp)
|
||||||
target_link_libraries(memgraph__e2e__replication__read_write_benchmark gflags json mgclient mg-utils mg-io Threads::Threads)
|
target_link_libraries(memgraph__e2e__replication__read_write_benchmark gflags json mgclient mg-utils mg-io Threads::Threads)
|
||||||
|
|
||||||
|
copy_e2e_python_files(replication_show common.py)
|
||||||
|
copy_e2e_python_files(replication_show conftest.py)
|
||||||
|
copy_e2e_python_files(replication_show show.py)
|
||||||
|
26
tests/e2e/replication/common.py
Normal file
26
tests/e2e/replication/common.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# Copyright 2022 Memgraph Ltd.
|
||||||
|
#
|
||||||
|
# Use of this software is governed by the Business Source License
|
||||||
|
# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
|
# License, and you may not use this file except in compliance with the Business Source License.
|
||||||
|
#
|
||||||
|
# As of the Change Date specified in that file, in accordance with
|
||||||
|
# the Business Source License, use of this software will be governed
|
||||||
|
# by the Apache License, Version 2.0, included in the file
|
||||||
|
# licenses/APL.txt.
|
||||||
|
|
||||||
|
import mgclient
|
||||||
|
import typing
|
||||||
|
|
||||||
|
|
||||||
|
def execute_and_fetch_all(
|
||||||
|
cursor: mgclient.Cursor, query: str, params: dict = {}
|
||||||
|
) -> typing.List[tuple]:
|
||||||
|
cursor.execute(query, params)
|
||||||
|
return cursor.fetchall()
|
||||||
|
|
||||||
|
|
||||||
|
def connect(**kwargs) -> mgclient.Connection:
|
||||||
|
connection = mgclient.connect(**kwargs)
|
||||||
|
connection.autocommit = True
|
||||||
|
return connection
|
44
tests/e2e/replication/conftest.py
Normal file
44
tests/e2e/replication/conftest.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# Copyright 2022 Memgraph Ltd.
|
||||||
|
#
|
||||||
|
# Use of this software is governed by the Business Source License
|
||||||
|
# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
|
# License, and you may not use this file except in compliance with the Business Source License.
|
||||||
|
#
|
||||||
|
# As of the Change Date specified in that file, in accordance with
|
||||||
|
# the Business Source License, use of this software will be governed
|
||||||
|
# by the Apache License, Version 2.0, included in the file
|
||||||
|
# licenses/APL.txt.
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from common import execute_and_fetch_all, connect
|
||||||
|
|
||||||
|
|
||||||
|
# The fixture here is more complex because the connection has to be
|
||||||
|
# parameterized based on the test parameters (info has to be available on both
|
||||||
|
# sides).
|
||||||
|
#
|
||||||
|
# https://docs.pytest.org/en/latest/example/parametrize.html#indirect-parametrization
|
||||||
|
# is not an elegant/feasible solution here.
|
||||||
|
#
|
||||||
|
# The solution was independently developed and then I stumbled upon the same
|
||||||
|
# approach here https://stackoverflow.com/a/68286553/4888809 which I think is
|
||||||
|
# optimal.
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def connection():
|
||||||
|
connection_holder = None
|
||||||
|
role_holder = None
|
||||||
|
|
||||||
|
def inner_connection(port, role):
|
||||||
|
nonlocal connection_holder, role_holder
|
||||||
|
connection_holder = connect(host="localhost", port=port)
|
||||||
|
role_holder = role
|
||||||
|
return connection_holder
|
||||||
|
|
||||||
|
yield inner_connection
|
||||||
|
|
||||||
|
# Only main instance can be cleaned up because replicas do NOT accept
|
||||||
|
# writes.
|
||||||
|
if role_holder == "main":
|
||||||
|
cursor = connection_holder.cursor()
|
||||||
|
execute_and_fetch_all(cursor, "MATCH (n) DETACH DELETE n;")
|
46
tests/e2e/replication/show.py
Executable file
46
tests/e2e/replication/show.py
Executable file
@ -0,0 +1,46 @@
|
|||||||
|
# Copyright 2022 Memgraph Ltd.
|
||||||
|
#
|
||||||
|
# Use of this software is governed by the Business Source License
|
||||||
|
# included in the file licenses/BSL.txt; by using this file, you agree to be bound by the terms of the Business Source
|
||||||
|
# License, and you may not use this file except in compliance with the Business Source License.
|
||||||
|
#
|
||||||
|
# As of the Change Date specified in that file, in accordance with
|
||||||
|
# the Business Source License, use of this software will be governed
|
||||||
|
# by the Apache License, Version 2.0, included in the file
|
||||||
|
# licenses/APL.txt.
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from common import execute_and_fetch_all
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"port, role",
|
||||||
|
[(7687, "main"), (7688, "replica"), (7689, "replica"), (7690, "replica")],
|
||||||
|
)
|
||||||
|
def test_show_replication_role(port, role, connection):
|
||||||
|
cursor = connection(port, role).cursor()
|
||||||
|
data = execute_and_fetch_all(cursor, "SHOW REPLICATION ROLE;")
|
||||||
|
assert cursor.description[0].name == "replication role"
|
||||||
|
assert data[0][0] == role
|
||||||
|
|
||||||
|
|
||||||
|
def test_show_replicas(connection):
|
||||||
|
cursor = connection(7687, "main").cursor()
|
||||||
|
actual_data = set(execute_and_fetch_all(cursor, "SHOW REPLICAS;"))
|
||||||
|
|
||||||
|
expected_column_names = {"name", "socket_address", "sync_mode", "timeout"}
|
||||||
|
actual_column_names = {x.name for x in cursor.description}
|
||||||
|
assert expected_column_names == actual_column_names
|
||||||
|
|
||||||
|
expected_data = {
|
||||||
|
("replica_1", "127.0.0.1:10001", "sync", 0),
|
||||||
|
("replica_2", "127.0.0.1:10002", "sync", 1.0),
|
||||||
|
("replica_3", "127.0.0.1:10003", "async", None),
|
||||||
|
}
|
||||||
|
assert expected_data == actual_data
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(pytest.main([__file__, "-rA"]))
|
@ -46,4 +46,31 @@ workloads:
|
|||||||
args: []
|
args: []
|
||||||
<<: *template_cluster
|
<<: *template_cluster
|
||||||
|
|
||||||
|
- name: "Show"
|
||||||
|
binary: "tests/e2e/pytest_runner.sh"
|
||||||
|
args: ["replication/show.py"]
|
||||||
|
cluster:
|
||||||
|
replica_1:
|
||||||
|
args: ["--bolt-port", "7688", "--log-level=TRACE"]
|
||||||
|
log_file: "replication-e2e-replica1.log"
|
||||||
|
setup_queries: ["SET REPLICATION ROLE TO REPLICA WITH PORT 10001;"]
|
||||||
|
validation_queries: []
|
||||||
|
replica_2:
|
||||||
|
args: ["--bolt-port", "7689", "--log-level=TRACE"]
|
||||||
|
log_file: "replication-e2e-replica2.log"
|
||||||
|
setup_queries: ["SET REPLICATION ROLE TO REPLICA WITH PORT 10002;"]
|
||||||
|
validation_queries: []
|
||||||
|
replica_3:
|
||||||
|
args: ["--bolt-port", "7690", "--log-level=TRACE"]
|
||||||
|
log_file: "replication-e2e-replica3.log"
|
||||||
|
setup_queries: ["SET REPLICATION ROLE TO REPLICA WITH PORT 10003;"]
|
||||||
|
validation_queries: []
|
||||||
|
main:
|
||||||
|
args: ["--bolt-port", "7687", "--log-level=TRACE"]
|
||||||
|
log_file: "replication-e2e-main.log"
|
||||||
|
setup_queries: [
|
||||||
|
"REGISTER REPLICA replica_1 SYNC WITH TIMEOUT 0 TO '127.0.0.1:10001'",
|
||||||
|
"REGISTER REPLICA replica_2 SYNC WITH TIMEOUT 1 TO '127.0.0.1:10002'",
|
||||||
|
"REGISTER REPLICA replica_3 ASYNC TO '127.0.0.1:10003'"
|
||||||
|
]
|
||||||
|
validation_queries: []
|
||||||
|
Loading…
Reference in New Issue
Block a user