diff --git a/test/int/test_dml.py b/test/int/test_dml.py new file mode 100644 index 0000000000000000000000000000000000000000..bf948c5bbfffc1e69020f181ef974e474394bf66 --- /dev/null +++ b/test/int/test_dml.py @@ -0,0 +1,186 @@ +from conftest import Cluster + + +def test_global_space_dml_catchup_by_log(cluster: Cluster): + # Leader + i1 = cluster.add_instance(wait_online=True, replicaset_id="r1") + # For quorum + i2 = cluster.add_instance(wait_online=True, replicaset_id="r1") + # For quorum + i3 = cluster.add_instance(wait_online=True, replicaset_id="r1") + # Catcher-upper replicaset master + i4 = cluster.add_instance(wait_online=True, replicaset_id="r2") + # Catcher-upper replicaset follower + i5 = cluster.add_instance(wait_online=True, replicaset_id="r2") + + index = i1.ddl_create_space( + dict( + id=812, + name="candy", + format=[ + dict(name="id", type="unsigned", is_nullable=False), + dict(name="kind", type="string", is_nullable=False), + dict(name="kilos", type="number", is_nullable=False), + ], + primary_key=[dict(field="id")], + distribution=dict(kind="global"), + ), + ) + i2.raft_wait_index(index, 3) + + # Some dml + index = i1.cas("insert", "candy", [1, "marshmallow", 2.7]) + i1.raft_wait_index(index, 3) + index = i1.cas("insert", "candy", [2, "milk chocolate", 6.9]) + i1.raft_wait_index(index, 3) + i2.raft_wait_index(index, 3) + i3.raft_wait_index(index, 3) + i4.raft_wait_index(index, 3) + i5.raft_wait_index(index, 3) + + # Dml applied ok + expected_tuples = [ + [1, "marshmallow", 2.7], + [2, "milk chocolate", 6.9], + ] + assert i1.call("box.space.candy:select") == expected_tuples + assert i2.call("box.space.candy:select") == expected_tuples + assert i3.call("box.space.candy:select") == expected_tuples + assert i4.call("box.space.candy:select") == expected_tuples + assert i5.call("box.space.candy:select") == expected_tuples + + # These will be catching up + i4.terminate() + i5.terminate() + + # More DML + index = i1.cas("replace", "candy", [2, "dark chocolate", 13.37]) + i1.raft_wait_index(index, 3) + index = i1.cas("delete", "candy", [1]) + i1.raft_wait_index(index, 3) + index = i1.cas("insert", "candy", [3, "ice cream", 0.3]) + i1.raft_wait_index(index, 3) + i2.raft_wait_index(index, 3) + i3.raft_wait_index(index, 3) + + # Dml applied ok again + expected_tuples = [ + [2, "dark chocolate", 13.37], + [3, "ice cream", 0.3], + ] + assert i1.call("box.space.candy:select") == expected_tuples + assert i2.call("box.space.candy:select") == expected_tuples + assert i3.call("box.space.candy:select") == expected_tuples + + # Master catch up by log + i4.start() + i4.wait_online() + assert i4.call("box.space.candy:select") == expected_tuples + + # Follower catch up by log + i5.start() + i5.wait_online() + assert i5.call("box.space.candy:select") == expected_tuples + + # Master boot by log + i6 = cluster.add_instance(wait_online=True, replicaset_id="r3") + assert i6.call("box.space.candy:select") == expected_tuples + + # Follower boot by log + i7 = cluster.add_instance(wait_online=True, replicaset_id="r3") + assert i7.call("box.space.candy:select") == expected_tuples + + +def test_global_space_dml_catchup_by_snapshot(cluster: Cluster): + # Leader + i1 = cluster.add_instance(wait_online=True, replicaset_id="r1") + # For quorum + i2 = cluster.add_instance(wait_online=True, replicaset_id="r1") + # For quorum + i3 = cluster.add_instance(wait_online=True, replicaset_id="r1") + # Catcher-upper replicaset master + i4 = cluster.add_instance(wait_online=True, replicaset_id="r2") + # Catcher-upper replicaset follower + i5 = cluster.add_instance(wait_online=True, replicaset_id="r2") + + index = i1.ddl_create_space( + dict( + id=812, + name="candy", + format=[ + dict(name="id", type="unsigned", is_nullable=False), + dict(name="kind", type="string", is_nullable=False), + dict(name="kilos", type="number", is_nullable=False), + ], + primary_key=[dict(field="id")], + distribution=dict(kind="global"), + ), + ) + i2.raft_wait_index(index, 3) + + # Some dml + index = i1.cas("insert", "candy", [1, "marshmallow", 2.7]) + i1.raft_wait_index(index, 3) + index = i1.cas("insert", "candy", [2, "milk chocolate", 6.9]) + i1.raft_wait_index(index, 3) + i2.raft_wait_index(index, 3) + i3.raft_wait_index(index, 3) + i4.raft_wait_index(index, 3) + i5.raft_wait_index(index, 3) + + # Dml applied ok + expected_tuples = [ + [1, "marshmallow", 2.7], + [2, "milk chocolate", 6.9], + ] + assert i1.call("box.space.candy:select") == expected_tuples + assert i2.call("box.space.candy:select") == expected_tuples + assert i3.call("box.space.candy:select") == expected_tuples + assert i4.call("box.space.candy:select") == expected_tuples + assert i5.call("box.space.candy:select") == expected_tuples + + # These will be catching up + i4.terminate() + i5.terminate() + + # More DML + index = i1.cas("replace", "candy", [2, "dark chocolate", 13.37]) + i1.raft_wait_index(index, 3) + index = i1.cas("delete", "candy", [1]) + i1.raft_wait_index(index, 3) + index = i1.cas("insert", "candy", [3, "ice cream", 0.3]) + i1.raft_wait_index(index, 3) + i2.raft_wait_index(index, 3) + i3.raft_wait_index(index, 3) + + # Dml applied ok again + expected_tuples = [ + [2, "dark chocolate", 13.37], + [3, "ice cream", 0.3], + ] + assert i1.call("box.space.candy:select") == expected_tuples + assert i2.call("box.space.candy:select") == expected_tuples + assert i3.call("box.space.candy:select") == expected_tuples + + # Compact raft log to trigger snapshot generation + i1.raft_compact_log() + i2.raft_compact_log() + i3.raft_compact_log() + + # Master catch up by snapshot + i4.start() + i4.wait_online() + assert i4.call("box.space.candy:select") == expected_tuples + + # Follower catch up by snapshot + i5.start() + i5.wait_online() + assert i5.call("box.space.candy:select") == expected_tuples + + # Master boot by snapshot + i6 = cluster.add_instance(wait_online=True, replicaset_id="r3") + assert i6.call("box.space.candy:select") == expected_tuples + + # Follower boot by snapshot + i7 = cluster.add_instance(wait_online=True, replicaset_id="r3") + assert i7.call("box.space.candy:select") == expected_tuples