diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 22:52:54 +0100 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 22:52:54 +0100 |
| commit | dcacc00e3750300617ba6e16eb346713f91a783a (patch) | |
| tree | 38e2d4fb5ed9d119711d4295c6eda4b014af73fd /examples/redis-unstable/tests/unit/cluster/slot-stats.tcl | |
| parent | 58dac10aeb8f5a041c46bddbeaf4c7966a99b998 (diff) | |
| download | crep-dcacc00e3750300617ba6e16eb346713f91a783a.tar.gz | |
Remove testing data
Diffstat (limited to 'examples/redis-unstable/tests/unit/cluster/slot-stats.tcl')
| -rw-r--r-- | examples/redis-unstable/tests/unit/cluster/slot-stats.tcl | 1169 |
1 files changed, 0 insertions, 1169 deletions
diff --git a/examples/redis-unstable/tests/unit/cluster/slot-stats.tcl b/examples/redis-unstable/tests/unit/cluster/slot-stats.tcl deleted file mode 100644 index 1123731..0000000 --- a/examples/redis-unstable/tests/unit/cluster/slot-stats.tcl +++ /dev/null @@ -1,1169 +0,0 @@ -# -# Copyright (c) 2009-Present, Redis Ltd. -# All rights reserved. -# -# Copyright (c) 2024-present, Valkey contributors. -# All rights reserved. -# -# Licensed under your choice of (a) the Redis Source Available License 2.0 -# (RSALv2); or (b) the Server Side Public License v1 (SSPLv1); or (c) the -# GNU Affero General Public License v3 (AGPLv3). -# -# Portions of this file are available under BSD3 terms; see REDISCONTRIBUTIONS for more information. -# - -# Integration tests for CLUSTER SLOT-STATS command. - -# ----------------------------------------------------------------------------- -# Helper functions for CLUSTER SLOT-STATS test cases. -# ----------------------------------------------------------------------------- - -# Converts array RESP response into a dict. -# This is useful for many test cases, where unnecessary nesting is removed. -proc convert_array_into_dict {slot_stats} { - set res [dict create] - foreach slot_stat $slot_stats { - # slot_stat is an array of size 2, where 0th index represents (int) slot, - # and 1st index represents (map) usage statistics. - dict set res [lindex $slot_stat 0] [lindex $slot_stat 1] - } - return $res -} - -proc get_cmdstat_usec {cmd r} { - set cmdstatline [cmdrstat $cmd r] - regexp "usec=(.*?),usec_per_call=(.*?),rejected_calls=0,failed_calls=0" $cmdstatline -> usec _ - return $usec -} - -proc initialize_expected_slots_dict {} { - set expected_slots [dict create] - for {set i 0} {$i < 16384} {incr i 1} { - dict set expected_slots $i 0 - } - return $expected_slots -} - -proc initialize_expected_slots_dict_with_range {start_slot end_slot} { - assert {$start_slot <= $end_slot} - set expected_slots [dict create] - for {set i $start_slot} {$i <= $end_slot} {incr i 1} { - dict set expected_slots $i 0 - } - return $expected_slots -} - -proc assert_empty_slot_stats {slot_stats metrics_to_assert} { - set slot_stats [convert_array_into_dict $slot_stats] - dict for {slot stats} $slot_stats { - foreach metric_name $metrics_to_assert { - set metric_value [dict get $stats $metric_name] - assert {$metric_value == 0} - } - } -} - -proc assert_empty_slot_stats_with_exception {slot_stats exception_slots metrics_to_assert} { - set slot_stats [convert_array_into_dict $slot_stats] - dict for {slot stats} $exception_slots { - assert {[dict exists $slot_stats $slot]} ;# slot_stats must contain the expected slots. - } - dict for {slot stats} $slot_stats { - if {[dict exists $exception_slots $slot]} { - foreach metric_name $metrics_to_assert { - set metric_value [dict get $exception_slots $slot $metric_name] - assert {[dict get $stats $metric_name] == $metric_value} - } - } else { - dict for {metric value} $stats { - assert {$value == 0} - } - } - } -} - -proc assert_equal_slot_stats {slot_stats_1 slot_stats_2 deterministic_metrics non_deterministic_metrics} { - set slot_stats_1 [convert_array_into_dict $slot_stats_1] - set slot_stats_2 [convert_array_into_dict $slot_stats_2] - assert {[dict size $slot_stats_1] == [dict size $slot_stats_2]} - - dict for {slot stats_1} $slot_stats_1 { - assert {[dict exists $slot_stats_2 $slot]} - set stats_2 [dict get $slot_stats_2 $slot] - - # For deterministic metrics, we assert their equality. - foreach metric $deterministic_metrics { - assert {[dict get $stats_1 $metric] == [dict get $stats_2 $metric]} - } - # For non-deterministic metrics, we assert their non-zeroness as a best-effort. - foreach metric $non_deterministic_metrics { - assert {([dict get $stats_1 $metric] == 0 && [dict get $stats_2 $metric] == 0) || \ - ([dict get $stats_1 $metric] != 0 && [dict get $stats_2 $metric] != 0)} - } - } -} - -proc assert_all_slots_have_been_seen {expected_slots} { - dict for {k v} $expected_slots { - assert {$v == 1} - } -} - -proc assert_slot_visibility {slot_stats expected_slots} { - set slot_stats [convert_array_into_dict $slot_stats] - dict for {slot _} $slot_stats { - assert {[dict exists $expected_slots $slot]} - dict set expected_slots $slot 1 - } - - assert_all_slots_have_been_seen $expected_slots -} - -proc assert_slot_stats_monotonic_order {slot_stats orderby is_desc} { - # For Tcl dict, the order of iteration is the order in which the keys were inserted into the dictionary - # Thus, the response ordering is preserved upon calling 'convert_array_into_dict()'. - # Source: https://www.tcl.tk/man/tcl8.6.11/TclCmd/dict.htm - set slot_stats [convert_array_into_dict $slot_stats] - set prev_metric -1 - dict for {_ stats} $slot_stats { - set curr_metric [dict get $stats $orderby] - if {$prev_metric != -1} { - if {$is_desc == 1} { - assert {$prev_metric >= $curr_metric} - } else { - assert {$prev_metric <= $curr_metric} - } - } - set prev_metric $curr_metric - } -} - -proc assert_slot_stats_monotonic_descent {slot_stats orderby} { - assert_slot_stats_monotonic_order $slot_stats $orderby 1 -} - -proc assert_slot_stats_monotonic_ascent {slot_stats orderby} { - assert_slot_stats_monotonic_order $slot_stats $orderby 0 -} - -proc wait_for_replica_key_exists {key key_count} { - wait_for_condition 1000 50 { - [R 1 exists $key] eq "$key_count" - } else { - fail "Test key was not replicated" - } -} - -# ----------------------------------------------------------------------------- -# Test cases for CLUSTER SLOT-STATS cpu-usec metric correctness. -# ----------------------------------------------------------------------------- - -start_cluster 1 0 {tags {external:skip cluster} overrides {cluster-slot-stats-enabled yes}} { - - # Define shared variables. - set key "FOO" - set key_slot [R 0 cluster keyslot $key] - set key_secondary "FOO2" - set key_secondary_slot [R 0 cluster keyslot $key_secondary] - set metrics_to_assert [list cpu-usec] - - test "CLUSTER SLOT-STATS cpu-usec reset upon CONFIG RESETSTAT." { - R 0 SET $key VALUE - R 0 DEL $key - R 0 CONFIG RESETSTAT - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats $slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS cpu-usec reset upon slot migration." { - R 0 SET $key VALUE - - R 0 CLUSTER DELSLOTS $key_slot - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats $slot_stats $metrics_to_assert - - R 0 CLUSTER ADDSLOTS $key_slot - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats $slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS cpu-usec for non-slot specific commands." { - R 0 INFO - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats $slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS cpu-usec for slot specific commands." { - R 0 SET $key VALUE - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set usec [get_cmdstat_usec set r] - set expected_slot_stats [ - dict create $key_slot [ - dict create cpu-usec $usec - ] - ] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS cpu-usec for blocking commands, unblocked on keyspace update." { - # Blocking command with no timeout. Only keyspace update can unblock this client. - set rd [redis_deferring_client] - $rd BLPOP $key 0 - wait_for_blocked_clients_count 1 - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - # When the client is blocked, no accumulation is made. This behaviour is identical to INFO COMMANDSTATS. - assert_empty_slot_stats $slot_stats $metrics_to_assert - - # Unblocking command. - R 0 LPUSH $key value - wait_for_blocked_clients_count 0 - - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set lpush_usec [get_cmdstat_usec lpush r] - set blpop_usec [get_cmdstat_usec blpop r] - - # Assert that both blocking and non-blocking command times have been accumulated. - set expected_slot_stats [ - dict create $key_slot [ - dict create cpu-usec [expr $lpush_usec + $blpop_usec] - ] - ] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS cpu-usec for blocking commands, unblocked on timeout." { - # Blocking command with 0.5 seconds timeout. - set rd [redis_deferring_client] - $rd BLPOP $key 0.5 - - # Confirm that the client is blocked, then unblocked within 1 second. - wait_for_blocked_clients_count 1 - wait_for_blocked_clients_count 0 - - # Assert that the blocking command time has been accumulated. - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set blpop_usec [get_cmdstat_usec blpop r] - set expected_slot_stats [ - dict create $key_slot [ - dict create cpu-usec $blpop_usec - ] - ] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS cpu-usec for transactions." { - set r1 [redis_client] - $r1 MULTI - $r1 SET $key value - $r1 GET $key - - # CPU metric is not accumulated until EXEC is reached. This behaviour is identical to INFO COMMANDSTATS. - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats $slot_stats $metrics_to_assert - - # Execute transaction, and assert that all nested command times have been accumulated. - $r1 EXEC - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set exec_usec [get_cmdstat_usec exec r] - set expected_slot_stats [ - dict create $key_slot [ - dict create cpu-usec $exec_usec - ] - ] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS cpu-usec for lua-scripts, without cross-slot keys." { - R 0 eval {#!lua - redis.call('set', KEYS[1], 'bar') redis.call('get', KEYS[2]) - } 2 $key $key - - set eval_usec [get_cmdstat_usec eval r] - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - - set expected_slot_stats [ - dict create $key_slot [ - dict create cpu-usec $eval_usec - ] - ] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS cpu-usec for lua-scripts, with cross-slot keys." { - R 0 eval {#!lua flags=allow-cross-slot-keys - redis.call('set', KEYS[1], 'bar') redis.call('get', ARGV[1]) - } 1 $key $key_secondary - - # For cross-slot, we do not accumulate at all. - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats $slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS cpu-usec for functions, without cross-slot keys." { - R 0 function load replace {#!lua name=f1 - redis.register_function{ - function_name='f1', - callback=function(keys, args) redis.call('set', keys[1], '1') redis.call('get', keys[2]) end - } - } - R 0 fcall f1 2 $key $key - - set fcall_usec [get_cmdstat_usec fcall r] - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - - set expected_slot_stats [ - dict create $key_slot [ - dict create cpu-usec $fcall_usec - ] - ] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS cpu-usec for functions, with cross-slot keys." { - R 0 function load replace {#!lua name=f1 - redis.register_function{ - function_name='f1', - callback=function(keys, args) redis.call('set', keys[1], '1') redis.call('get', args[1]) end, - flags={'allow-cross-slot-keys'} - } - } - R 0 fcall f1 1 $key $key_secondary - - # For cross-slot, we do not accumulate at all. - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats $slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL -} - -# ----------------------------------------------------------------------------- -# Test cases for CLUSTER SLOT-STATS network-bytes-in. -# ----------------------------------------------------------------------------- - -start_cluster 1 0 {tags {external:skip cluster} overrides {cluster-slot-stats-enabled yes}} { - - # Define shared variables. - set key "key" - set key_slot [R 0 cluster keyslot $key] - set metrics_to_assert [list network-bytes-in] - - test "CLUSTER SLOT-STATS network-bytes-in, multi bulk buffer processing." { - # *3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n --> 33 bytes. - R 0 SET $key value - - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set expected_slot_stats [ - dict create $key_slot [ - dict create network-bytes-in 33 - ] - ] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS network-bytes-in, in-line buffer processing." { - set rd [redis_deferring_client] - # SET key value\r\n --> 15 bytes. - $rd write "SET $key value\r\n" - $rd flush - - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set expected_slot_stats [ - dict create $key_slot [ - dict create network-bytes-in 15 - ] - ] - - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS network-bytes-in, blocking command." { - set rd [redis_deferring_client] - # *3\r\n$5\r\nblpop\r\n$3\r\nkey\r\n$1\r\n0\r\n --> 31 bytes. - $rd BLPOP $key 0 - wait_for_blocked_clients_count 1 - - # Slot-stats must be empty here, as the client is yet to be unblocked. - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats $slot_stats $metrics_to_assert - - # *3\r\n$5\r\nlpush\r\n$3\r\nkey\r\n$5\r\nvalue\r\n --> 35 bytes. - R 0 LPUSH $key value - wait_for_blocked_clients_count 0 - - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set expected_slot_stats [ - dict create $key_slot [ - dict create network-bytes-in 66 ;# 31 + 35 bytes. - ] - ] - - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS network-bytes-in, multi-exec transaction." { - set r [redis_client] - # *1\r\n$5\r\nmulti\r\n --> 15 bytes. - $r MULTI - # *3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n --> 33 bytes. - assert {[$r SET $key value] eq {QUEUED}} - # *1\r\n$4\r\nexec\r\n --> 14 bytes. - assert {[$r EXEC] eq {OK}} - - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set expected_slot_stats [ - dict create $key_slot [ - dict create network-bytes-in 62 ;# 15 + 33 + 14 bytes. - ] - ] - - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS network-bytes-in, non slot specific command." { - R 0 INFO - - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats $slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS network-bytes-in, pub/sub." { - # PUB/SUB does not get accumulated at per-slot basis, - # as it is cluster-wide and is not slot specific. - set rd [redis_deferring_client] - $rd subscribe channel - R 0 publish channel message - - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats $slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL -} - -start_cluster 1 1 {tags {external:skip cluster} overrides {cluster-slot-stats-enabled yes}} { - set channel "channel" - set key_slot [R 0 cluster keyslot $channel] - set metrics_to_assert [list network-bytes-in] - - # Setup replication. - assert {[s -1 role] eq {slave}} - wait_for_condition 1000 50 { - [s -1 master_link_status] eq {up} - } else { - fail "Instance #1 master link status is not up" - } - R 1 readonly - - test "CLUSTER SLOT-STATS network-bytes-in, sharded pub/sub." { - set slot [R 0 cluster keyslot $channel] - set primary [Rn 0] - set replica [Rn 1] - set replica_subcriber [redis_deferring_client -1] - $replica_subcriber SSUBSCRIBE $channel - # *2\r\n$10\r\nssubscribe\r\n$7\r\nchannel\r\n --> 34 bytes. - $primary SPUBLISH $channel hello - # *3\r\n$8\r\nspublish\r\n$7\r\nchannel\r\n$5\r\nhello\r\n --> 42 bytes. - - set slot_stats [$primary CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set expected_slot_stats [ - dict create $key_slot [ - dict create network-bytes-in 42 - ] - ] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - - set slot_stats [$replica CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set expected_slot_stats [ - dict create $key_slot [ - dict create network-bytes-in 34 - ] - ] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL -} - -# ----------------------------------------------------------------------------- -# Test cases for CLUSTER SLOT-STATS network-bytes-out correctness. -# ----------------------------------------------------------------------------- - -start_cluster 1 0 {tags {external:skip cluster}} { - # Define shared variables. - set key "FOO" - set key_slot [R 0 cluster keyslot $key] - set expected_slots_to_key_count [dict create $key_slot 1] - set metrics_to_assert [list network-bytes-out] - R 0 CONFIG SET cluster-slot-stats-enabled yes - - test "CLUSTER SLOT-STATS network-bytes-out, for non-slot specific commands." { - R 0 INFO - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats $slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS network-bytes-out, for slot specific commands." { - R 0 SET $key value - # +OK\r\n --> 5 bytes - - set expected_slot_stats [ - dict create $key_slot [ - dict create network-bytes-out 5 - ] - ] - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL - - test "CLUSTER SLOT-STATS network-bytes-out, blocking commands." { - set rd [redis_deferring_client] - $rd BLPOP $key 0 - wait_for_blocked_clients_count 1 - - # Assert empty slot stats here, since COB is yet to be flushed due to the block. - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats $slot_stats $metrics_to_assert - - # Unblock the command. - # LPUSH client) :1\r\n --> 4 bytes. - # BLPOP client) *2\r\n$3\r\nkey\r\n$5\r\nvalue\r\n --> 24 bytes, upon unblocking. - R 0 LPUSH $key value - wait_for_blocked_clients_count 0 - - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set expected_slot_stats [ - dict create $key_slot [ - dict create network-bytes-out 28 ;# 4 + 24 bytes. - ] - ] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } - R 0 CONFIG RESETSTAT - R 0 FLUSHALL -} - -start_cluster 1 1 {tags {external:skip cluster}} { - - # Define shared variables. - set key "FOO" - set key_slot [R 0 CLUSTER KEYSLOT $key] - set metrics_to_assert [list network-bytes-out] - R 0 CONFIG SET cluster-slot-stats-enabled yes - - # Setup replication. - assert {[s -1 role] eq {slave}} - wait_for_condition 1000 50 { - [s -1 master_link_status] eq {up} - } else { - fail "Instance #1 master link status is not up" - } - R 1 readonly - - test "CLUSTER SLOT-STATS network-bytes-out, replication stream egress." { - assert_equal [R 0 SET $key VALUE] {OK} - # Local client) +OK\r\n --> 5 bytes. - # Replication stream) *3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n --> 33 bytes. - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set expected_slot_stats [ - dict create $key_slot [ - dict create network-bytes-out 38 ;# 5 + 33 bytes. - ] - ] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } -} - -start_cluster 1 1 {tags {external:skip cluster}} { - - # Define shared variables. - set channel "channel" - set key_slot [R 0 cluster keyslot $channel] - set channel_secondary "channel2" - set key_slot_secondary [R 0 cluster keyslot $channel_secondary] - set metrics_to_assert [list network-bytes-out] - R 0 CONFIG SET cluster-slot-stats-enabled yes - - test "CLUSTER SLOT-STATS network-bytes-out, sharded pub/sub, single channel." { - set slot [R 0 cluster keyslot $channel] - set publisher [Rn 0] - set subscriber [redis_client] - set replica [redis_deferring_client -1] - - # Subscriber client) *3\r\n$10\r\nssubscribe\r\n$7\r\nchannel\r\n:1\r\n --> 38 bytes - $subscriber SSUBSCRIBE $channel - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set expected_slot_stats [ - dict create $key_slot [ - dict create network-bytes-out 38 - ] - ] - R 0 CONFIG RESETSTAT - - # Publisher client) :1\r\n --> 4 bytes. - # Subscriber client) *3\r\n$8\r\nsmessage\r\n$7\r\nchannel\r\n$5\r\nhello\r\n --> 42 bytes. - assert_equal 1 [$publisher SPUBLISH $channel hello] - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set expected_slot_stats [ - dict create $key_slot [ - dict create network-bytes-out 46 ;# 4 + 42 bytes. - ] - ] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } - $subscriber QUIT - R 0 FLUSHALL - R 0 CONFIG RESETSTAT - - test "CLUSTER SLOT-STATS network-bytes-out, sharded pub/sub, cross-slot channels." { - set slot [R 0 cluster keyslot $channel] - set publisher [Rn 0] - set subscriber [redis_client] - set replica [redis_deferring_client -1] - - # Stack multi-slot subscriptions against a single client. - # For primary channel; - # Subscriber client) *3\r\n$10\r\nssubscribe\r\n$7\r\nchannel\r\n:1\r\n --> 38 bytes - # For secondary channel; - # Subscriber client) *3\r\n$10\r\nssubscribe\r\n$8\r\nchannel2\r\n:1\r\n --> 39 bytes - $subscriber SSUBSCRIBE $channel - $subscriber SSUBSCRIBE $channel_secondary - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set expected_slot_stats [ - dict create \ - $key_slot [ \ - dict create network-bytes-out 38 - ] \ - $key_slot_secondary [ \ - dict create network-bytes-out 39 - ] - ] - R 0 CONFIG RESETSTAT - - # For primary channel; - # Publisher client) :1\r\n --> 4 bytes. - # Subscriber client) *3\r\n$8\r\nsmessage\r\n$7\r\nchannel\r\n$5\r\nhello\r\n --> 42 bytes. - # For secondary channel; - # Publisher client) :1\r\n --> 4 bytes. - # Subscriber client) *3\r\n$8\r\nsmessage\r\n$8\r\nchannel2\r\n$5\r\nhello\r\n --> 43 bytes. - assert_equal 1 [$publisher SPUBLISH $channel hello] - assert_equal 1 [$publisher SPUBLISH $channel_secondary hello] - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set expected_slot_stats [ - dict create \ - $key_slot [ \ - dict create network-bytes-out 46 ;# 4 + 42 bytes. - ] \ - $key_slot_secondary [ \ - dict create network-bytes-out 47 ;# 4 + 43 bytes. - ] - ] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } -} - -# ----------------------------------------------------------------------------- -# Test cases for CLUSTER SLOT-STATS key-count metric correctness. -# ----------------------------------------------------------------------------- - -start_cluster 1 0 {tags {external:skip cluster} overrides {cluster-slot-stats-enabled yes}} { - - # Define shared variables. - set key "FOO" - set key_slot [R 0 cluster keyslot $key] - set metrics_to_assert [list key-count] - set expected_slot_stats [ - dict create $key_slot [ - dict create key-count 1 - ] - ] - - test "CLUSTER SLOT-STATS contains default value upon redis-server startup" { - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats $slot_stats $metrics_to_assert - } - - test "CLUSTER SLOT-STATS contains correct metrics upon key introduction" { - R 0 SET $key TEST - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } - - test "CLUSTER SLOT-STATS contains correct metrics upon key mutation" { - R 0 SET $key NEW_VALUE - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } - - test "CLUSTER SLOT-STATS contains correct metrics upon key deletion" { - R 0 DEL $key - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats $slot_stats $metrics_to_assert - } - - test "CLUSTER SLOT-STATS slot visibility based on slot ownership changes" { - R 0 CONFIG SET cluster-require-full-coverage no - - R 0 CLUSTER DELSLOTS $key_slot - set expected_slots [initialize_expected_slots_dict] - dict unset expected_slots $key_slot - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert {[dict size $expected_slots] == 16383} - assert_slot_visibility $slot_stats $expected_slots - - R 0 CLUSTER ADDSLOTS $key_slot - set expected_slots [initialize_expected_slots_dict] - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert {[dict size $expected_slots] == 16384} - assert_slot_visibility $slot_stats $expected_slots - } -} - -# ----------------------------------------------------------------------------- -# Test cases for CLUSTER SLOT-STATS SLOTSRANGE sub-argument. -# ----------------------------------------------------------------------------- - -start_cluster 1 0 {tags {external:skip cluster}} { - - test "CLUSTER SLOT-STATS SLOTSRANGE all slots present" { - set start_slot 100 - set end_slot 102 - set expected_slots [initialize_expected_slots_dict_with_range $start_slot $end_slot] - - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE $start_slot $end_slot] - assert_slot_visibility $slot_stats $expected_slots - } - - test "CLUSTER SLOT-STATS SLOTSRANGE some slots missing" { - set start_slot 100 - set end_slot 102 - set expected_slots [initialize_expected_slots_dict_with_range $start_slot $end_slot] - - R 0 CLUSTER DELSLOTS $start_slot - dict unset expected_slots $start_slot - - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE $start_slot $end_slot] - assert_slot_visibility $slot_stats $expected_slots - } -} - -# ----------------------------------------------------------------------------- -# Test cases for CLUSTER SLOT-STATS ORDERBY sub-argument. -# ----------------------------------------------------------------------------- - -start_cluster 1 0 {tags {external:skip cluster} overrides {cluster-slot-stats-enabled yes}} { - - set metrics [list "key-count" "memory-bytes" "cpu-usec" "network-bytes-in" "network-bytes-out"] - - # SET keys for target hashslots, to encourage ordering. - set hash_tags [list 0 1 2 3 4] - set num_keys 1 - foreach hash_tag $hash_tags { - for {set i 0} {$i < $num_keys} {incr i 1} { - R 0 SET "$i{$hash_tag}" VALUE - } - incr num_keys 1 - } - - # SET keys for random hashslots, for random noise. - set num_keys 0 - while {$num_keys < 1000} { - set random_key [randomInt 16384] - R 0 SET $random_key VALUE - incr num_keys 1 - } - - test "CLUSTER SLOT-STATS ORDERBY DESC correct ordering" { - foreach orderby $metrics { - set slot_stats [R 0 CLUSTER SLOT-STATS ORDERBY $orderby DESC] - assert_slot_stats_monotonic_descent $slot_stats $orderby - } - } - - test "CLUSTER SLOT-STATS ORDERBY ASC correct ordering" { - foreach orderby $metrics { - set slot_stats [R 0 CLUSTER SLOT-STATS ORDERBY $orderby ASC] - assert_slot_stats_monotonic_ascent $slot_stats $orderby - } - } - - test "CLUSTER SLOT-STATS ORDERBY LIMIT correct response pagination, where limit is less than number of assigned slots" { - R 0 FLUSHALL SYNC - R 0 CONFIG RESETSTAT - - foreach orderby $metrics { - set limit 5 - set slot_stats_desc [R 0 CLUSTER SLOT-STATS ORDERBY $orderby LIMIT $limit DESC] - set slot_stats_asc [R 0 CLUSTER SLOT-STATS ORDERBY $orderby LIMIT $limit ASC] - set slot_stats_desc_length [llength $slot_stats_desc] - set slot_stats_asc_length [llength $slot_stats_asc] - assert {$limit == $slot_stats_desc_length && $limit == $slot_stats_asc_length} - - # All slot statistics have been reset to 0, so we will order by slot in ascending order. - set expected_slots [dict create 0 0 1 0 2 0 3 0 4 0] - assert_slot_visibility $slot_stats_desc $expected_slots - assert_slot_visibility $slot_stats_asc $expected_slots - } - } - - test "CLUSTER SLOT-STATS ORDERBY LIMIT correct response pagination, where limit is greater than number of assigned slots" { - R 0 CONFIG SET cluster-require-full-coverage no - R 0 FLUSHALL SYNC - R 0 CLUSTER FLUSHSLOTS - R 0 CLUSTER ADDSLOTS 100 101 - - foreach orderby $metrics { - set num_assigned_slots 2 - set limit 5 - set slot_stats_desc [R 0 CLUSTER SLOT-STATS ORDERBY $orderby LIMIT $limit DESC] - set slot_stats_asc [R 0 CLUSTER SLOT-STATS ORDERBY $orderby LIMIT $limit ASC] - set slot_stats_desc_length [llength $slot_stats_desc] - set slot_stats_asc_length [llength $slot_stats_asc] - set expected_response_length [expr min($num_assigned_slots, $limit)] - assert {$expected_response_length == $slot_stats_desc_length && $expected_response_length == $slot_stats_asc_length} - - set expected_slots [dict create 100 0 101 0] - assert_slot_visibility $slot_stats_desc $expected_slots - assert_slot_visibility $slot_stats_asc $expected_slots - } - } - - test "CLUSTER SLOT-STATS ORDERBY arg sanity check." { - # Non-existent argument. - assert_error "ERR*" {R 0 CLUSTER SLOT-STATS ORDERBY key-count non-existent-arg} - # Negative LIMIT. - assert_error "ERR*" {R 0 CLUSTER SLOT-STATS ORDERBY key-count DESC LIMIT -1} - # Non-existent ORDERBY metric. - assert_error "ERR*" {R 0 CLUSTER SLOT-STATS ORDERBY non-existent-metric} - # When cluster-slot-stats-enabled config is disabled, you cannot sort using advanced metrics. - R 0 CONFIG SET cluster-slot-stats-enabled no - set orderby "cpu-usec" - assert_error "ERR*" {R 0 CLUSTER SLOT-STATS ORDERBY $orderby} - set orderby "network-bytes-in" - assert_error "ERR*" {R 0 CLUSTER SLOT-STATS ORDERBY $orderby} - set orderby "network-bytes-out" - assert_error "ERR*" {R 0 CLUSTER SLOT-STATS ORDERBY $orderby} - set orderby "memory-bytes" - assert_error "ERR*" {R 0 CLUSTER SLOT-STATS ORDERBY $orderby} - - # When only cpu net is enabled, memory-bytes ORDERBY should fail - R 0 CONFIG SET cluster-slot-stats-enabled "cpu net" - assert_error "ERR*" {R 0 CLUSTER SLOT-STATS ORDERBY memory-bytes} - } - -} - -# ----------------------------------------------------------------------------- -# Test cases for CLUSTER SLOT-STATS replication. -# ----------------------------------------------------------------------------- - -start_cluster 1 1 {tags {external:skip cluster} overrides {cluster-slot-stats-enabled yes}} { - - # Define shared variables. - set key "key" - set key_slot [R 0 CLUSTER KEYSLOT $key] - set primary [Rn 0] - set replica [Rn 1] - - # For replication, assertions are split between deterministic and non-deterministic metrics. - # * For deterministic metrics, strict equality assertions are made. - # * For non-deterministic metrics, non-zeroness assertions are made. - # Non-zeroness as in, both primary and replica should either have some value, or no value at all. - # - # * key-count is deterministic between primary and its replica. - # * cpu-usec is non-deterministic between primary and its replica. - # * network-bytes-in is deterministic between primary and its replica. - # * network-bytes-out will remain empty in the replica, since primary client do not receive replies, unless for replicationSendAck(). - set deterministic_metrics [list key-count network-bytes-in] - set non_deterministic_metrics [list cpu-usec] - set empty_metrics [list network-bytes-out] - - # Setup replication. - assert {[s -1 role] eq {slave}} - wait_for_condition 1000 50 { - [s -1 master_link_status] eq {up} - } else { - fail "Instance #1 master link status is not up" - } - R 1 readonly - - test "CLUSTER SLOT-STATS metrics replication for new keys" { - # *3\r\n$3\r\nset\r\n$3\r\nkey\r\n$5\r\nvalue\r\n --> 33 bytes. - R 0 SET $key VALUE - - set expected_slot_stats [ - dict create $key_slot [ - dict create key-count 1 network-bytes-in 33 - ] - ] - set slot_stats_master [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats_with_exception $slot_stats_master $expected_slot_stats $deterministic_metrics - - wait_for_condition 500 10 { - [string match {*calls=1,*} [cmdrstat set $replica]] - } else { - fail "Replica did not receive the command." - } - set slot_stats_replica [R 1 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_equal_slot_stats $slot_stats_master $slot_stats_replica $deterministic_metrics $non_deterministic_metrics - assert_empty_slot_stats $slot_stats_replica $empty_metrics - } - R 0 CONFIG RESETSTAT - R 1 CONFIG RESETSTAT - - test "CLUSTER SLOT-STATS metrics replication for existing keys" { - # *3\r\n$3\r\nset\r\n$3\r\nkey\r\n$13\r\nvalue_updated\r\n --> 42 bytes. - R 0 SET $key VALUE_UPDATED - - set expected_slot_stats [ - dict create $key_slot [ - dict create key-count 1 network-bytes-in 42 - ] - ] - set slot_stats_master [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats_with_exception $slot_stats_master $expected_slot_stats $deterministic_metrics - - wait_for_condition 500 10 { - [string match {*calls=1,*} [cmdrstat set $replica]] - } else { - fail "Replica did not receive the command." - } - set slot_stats_replica [R 1 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_equal_slot_stats $slot_stats_master $slot_stats_replica $deterministic_metrics $non_deterministic_metrics - assert_empty_slot_stats $slot_stats_replica $empty_metrics - } - R 0 CONFIG RESETSTAT - R 1 CONFIG RESETSTAT - - test "CLUSTER SLOT-STATS metrics replication for deleting keys" { - # *2\r\n$3\r\ndel\r\n$3\r\nkey\r\n --> 22 bytes. - R 0 DEL $key - - set expected_slot_stats [ - dict create $key_slot [ - dict create key-count 0 network-bytes-in 22 - ] - ] - set slot_stats_master [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_empty_slot_stats_with_exception $slot_stats_master $expected_slot_stats $deterministic_metrics - - wait_for_condition 500 10 { - [string match {*calls=1,*} [cmdrstat del $replica]] - } else { - fail "Replica did not receive the command." - } - set slot_stats_replica [R 1 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - assert_equal_slot_stats $slot_stats_master $slot_stats_replica $deterministic_metrics $non_deterministic_metrics - assert_empty_slot_stats $slot_stats_replica $empty_metrics - } - R 0 CONFIG RESETSTAT - R 1 CONFIG RESETSTAT -} - -start_cluster 2 2 {tags {external:skip cluster} overrides {cluster-slot-stats-enabled yes}} { - test "CLUSTER SLOT-STATS reset upon atomic slot migration" { - # key on slot-0 - set key0 "{06S}mykey0" - set key0_slot [R 0 CLUSTER KEYSLOT $key0] - R 0 SET $key0 VALUE - - # Migrate slot-0 to node-1 - R 1 CLUSTER MIGRATION IMPORT 0 0 - wait_for_condition 1000 10 { - [CI 0 cluster_slot_migration_active_tasks] == 0 && - [CI 1 cluster_slot_migration_active_tasks] == 0 - } else { - fail "ASM tasks did not complete" - } - - set expected_slot_stats [ - dict create \ - $key0_slot [ \ - dict create key-count 1 \ - dict create cpu-usec 0 \ - dict create network-bytes-in 0 \ - dict create network-bytes-out 0 \ - ] - ] - set metrics_to_assert [list key-count cpu-usec network-bytes-in network-bytes-out] - - # Verify metrics are reset except key-count - set slot_stats [R 1 CLUSTER SLOT-STATS SLOTSRANGE 0 0] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - - # Migrate slot-0 back to node-0 - R 0 CLUSTER MIGRATION IMPORT 0 0 - wait_for_condition 1000 10 { - [CI 0 cluster_slot_migration_active_tasks] == 0 && - [CI 1 cluster_slot_migration_active_tasks] == 0 - } else { - fail "ASM tasks did not complete" - } - - # Verify metrics are reset except key-count - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 0] - assert_empty_slot_stats_with_exception $slot_stats $expected_slot_stats $metrics_to_assert - } -} - -# ----------------------------------------------------------------------------- -# Test cases for CLUSTER SLOT-STATS memory-bytes field presence. -# ----------------------------------------------------------------------------- - -start_cluster 1 0 {tags {external:skip cluster} overrides {cluster-slot-stats-enabled yes}} { - # Define shared variables. - set key "FOO" - set key_slot [R 0 cluster keyslot $key] - - test "CLUSTER SLOT-STATS memory-bytes field present when cluster-slot-stats-enabled set on startup" { - R 0 SET $key VALUE - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set slot_stats [convert_array_into_dict $slot_stats] - - # Verify memory-bytes field is present - assert {[dict exists $slot_stats $key_slot]} - set stats [dict get $slot_stats $key_slot] - assert {[dict exists $stats memory-bytes]} - assert {[dict get $stats memory-bytes] > 0} - } - - test "CLUSTER SLOT-STATS net mem combination shows only net and mem stats" { - R 0 CONFIG SET cluster-slot-stats-enabled "net mem" - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set slot_stats [convert_array_into_dict $slot_stats] - - set stats [dict get $slot_stats $key_slot] - assert {[dict exists $stats memory-bytes]} - assert {[dict exists $stats network-bytes-in]} - assert {[dict exists $stats network-bytes-out]} - assert {![dict exists $stats cpu-usec]} - } - - test "CLUSTER SLOT-STATS cpu mem combination shows only cpu and mem stats" { - R 0 CONFIG SET cluster-slot-stats-enabled "cpu mem" - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set slot_stats [convert_array_into_dict $slot_stats] - - set stats [dict get $slot_stats $key_slot] - assert {[dict exists $stats memory-bytes]} - assert {[dict exists $stats cpu-usec]} - assert {![dict exists $stats network-bytes-in]} - assert {![dict exists $stats network-bytes-out]} - - # Restore to yes for subsequent tests - R 0 CONFIG SET cluster-slot-stats-enabled yes - } - - test "CLUSTER SLOT-STATS memory-bytes field not present after disabling cluster-slot-stats-enabled" { - R 0 CONFIG SET cluster-slot-stats-enabled no - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set slot_stats [convert_array_into_dict $slot_stats] - - # Verify memory-bytes field is not present after disabling config - # (memory tracking is disabled when MEM flag is removed) - assert {[dict exists $slot_stats $key_slot]} - set stats [dict get $slot_stats $key_slot] - assert {![dict exists $stats memory-bytes]} - - # Verify other stats fields are not present - assert {![dict exists $stats cpu-usec]} - assert {![dict exists $stats network-bytes-in]} - assert {![dict exists $stats network-bytes-out]} - } - - test "CLUSTER SLOT-STATS memory tracking cannot be re-enabled after being disabled" { - # Once memory tracking is disabled, it cannot be re-enabled at runtime - assert_error "ERR*memory tracking cannot be enabled at runtime*" {R 0 CONFIG SET cluster-slot-stats-enabled yes} - assert_error "ERR*memory tracking cannot be enabled at runtime*" {R 0 CONFIG SET cluster-slot-stats-enabled mem} - - # But cpu and net can still be enabled - R 0 CONFIG SET cluster-slot-stats-enabled "cpu net" - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set slot_stats [convert_array_into_dict $slot_stats] - - assert {[dict exists $slot_stats $key_slot]} - set stats [dict get $slot_stats $key_slot] - assert {![dict exists $stats memory-bytes]} - assert {[dict exists $stats cpu-usec]} - assert {[dict exists $stats network-bytes-in]} - assert {[dict exists $stats network-bytes-out]} - } -} - -start_cluster 1 0 {tags {external:skip cluster} overrides {cluster-slot-stats-enabled no}} { - # Define shared variables. - set key "FOO" - set key_slot [R 0 cluster keyslot $key] - - test "CLUSTER SLOT-STATS memory-bytes field not present when cluster-slot-stats-enabled not set on startup" { - R 0 SET $key VALUE - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set slot_stats [convert_array_into_dict $slot_stats] - - # Verify memory-bytes field is not present - assert {[dict exists $slot_stats $key_slot]} - set stats [dict get $slot_stats $key_slot] - assert {![dict exists $stats memory-bytes]} - - # Only key-count should be present - assert {[dict exists $stats key-count]} - assert {[dict get $stats key-count] == 1} - } - - test "CLUSTER SLOT-STATS enabling mem at runtime fails when not enabled at startup" { - # Trying to enable memory tracking at runtime should fail - assert_error "ERR*memory tracking cannot be enabled at runtime*" {R 0 CONFIG SET cluster-slot-stats-enabled mem} - assert_error "ERR*memory tracking cannot be enabled at runtime*" {R 0 CONFIG SET cluster-slot-stats-enabled yes} - assert_error "ERR*memory tracking cannot be enabled at runtime*" {R 0 CONFIG SET cluster-slot-stats-enabled "cpu net mem"} - } - - test "CLUSTER SLOT-STATS enabling cpu and net at runtime works" { - R 0 CONFIG SET cluster-slot-stats-enabled "cpu net" - set slot_stats [R 0 CLUSTER SLOT-STATS SLOTSRANGE 0 16383] - set slot_stats [convert_array_into_dict $slot_stats] - - # Verify memory-bytes field is still not present - assert {[dict exists $slot_stats $key_slot]} - set stats [dict get $slot_stats $key_slot] - assert {![dict exists $stats memory-bytes]} - - # Other stats fields should now be present - assert {[dict exists $stats cpu-usec]} - assert {[dict exists $stats network-bytes-in]} - assert {[dict exists $stats network-bytes-out]} - } -} |
