Skip to content

Commit 87a79eb

Browse files
committed
MB-67082: Add online eviction policy test cases
Add eviction policy only test cases to BucketMigrationTest Change-Id: I0b2842cbc92e321cbd7ec8433b1c2b64ae265a1c Reviewed-on: https://review.couchbase.org/c/ns_server/+/230213 Well-Formed: Build Bot <[email protected]> Well-Formed: Restriction Checker Tested-by: Neelima Premsankar <[email protected]> Reviewed-by: Steve Watanabe <[email protected]>
1 parent cd996f3 commit 87a79eb

File tree

1 file changed

+228
-26
lines changed

1 file changed

+228
-26
lines changed

cluster_tests/testsets/bucket_migration_test.py

Lines changed: 228 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -207,22 +207,20 @@ def is_node_ejected():
207207
f"ejected node: {ejected_otp_node}"
208208

209209

210-
def assert_per_node_storage_mode_in_memcached(
211-
node, bucket_name, expected_storage_mode
212-
):
213-
storage_mode = (
214-
testlib.diag_eval(
215-
node,
216-
f'ns_memcached:get_config_stats("{bucket_name}", <<"ep_backend">>).',
217-
)
218-
.content.decode("ascii")
219-
.strip('<<"')
220-
.strip('">>')
221-
)
210+
def wait_for_bucket_online_on_all_nodes(cluster, bucket_name):
211+
"""Wait for bucket to be online on all nodes in the cluster"""
222212

223-
if expected_storage_mode == "couchstore":
224-
expected_storage_mode = "couchdb"
225-
assert storage_mode == expected_storage_mode
213+
def is_bucket_online_on_all_nodes():
214+
r = get_bucket(cluster, bucket_name)
215+
return all([node["status"] == "healthy" for node in r["nodes"]])
216+
217+
testlib.poll_for_condition(
218+
is_bucket_online_on_all_nodes,
219+
sleep_time=0.5,
220+
attempts=20,
221+
timeout=60,
222+
msg=f"waiting for bucket {bucket_name} to be online on all nodes",
223+
)
226224

227225

228226
def assert_per_node_eviction_policy_in_memcached(
@@ -251,6 +249,24 @@ def assert_per_node_eviction_policy_in_memcached(
251249
assert eviction_policy == expected_eviction_policy
252250

253251

252+
def assert_per_node_storage_mode_in_memcached(
253+
node, bucket_name, expected_storage_mode
254+
):
255+
storage_mode = (
256+
testlib.diag_eval(
257+
node,
258+
f'ns_memcached:get_config_stats("{bucket_name}", <<"ep_backend">>).',
259+
)
260+
.content.decode("ascii")
261+
.strip('<<"')
262+
.strip('">>')
263+
)
264+
265+
if expected_storage_mode == "couchstore":
266+
expected_storage_mode = "couchdb"
267+
assert storage_mode == expected_storage_mode
268+
269+
254270
def _find_available_new_node(cluster, old_nodes):
255271
"""Find an available new node for swap rebalance"""
256272
for candidate_node in cluster._nodes:
@@ -806,17 +822,7 @@ def perform_delta_recovery_mid_storage_and_eviction_policy_migration_test(
806822
new_eviction_policy="fullEviction",
807823
)
808824

809-
def is_bucket_online_on_all_nodes():
810-
r = get_bucket(self.cluster, bucket_name)
811-
return all([node["status"] == "healthy" for node in r["nodes"]])
812-
813-
testlib.poll_for_condition(
814-
is_bucket_online_on_all_nodes,
815-
sleep_time=0.5,
816-
attempts=20,
817-
timeout=60,
818-
msg="poll bucket is online on all nodes",
819-
)
825+
wait_for_bucket_online_on_all_nodes(self.cluster, bucket_name)
820826

821827
# Failover a node and delta-recover it - the bucket should still have
822828
# per-node storage_mode/eviction_policy override props. Storage mode
@@ -844,3 +850,199 @@ def is_bucket_online_on_all_nodes():
844850
assert_per_node_eviction_policy_in_memcached(
845851
failover_node, bucket_name, "valueOnly"
846852
)
853+
854+
def eviction_policy_only_via_rebalance_test(self):
855+
"""Test eviction policy change on magma bucket with --no-restart"""
856+
bucket_name = "bucket-magma-eviction-test"
857+
858+
# Create bucket with magma and fullEviction eviction policy
859+
create_bucket(self.cluster, bucket_name, "magma", 1024, "fullEviction")
860+
861+
# Update bucket with eviction policy change + --no-restart
862+
update_data = {
863+
"name": bucket_name,
864+
"evictionPolicy": "valueOnly",
865+
"noRestart": "true",
866+
}
867+
868+
self.cluster.update_bucket(update_data)
869+
870+
# Verify eviction policy overrides are added
871+
assert_per_node_eviction_policy_keys_added(
872+
self.cluster, bucket_name, "fullEviction"
873+
)
874+
875+
# Wait for bucket to be online on all nodes before checking memcached
876+
wait_for_bucket_online_on_all_nodes(self.cluster, bucket_name)
877+
878+
for node in self.cluster.connected_nodes:
879+
assert_per_node_eviction_policy_in_memcached(
880+
node,
881+
bucket_name,
882+
"fullEviction",
883+
)
884+
885+
# Perform single node swap rebalance to apply the changes
886+
perform_single_node_swap_rebalance(
887+
self.cluster,
888+
bucket_name,
889+
node_index=0,
890+
expected_eviction_policy="valueOnly",
891+
)
892+
893+
self.cluster.delete_bucket(bucket_name)
894+
895+
def eviction_policy_only_via_full_recovery_test(self):
896+
"""Test eviction policy change with --no-restart, then full recovery"""
897+
bucket_name = "bucket-eviction-fullrec-test"
898+
899+
# Create bucket with couchstore + valueOnly
900+
create_bucket(
901+
self.cluster, bucket_name, "couchstore", 1024, "valueOnly"
902+
)
903+
904+
# Change eviction policy with --no-restart
905+
update_data = {
906+
"name": bucket_name,
907+
"evictionPolicy": "fullEviction",
908+
"noRestart": "true",
909+
}
910+
911+
self.cluster.update_bucket(update_data)
912+
913+
# Verify eviction policy overrides are added
914+
assert_per_node_eviction_policy_keys_added(
915+
self.cluster, bucket_name, "valueOnly"
916+
)
917+
918+
wait_for_bucket_online_on_all_nodes(self.cluster, bucket_name)
919+
920+
for node in self.cluster.connected_nodes:
921+
assert_per_node_eviction_policy_in_memcached(
922+
node,
923+
bucket_name,
924+
"valueOnly", # Should still be original value
925+
)
926+
927+
perform_failover_full_recovery(
928+
self.cluster, bucket_name, expected_eviction_policy="fullEviction"
929+
)
930+
931+
self.cluster.delete_bucket(bucket_name)
932+
933+
def eviction_policy_only_via_delta_recovery_test(self):
934+
"""Test eviction policy change with --no-restart, then delta recovery"""
935+
bucket_name = "bucket-eviction-deltarec-test"
936+
937+
# Create bucket with couchstore + fullEviction
938+
create_bucket(
939+
self.cluster, bucket_name, "couchstore", 1024, "fullEviction"
940+
)
941+
942+
# Change eviction policy with --no-restart
943+
update_data = {
944+
"name": bucket_name,
945+
"evictionPolicy": "valueOnly",
946+
"noRestart": "true",
947+
}
948+
949+
self.cluster.update_bucket(update_data)
950+
951+
# Verify eviction policy overrides are added
952+
assert_per_node_eviction_policy_keys_added(
953+
self.cluster, bucket_name, "fullEviction"
954+
)
955+
956+
wait_for_bucket_online_on_all_nodes(self.cluster, bucket_name)
957+
958+
for node in self.cluster.connected_nodes:
959+
assert_per_node_eviction_policy_in_memcached(
960+
node,
961+
bucket_name,
962+
"fullEviction", # Should still be original value
963+
)
964+
965+
# Perform delta recovery on each node
966+
for node in self.cluster.connected_nodes:
967+
self.cluster.failover_node(node, graceful=False)
968+
self.cluster.recover_node(
969+
node, recovery_type="delta", do_rebalance=True
970+
)
971+
972+
# Verify overrides are removed and memcached has new eviction policy
973+
assert_per_node_eviction_policy_not_present(
974+
self.cluster, node, bucket_name
975+
)
976+
assert_per_node_eviction_policy_in_memcached(
977+
node, bucket_name, "valueOnly"
978+
)
979+
980+
self.cluster.delete_bucket(bucket_name)
981+
982+
def eviction_policy_only_interleaved_test(self):
983+
"""Test eviction policy change with --no-restart, then immediate change without --no-restart"""
984+
bucket_name = "bucket-eviction-immediate-test"
985+
986+
# Create bucket with magma + valueOnly
987+
create_bucket(self.cluster, bucket_name, "magma", 1024, "valueOnly")
988+
989+
# Change eviction policy with --no-restart
990+
update_data_with_no_restart = {
991+
"name": bucket_name,
992+
"evictionPolicy": "fullEviction",
993+
"noRestart": "true",
994+
}
995+
996+
self.cluster.update_bucket(update_data_with_no_restart)
997+
998+
# Verify eviction policy overrides are added
999+
assert_per_node_eviction_policy_keys_added(
1000+
self.cluster, bucket_name, "valueOnly"
1001+
)
1002+
1003+
# Wait for bucket to be online on all nodes before checking memcached
1004+
wait_for_bucket_online_on_all_nodes(self.cluster, bucket_name)
1005+
1006+
for node in self.cluster.connected_nodes:
1007+
assert_per_node_eviction_policy_in_memcached(
1008+
node,
1009+
bucket_name,
1010+
"valueOnly", # Should still be original value
1011+
)
1012+
1013+
# Now change eviction policy WITHOUT --no-restart
1014+
update_data_without_no_restart = {
1015+
"name": bucket_name,
1016+
"evictionPolicy": "fullEviction",
1017+
}
1018+
1019+
self.cluster.update_bucket(update_data_without_no_restart)
1020+
1021+
# Verify overrides are gone and memcached immediately reflects the change
1022+
for node in self.cluster.connected_nodes:
1023+
assert_per_node_eviction_policy_not_present(
1024+
self.cluster, node, bucket_name
1025+
)
1026+
1027+
# Poll for eviction policy change in memcached (since bucket restart is async)
1028+
def check_eviction_policy_changed():
1029+
eviction_policy = (
1030+
testlib.diag_eval(
1031+
self.cluster,
1032+
f'ns_memcached:get_config_stats("{bucket_name}", <<"ep_item_eviction_policy">>).',
1033+
)
1034+
.content.decode("ascii")
1035+
.strip('<<"')
1036+
.strip('">>')
1037+
)
1038+
return eviction_policy == "full_eviction"
1039+
1040+
testlib.poll_for_condition(
1041+
check_eviction_policy_changed,
1042+
sleep_time=0.5,
1043+
attempts=20, # 10 seconds total with 1-second check interval
1044+
timeout=30,
1045+
msg=f"waiting for eviction policy to change to full_eviction on {node.hostname()}",
1046+
)
1047+
1048+
self.cluster.delete_bucket(bucket_name)

0 commit comments

Comments
 (0)