aboutsummaryrefslogtreecommitdiff
path: root/examples/redis-unstable/tests/unit/moduleapi/propagate.tcl
diff options
context:
space:
mode:
Diffstat (limited to 'examples/redis-unstable/tests/unit/moduleapi/propagate.tcl')
-rw-r--r--examples/redis-unstable/tests/unit/moduleapi/propagate.tcl806
1 files changed, 0 insertions, 806 deletions
diff --git a/examples/redis-unstable/tests/unit/moduleapi/propagate.tcl b/examples/redis-unstable/tests/unit/moduleapi/propagate.tcl
deleted file mode 100644
index d3d08d9..0000000
--- a/examples/redis-unstable/tests/unit/moduleapi/propagate.tcl
+++ /dev/null
@@ -1,806 +0,0 @@
1set testmodule [file normalize tests/modules/propagate.so]
2set miscmodule [file normalize tests/modules/misc.so]
3set keyspace_events [file normalize tests/modules/keyspace_events.so]
4
5tags "modules external:skip" {
6 test {Modules can propagate in async and threaded contexts} {
7 start_server [list overrides [list loadmodule "$testmodule"]] {
8 set replica [srv 0 client]
9 set replica_host [srv 0 host]
10 set replica_port [srv 0 port]
11 $replica module load $keyspace_events
12 start_server [list overrides [list loadmodule "$testmodule"]] {
13 set master [srv 0 client]
14 set master_host [srv 0 host]
15 set master_port [srv 0 port]
16 $master module load $keyspace_events
17
18 # Start the replication process...
19 $replica replicaof $master_host $master_port
20 wait_for_sync $replica
21 after 1000
22
23 test {module propagates from timer} {
24 set repl [attach_to_replication_stream]
25
26 $master propagate-test.timer
27
28 wait_for_condition 500 10 {
29 [$replica get timer] eq "3"
30 } else {
31 fail "The two counters don't match the expected value."
32 }
33
34 assert_replication_stream $repl {
35 {select *}
36 {incr timer}
37 {incr timer}
38 {incr timer}
39 }
40 close_replication_stream $repl
41 }
42
43 test {module propagation with notifications} {
44 set repl [attach_to_replication_stream]
45
46 $master set x y
47
48 assert_replication_stream $repl {
49 {multi}
50 {select *}
51 {incr notifications}
52 {set x y}
53 {exec}
54 }
55 close_replication_stream $repl
56 }
57
58 test {module propagation with notifications with multi} {
59 set repl [attach_to_replication_stream]
60
61 $master multi
62 $master set x1 y1
63 $master set x2 y2
64 $master exec
65
66 assert_replication_stream $repl {
67 {multi}
68 {select *}
69 {incr notifications}
70 {set x1 y1}
71 {incr notifications}
72 {set x2 y2}
73 {exec}
74 }
75 close_replication_stream $repl
76 }
77
78 test {module propagation with notifications with active-expire} {
79 $master debug set-active-expire 1
80 set repl [attach_to_replication_stream]
81
82 $master set asdf1 1 PX 300
83 $master set asdf2 2 PX 300
84 $master set asdf3 3 PX 300
85
86 wait_for_condition 500 10 {
87 [$replica keys asdf*] eq {}
88 } else {
89 fail "Not all keys have expired"
90 }
91
92 # Note whenever there's double notification: SET with PX issues two separate
93 # notifications: one for "set" and one for "expire"
94 assert_replication_stream $repl {
95 {multi}
96 {select *}
97 {incr notifications}
98 {incr notifications}
99 {set asdf1 1 PXAT *}
100 {exec}
101 {multi}
102 {incr notifications}
103 {incr notifications}
104 {set asdf2 2 PXAT *}
105 {exec}
106 {multi}
107 {incr notifications}
108 {incr notifications}
109 {set asdf3 3 PXAT *}
110 {exec}
111 {multi}
112 {incr notifications}
113 {incr notifications}
114 {incr testkeyspace:expired}
115 {del asdf*}
116 {exec}
117 {multi}
118 {incr notifications}
119 {incr notifications}
120 {incr testkeyspace:expired}
121 {del asdf*}
122 {exec}
123 {multi}
124 {incr notifications}
125 {incr notifications}
126 {incr testkeyspace:expired}
127 {del asdf*}
128 {exec}
129 }
130 close_replication_stream $repl
131
132 $master debug set-active-expire 0
133 }
134
135 test {module propagation with notifications with eviction case 1} {
136 $master flushall
137 $master set asdf1 1
138 $master set asdf2 2
139 $master set asdf3 3
140
141 $master config set maxmemory-policy allkeys-random
142 $master config set maxmemory 1
143
144 # Please note the following loop:
145 # We evict a key and send a notification, which does INCR on the "notifications" key, so
146 # that every time we evict any key, "notifications" key exist (it happens inside the
147 # performEvictions loop). So even evicting "notifications" causes INCR on "notifications".
148 # If maxmemory_eviction_tenacity would have been set to 100 this would be an endless loop, but
149 # since the default is 10, at some point the performEvictions loop would end.
150 # Bottom line: "notifications" always exists and we can't really determine the order of evictions
151 # This test is here only for sanity
152
153 # The replica will get the notification with multi exec and we have a generic notification handler
154 # that performs `RedisModule_Call(ctx, "INCR", "c", "multi");` if the notification is inside multi exec.
155 # so we will have 2 keys, "notifications" and "multi".
156 wait_for_condition 500 10 {
157 [$replica dbsize] eq 2
158 } else {
159 fail "Not all keys have been evicted"
160 }
161
162 $master config set maxmemory 0
163 $master config set maxmemory-policy noeviction
164 }
165
166 test {module propagation with notifications with eviction case 2} {
167 $master flushall
168 set repl [attach_to_replication_stream]
169
170 $master set asdf1 1 EX 300
171 $master set asdf2 2 EX 300
172 $master set asdf3 3 EX 300
173
174 # Please note we use volatile eviction to prevent the loop described in the test above.
175 # "notifications" is not volatile so it always remains
176 $master config resetstat
177 $master config set maxmemory-policy volatile-ttl
178 $master config set maxmemory 1
179
180 wait_for_condition 500 10 {
181 [s evicted_keys] eq 3
182 } else {
183 fail "Not all keys have been evicted"
184 }
185
186 $master config set maxmemory 0
187 $master config set maxmemory-policy noeviction
188
189 $master set asdf4 4
190
191 # Note whenever there's double notification: SET with EX issues two separate
192 # notifications: one for "set" and one for "expire"
193 # Note that although CONFIG SET maxmemory is called in this flow (see issue #10014),
194 # eviction will happen and will not induce propagation of the CONFIG command (see #10019).
195 assert_replication_stream $repl {
196 {multi}
197 {select *}
198 {incr notifications}
199 {incr notifications}
200 {set asdf1 1 PXAT *}
201 {exec}
202 {multi}
203 {incr notifications}
204 {incr notifications}
205 {set asdf2 2 PXAT *}
206 {exec}
207 {multi}
208 {incr notifications}
209 {incr notifications}
210 {set asdf3 3 PXAT *}
211 {exec}
212 {multi}
213 {incr notifications}
214 {del asdf*}
215 {exec}
216 {multi}
217 {incr notifications}
218 {del asdf*}
219 {exec}
220 {multi}
221 {incr notifications}
222 {del asdf*}
223 {exec}
224 {multi}
225 {incr notifications}
226 {set asdf4 4}
227 {exec}
228 }
229 close_replication_stream $repl
230 }
231
232 test {module propagation with timer and CONFIG SET maxmemory} {
233 set repl [attach_to_replication_stream]
234
235 $master config resetstat
236 $master config set maxmemory-policy volatile-random
237
238 $master propagate-test.timer-maxmemory
239
240 # Wait until the volatile keys are evicted
241 wait_for_condition 500 10 {
242 [s evicted_keys] eq 2
243 } else {
244 fail "Not all keys have been evicted"
245 }
246
247 assert_replication_stream $repl {
248 {multi}
249 {select *}
250 {incr notifications}
251 {incr notifications}
252 {set timer-maxmemory-volatile-start 1 PXAT *}
253 {incr timer-maxmemory-middle}
254 {incr notifications}
255 {incr notifications}
256 {set timer-maxmemory-volatile-end 1 PXAT *}
257 {exec}
258 {multi}
259 {incr notifications}
260 {del timer-maxmemory-volatile-*}
261 {exec}
262 {multi}
263 {incr notifications}
264 {del timer-maxmemory-volatile-*}
265 {exec}
266 }
267 close_replication_stream $repl
268
269 $master config set maxmemory 0
270 $master config set maxmemory-policy noeviction
271 }
272
273 test {module propagation with timer and EVAL} {
274 set repl [attach_to_replication_stream]
275
276 $master propagate-test.timer-eval
277
278 assert_replication_stream $repl {
279 {multi}
280 {select *}
281 {incr notifications}
282 {incrby timer-eval-start 1}
283 {incr notifications}
284 {set foo bar}
285 {incr timer-eval-middle}
286 {incr notifications}
287 {incrby timer-eval-end 1}
288 {exec}
289 }
290 close_replication_stream $repl
291 }
292
293 test {module propagates nested ctx case1} {
294 set repl [attach_to_replication_stream]
295
296 $master propagate-test.timer-nested
297
298 wait_for_condition 500 10 {
299 [$replica get timer-nested-end] eq "1"
300 } else {
301 fail "The two counters don't match the expected value."
302 }
303
304 assert_replication_stream $repl {
305 {multi}
306 {select *}
307 {incrby timer-nested-start 1}
308 {incrby timer-nested-end 1}
309 {exec}
310 }
311 close_replication_stream $repl
312
313 # Note propagate-test.timer-nested just propagates INCRBY, causing an
314 # inconsistency, so we flush
315 $master flushall
316 }
317
318 test {module propagates nested ctx case2} {
319 set repl [attach_to_replication_stream]
320
321 $master propagate-test.timer-nested-repl
322
323 wait_for_condition 500 10 {
324 [$replica get timer-nested-end] eq "1"
325 } else {
326 fail "The two counters don't match the expected value."
327 }
328
329 assert_replication_stream $repl {
330 {multi}
331 {select *}
332 {incrby timer-nested-start 1}
333 {incr notifications}
334 {incr using-call}
335 {incr counter-1}
336 {incr counter-2}
337 {incr counter-3}
338 {incr counter-4}
339 {incr notifications}
340 {incr after-call}
341 {incr notifications}
342 {incr before-call-2}
343 {incr notifications}
344 {incr asdf}
345 {incr notifications}
346 {del asdf}
347 {incr notifications}
348 {incr after-call-2}
349 {incr notifications}
350 {incr timer-nested-middle}
351 {incrby timer-nested-end 1}
352 {exec}
353 }
354 close_replication_stream $repl
355
356 # Note propagate-test.timer-nested-repl just propagates INCRBY, causing an
357 # inconsistency, so we flush
358 $master flushall
359 }
360
361 test {module propagates from thread} {
362 set repl [attach_to_replication_stream]
363
364 $master propagate-test.thread
365
366 wait_for_condition 500 10 {
367 [$replica get a-from-thread] eq "3"
368 } else {
369 fail "The two counters don't match the expected value."
370 }
371
372 assert_replication_stream $repl {
373 {multi}
374 {select *}
375 {incr a-from-thread}
376 {incr notifications}
377 {incr thread-call}
378 {incr b-from-thread}
379 {exec}
380 {multi}
381 {incr a-from-thread}
382 {incr notifications}
383 {incr thread-call}
384 {incr b-from-thread}
385 {exec}
386 {multi}
387 {incr a-from-thread}
388 {incr notifications}
389 {incr thread-call}
390 {incr b-from-thread}
391 {exec}
392 }
393 close_replication_stream $repl
394 }
395
396 test {module propagates from thread with detached ctx} {
397 set repl [attach_to_replication_stream]
398
399 $master propagate-test.detached-thread
400
401 wait_for_condition 500 10 {
402 [$replica get thread-detached-after] eq "1"
403 } else {
404 fail "The key doesn't match the expected value."
405 }
406
407 assert_replication_stream $repl {
408 {multi}
409 {select *}
410 {incr thread-detached-before}
411 {incr notifications}
412 {incr thread-detached-1}
413 {incr notifications}
414 {incr thread-detached-2}
415 {incr thread-detached-after}
416 {exec}
417 }
418 close_replication_stream $repl
419 }
420
421 test {module propagates from command} {
422 set repl [attach_to_replication_stream]
423
424 $master propagate-test.simple
425 $master propagate-test.mixed
426
427 assert_replication_stream $repl {
428 {multi}
429 {select *}
430 {incr counter-1}
431 {incr counter-2}
432 {exec}
433 {multi}
434 {incr notifications}
435 {incr using-call}
436 {incr counter-1}
437 {incr counter-2}
438 {incr notifications}
439 {incr after-call}
440 {exec}
441 }
442 close_replication_stream $repl
443 }
444
445 test {module propagates from EVAL} {
446 set repl [attach_to_replication_stream]
447
448 assert_equal [ $master eval { \
449 redis.call("propagate-test.simple"); \
450 redis.call("set", "x", "y"); \
451 redis.call("propagate-test.mixed"); return "OK" } 0 ] {OK}
452
453 assert_replication_stream $repl {
454 {multi}
455 {select *}
456 {incr counter-1}
457 {incr counter-2}
458 {incr notifications}
459 {set x y}
460 {incr notifications}
461 {incr using-call}
462 {incr counter-1}
463 {incr counter-2}
464 {incr notifications}
465 {incr after-call}
466 {exec}
467 }
468 close_replication_stream $repl
469 }
470
471 test {module propagates from command after good EVAL} {
472 set repl [attach_to_replication_stream]
473
474 assert_equal [ $master eval { return "hello" } 0 ] {hello}
475 $master propagate-test.simple
476 $master propagate-test.mixed
477
478 assert_replication_stream $repl {
479 {multi}
480 {select *}
481 {incr counter-1}
482 {incr counter-2}
483 {exec}
484 {multi}
485 {incr notifications}
486 {incr using-call}
487 {incr counter-1}
488 {incr counter-2}
489 {incr notifications}
490 {incr after-call}
491 {exec}
492 }
493 close_replication_stream $repl
494 }
495
496 test {module propagates from command after bad EVAL} {
497 set repl [attach_to_replication_stream]
498
499 catch { $master eval { return "hello" } -12 } e
500 assert_equal $e {ERR Number of keys can't be negative}
501 $master propagate-test.simple
502 $master propagate-test.mixed
503
504 assert_replication_stream $repl {
505 {multi}
506 {select *}
507 {incr counter-1}
508 {incr counter-2}
509 {exec}
510 {multi}
511 {incr notifications}
512 {incr using-call}
513 {incr counter-1}
514 {incr counter-2}
515 {incr notifications}
516 {incr after-call}
517 {exec}
518 }
519 close_replication_stream $repl
520 }
521
522 test {module propagates from multi-exec} {
523 set repl [attach_to_replication_stream]
524
525 $master multi
526 $master propagate-test.simple
527 $master propagate-test.mixed
528 $master propagate-test.timer-nested-repl
529 $master exec
530
531 wait_for_condition 500 10 {
532 [$replica get timer-nested-end] eq "1"
533 } else {
534 fail "The two counters don't match the expected value."
535 }
536
537 assert_replication_stream $repl {
538 {multi}
539 {select *}
540 {incr counter-1}
541 {incr counter-2}
542 {incr notifications}
543 {incr using-call}
544 {incr counter-1}
545 {incr counter-2}
546 {incr notifications}
547 {incr after-call}
548 {exec}
549 {multi}
550 {incrby timer-nested-start 1}
551 {incr notifications}
552 {incr using-call}
553 {incr counter-1}
554 {incr counter-2}
555 {incr counter-3}
556 {incr counter-4}
557 {incr notifications}
558 {incr after-call}
559 {incr notifications}
560 {incr before-call-2}
561 {incr notifications}
562 {incr asdf}
563 {incr notifications}
564 {del asdf}
565 {incr notifications}
566 {incr after-call-2}
567 {incr notifications}
568 {incr timer-nested-middle}
569 {incrby timer-nested-end 1}
570 {exec}
571 }
572 close_replication_stream $repl
573
574 # Note propagate-test.timer-nested just propagates INCRBY, causing an
575 # inconsistency, so we flush
576 $master flushall
577 }
578
579 test {module RM_Call of expired key propagation} {
580 $master debug set-active-expire 0
581
582 $master set k1 900 px 100
583 after 110
584
585 set repl [attach_to_replication_stream]
586 $master propagate-test.incr k1
587
588 assert_replication_stream $repl {
589 {multi}
590 {select *}
591 {del k1}
592 {propagate-test.incr k1}
593 {exec}
594 }
595 close_replication_stream $repl
596
597 assert_equal [$master get k1] 1
598 assert_equal [$master ttl k1] -1
599
600 wait_for_condition 50 100 {
601 [$replica get k1] eq 1 &&
602 [$replica ttl k1] eq -1
603 } else {
604 fail "failed RM_Call of expired key propagation"
605 }
606 }
607
608 test {module notification on set} {
609 set repl [attach_to_replication_stream]
610
611 $master SADD s foo
612
613 wait_for_condition 500 10 {
614 [$replica SCARD s] eq "1"
615 } else {
616 fail "Failed to wait for set to be replicated"
617 }
618
619 $master SPOP s 1
620
621 wait_for_condition 500 10 {
622 [$replica SCARD s] eq "0"
623 } else {
624 fail "Failed to wait for set to be replicated"
625 }
626
627 # Currently the `del` command comes after the notification.
628 # When we fix spop to fire notification at the end (like all other commands),
629 # the `del` will come first.
630 assert_replication_stream $repl {
631 {multi}
632 {select *}
633 {incr notifications}
634 {sadd s foo}
635 {exec}
636 {multi}
637 {incr notifications}
638 {incr notifications}
639 {del s}
640 {exec}
641 }
642 close_replication_stream $repl
643 }
644
645 test {module key miss notification do not cause read command to be replicated} {
646 set repl [attach_to_replication_stream]
647
648 $master flushall
649
650 $master get unexisting_key
651
652 wait_for_condition 500 10 {
653 [$replica get missed] eq "1"
654 } else {
655 fail "Failed to wait for set to be replicated"
656 }
657
658 # Test is checking a wrong!!! behavior that causes a read command to be replicated to replica/aof.
659 # We keep the test to verify that such a wrong behavior does not cause any crashes.
660 assert_replication_stream $repl {
661 {select *}
662 {flushall}
663 {multi}
664 {incr notifications}
665 {incr missed}
666 {get unexisting_key}
667 {exec}
668 }
669
670 close_replication_stream $repl
671 }
672
673 test "Unload the module - propagate-test/testkeyspace" {
674 assert_equal {OK} [r module unload propagate-test]
675 assert_equal {OK} [r module unload testkeyspace]
676 }
677
678 assert_equal [s -1 unexpected_error_replies] 0
679 }
680 }
681 }
682}
683
684
685tags "modules aof external:skip" {
686 foreach aofload_type {debug_cmd startup} {
687 test "Modules RM_Replicate replicates MULTI/EXEC correctly: AOF-load type $aofload_type" {
688 start_server [list overrides [list loadmodule "$testmodule"]] {
689 # Enable the AOF
690 r config set appendonly yes
691 r config set auto-aof-rewrite-percentage 0 ; # Disable auto-rewrite.
692 waitForBgrewriteaof r
693
694 r propagate-test.simple
695 r propagate-test.mixed
696 r multi
697 r propagate-test.simple
698 r propagate-test.mixed
699 r exec
700
701 assert_equal [r get counter-1] {}
702 assert_equal [r get counter-2] {}
703 assert_equal [r get using-call] 2
704 assert_equal [r get after-call] 2
705 assert_equal [r get notifications] 4
706
707 # Load the AOF
708 if {$aofload_type == "debug_cmd"} {
709 r debug loadaof
710 } else {
711 r config rewrite
712 restart_server 0 true false
713 wait_done_loading r
714 }
715
716 # This module behaves bad on purpose, it only calls
717 # RM_Replicate for counter-1 and counter-2 so values
718 # after AOF-load are different
719 assert_equal [r get counter-1] 4
720 assert_equal [r get counter-2] 4
721 assert_equal [r get using-call] 2
722 assert_equal [r get after-call] 2
723 # 4+4+2+2 commands from AOF (just above) + 4 "INCR notifications" from AOF + 4 notifications for these INCRs
724 assert_equal [r get notifications] 20
725
726 assert_equal {OK} [r module unload propagate-test]
727 assert_equal [s 0 unexpected_error_replies] 0
728 }
729 }
730 test "Modules RM_Call does not update stats during aof load: AOF-load type $aofload_type" {
731 start_server [list overrides [list loadmodule "$miscmodule"]] {
732 # Enable the AOF
733 r config set appendonly yes
734 r config set auto-aof-rewrite-percentage 0 ; # Disable auto-rewrite.
735 waitForBgrewriteaof r
736
737 r config resetstat
738 r set foo bar
739 r EVAL {return redis.call('SET', KEYS[1], ARGV[1])} 1 foo bar2
740 r test.rm_call_replicate set foo bar3
741 r EVAL {return redis.call('test.rm_call_replicate',ARGV[1],KEYS[1],ARGV[2])} 1 foo set bar4
742
743 r multi
744 r set foo bar5
745 r EVAL {return redis.call('SET', KEYS[1], ARGV[1])} 1 foo bar6
746 r test.rm_call_replicate set foo bar7
747 r EVAL {return redis.call('test.rm_call_replicate',ARGV[1],KEYS[1],ARGV[2])} 1 foo set bar8
748 r exec
749
750 assert_match {*calls=8,*,rejected_calls=0,failed_calls=0} [cmdrstat set r]
751
752
753 # Load the AOF
754 if {$aofload_type == "debug_cmd"} {
755 r config resetstat
756 r debug loadaof
757 } else {
758 r config rewrite
759 restart_server 0 true false
760 wait_done_loading r
761 }
762
763 assert_no_match {*calls=*} [cmdrstat set r]
764
765 }
766 }
767 }
768}
769
770# This test does not really test module functionality, but rather uses a module
771# command to test Redis replication mechanisms.
772test {Replicas that was marked as CLIENT_CLOSE_ASAP should not keep the replication backlog from been trimmed} {
773 start_server [list overrides [list loadmodule "$testmodule"] tags {"external:skip"}] {
774 set replica [srv 0 client]
775 start_server [list overrides [list loadmodule "$testmodule"] tags {"external:skip"}] {
776 set master [srv 0 client]
777 set master_host [srv 0 host]
778 set master_port [srv 0 port]
779 $master config set client-output-buffer-limit "replica 10mb 5mb 0"
780
781 # Start the replication process...
782 $replica replicaof $master_host $master_port
783 wait_for_sync $replica
784
785 test {module propagates from timer} {
786 # Replicate large commands to make the replica disconnected.
787 $master write [format_command propagate-test.verbatim 100000 [string repeat "a" 1000]] ;# almost 100mb
788 # Execute this command together with module commands within the same
789 # event loop to prevent periodic cleanup of replication backlog.
790 $master write [format_command info memory]
791 $master flush
792 $master read ;# propagate-test.verbatim
793 set res [$master read] ;# info memory
794
795 # Wait for the replica to be disconnected.
796 wait_for_log_messages 0 {"*flags=S*scheduled to be closed ASAP for overcoming of output buffer limits*"} 0 1500 10
797 # Due to the replica reaching the soft limit (5MB), memory peaks should not significantly
798 # exceed the replica soft limit. Furthermore, as the replica release its reference to
799 # replication backlog, it should be properly trimmed, the memory usage of replication
800 # backlog should not significantly exceed repl-backlog-size (default 1MB). */
801 assert_lessthan [getInfoProperty $res used_memory_peak] 20000000;# less than 20mb
802 assert_lessthan [getInfoProperty $res mem_replication_backlog] 2000000;# less than 2mb
803 }
804 }
805 }
806}