summaryrefslogtreecommitdiff
path: root/examples/redis-unstable/tests/unit/multi.tcl
diff options
context:
space:
mode:
Diffstat (limited to 'examples/redis-unstable/tests/unit/multi.tcl')
-rw-r--r--examples/redis-unstable/tests/unit/multi.tcl925
1 files changed, 925 insertions, 0 deletions
diff --git a/examples/redis-unstable/tests/unit/multi.tcl b/examples/redis-unstable/tests/unit/multi.tcl
new file mode 100644
index 0000000..4e8e807
--- /dev/null
+++ b/examples/redis-unstable/tests/unit/multi.tcl
@@ -0,0 +1,925 @@
1proc wait_for_dbsize {size} {
2 set r2 [redis_client]
3 wait_for_condition 50 100 {
4 [$r2 dbsize] == $size
5 } else {
6 fail "Target dbsize not reached"
7 }
8 $r2 close
9}
10
11start_server {tags {"multi"}} {
12 test {MULTI / EXEC basics} {
13 r del mylist
14 r rpush mylist a
15 r rpush mylist b
16 r rpush mylist c
17 r multi
18 set v1 [r lrange mylist 0 -1]
19 set v2 [r ping]
20 set v3 [r exec]
21 list $v1 $v2 $v3
22 } {QUEUED QUEUED {{a b c} PONG}}
23
24 test {DISCARD} {
25 r del mylist
26 r rpush mylist a
27 r rpush mylist b
28 r rpush mylist c
29 r multi
30 set v1 [r del mylist]
31 set v2 [r discard]
32 set v3 [r lrange mylist 0 -1]
33 list $v1 $v2 $v3
34 } {QUEUED OK {a b c}}
35
36 test {Nested MULTI are not allowed} {
37 set err {}
38 r multi
39 catch {[r multi]} err
40 r exec
41 set _ $err
42 } {*ERR MULTI*}
43
44 test {MULTI where commands alter argc/argv} {
45 r sadd myset a
46 r multi
47 r spop myset
48 list [r exec] [r exists myset]
49 } {a 0}
50
51 test {WATCH inside MULTI is not allowed} {
52 set err {}
53 r multi
54 catch {[r watch x]} err
55 r exec
56 set _ $err
57 } {*ERR WATCH*}
58
59 test {EXEC fails if there are errors while queueing commands #1} {
60 r del foo1{t} foo2{t}
61 r multi
62 r set foo1{t} bar1
63 catch {r non-existing-command}
64 r set foo2{t} bar2
65 catch {r exec} e
66 assert_match {EXECABORT*} $e
67 list [r exists foo1{t}] [r exists foo2{t}]
68 } {0 0}
69
70 test {EXEC fails if there are errors while queueing commands #2} {
71 set rd [redis_deferring_client]
72 r del foo1{t} foo2{t}
73 r multi
74 r set foo1{t} bar1
75 $rd config set maxmemory 1
76 assert {[$rd read] eq {OK}}
77 catch {r lpush mylist{t} myvalue}
78 $rd config set maxmemory 0
79 assert {[$rd read] eq {OK}}
80 r set foo2{t} bar2
81 catch {r exec} e
82 assert_match {EXECABORT*} $e
83 $rd close
84 list [r exists foo1{t}] [r exists foo2{t}]
85 } {0 0} {needs:config-maxmemory}
86
87 test {If EXEC aborts, the client MULTI state is cleared} {
88 r del foo1{t} foo2{t}
89 r multi
90 r set foo1{t} bar1
91 catch {r non-existing-command}
92 r set foo2{t} bar2
93 catch {r exec} e
94 assert_match {EXECABORT*} $e
95 r ping
96 } {PONG}
97
98 test {EXEC works on WATCHed key not modified} {
99 r watch x{t} y{t} z{t}
100 r watch k{t}
101 r multi
102 r ping
103 r exec
104 } {PONG}
105
106 test {EXEC fail on WATCHed key modified (1 key of 1 watched)} {
107 r set x 30
108 r watch x
109 r set x 40
110 r multi
111 r ping
112 r exec
113 } {}
114
115 test {EXEC fail on WATCHed key modified (1 key of 5 watched)} {
116 r set x{t} 30
117 r watch a{t} b{t} x{t} k{t} z{t}
118 r set x{t} 40
119 r multi
120 r ping
121 r exec
122 } {}
123
124 test {EXEC fail on WATCHed key modified by SORT with STORE even if the result is empty} {
125 r flushdb
126 r lpush foo bar
127 r watch foo
128 r sort emptylist store foo
129 r multi
130 r ping
131 r exec
132 } {} {cluster:skip}
133
134 test {EXEC fail on lazy expired WATCHed key} {
135 r del key
136 r debug set-active-expire 0
137
138 for {set j 0} {$j < 10} {incr j} {
139 r set key 1 px 100
140 r watch key
141 after 101
142 r multi
143 r incr key
144
145 set res [r exec]
146 if {$res eq {}} break
147 }
148 if {$::verbose} { puts "EXEC fail on lazy expired WATCHed key attempts: $j" }
149
150 r debug set-active-expire 1
151 set _ $res
152 } {} {needs:debug}
153
154 test {WATCH stale keys should not fail EXEC} {
155 r del x
156 r debug set-active-expire 0
157 r set x foo px 1
158 after 2
159 r watch x
160 r multi
161 r ping
162 assert_equal {PONG} [r exec]
163 r debug set-active-expire 1
164 } {OK} {needs:debug}
165
166 test {Delete WATCHed stale keys should not fail EXEC} {
167 r del x
168 r debug set-active-expire 0
169 r set x foo px 1
170 after 2
171 r watch x
172 # EXISTS triggers lazy expiry/deletion
173 assert_equal 0 [r exists x]
174 r multi
175 r ping
176 assert_equal {PONG} [r exec]
177 r debug set-active-expire 1
178 } {OK} {needs:debug}
179
180 test {FLUSHDB while watching stale keys should not fail EXEC} {
181 r del x
182 r debug set-active-expire 0
183 r set x foo px 1
184 after 2
185 r watch x
186 r flushdb
187 r multi
188 r ping
189 assert_equal {PONG} [r exec]
190 r debug set-active-expire 1
191 } {OK} {needs:debug}
192
193 test {After successful EXEC key is no longer watched} {
194 r set x 30
195 r watch x
196 r multi
197 r ping
198 r exec
199 r set x 40
200 r multi
201 r ping
202 r exec
203 } {PONG}
204
205 test {After failed EXEC key is no longer watched} {
206 r set x 30
207 r watch x
208 r set x 40
209 r multi
210 r ping
211 r exec
212 r set x 40
213 r multi
214 r ping
215 r exec
216 } {PONG}
217
218 test {It is possible to UNWATCH} {
219 r set x 30
220 r watch x
221 r set x 40
222 r unwatch
223 r multi
224 r ping
225 r exec
226 } {PONG}
227
228 test {UNWATCH when there is nothing watched works as expected} {
229 r unwatch
230 } {OK}
231
232 test {FLUSHALL is able to touch the watched keys} {
233 r set x 30
234 r watch x
235 r flushall
236 r multi
237 r ping
238 r exec
239 } {}
240
241 test {FLUSHALL does not touch non affected keys} {
242 r del x
243 r watch x
244 r flushall
245 r multi
246 r ping
247 r exec
248 } {PONG}
249
250 test {FLUSHDB is able to touch the watched keys} {
251 r set x 30
252 r watch x
253 r flushdb
254 r multi
255 r ping
256 r exec
257 } {}
258
259 test {FLUSHDB does not touch non affected keys} {
260 r del x
261 r watch x
262 r flushdb
263 r multi
264 r ping
265 r exec
266 } {PONG}
267
268 test {SWAPDB is able to touch the watched keys that exist} {
269 r flushall
270 r select 0
271 r set x 30
272 r watch x ;# make sure x (set to 30) doesn't change (SWAPDB will "delete" it)
273 r swapdb 0 1
274 r multi
275 r ping
276 r exec
277 } {} {singledb:skip}
278
279 test {SWAPDB is able to touch the watched keys that do not exist} {
280 r flushall
281 r select 1
282 r set x 30
283 r select 0
284 r watch x ;# make sure the key x (currently missing) doesn't change (SWAPDB will create it)
285 r swapdb 0 1
286 r multi
287 r ping
288 r exec
289 } {} {singledb:skip}
290
291 test {SWAPDB does not touch watched stale keys} {
292 r flushall
293 r select 1
294 r debug set-active-expire 0
295 r set x foo px 1
296 after 2
297 r watch x
298 r swapdb 0 1 ; # expired key replaced with no key => no change
299 r multi
300 r ping
301 assert_equal {PONG} [r exec]
302 r debug set-active-expire 1
303 } {OK} {singledb:skip needs:debug}
304
305 test {SWAPDB does not touch non-existing key replaced with stale key} {
306 r flushall
307 r select 0
308 r debug set-active-expire 0
309 r set x foo px 1
310 after 2
311 r select 1
312 r watch x
313 r swapdb 0 1 ; # no key replaced with expired key => no change
314 r multi
315 r ping
316 assert_equal {PONG} [r exec]
317 r debug set-active-expire 1
318 } {OK} {singledb:skip needs:debug}
319
320 test {SWAPDB does not touch stale key replaced with another stale key} {
321 r flushall
322 r debug set-active-expire 0
323 r select 1
324 r set x foo px 1
325 r select 0
326 r set x bar px 1
327 after 2
328 r select 1
329 r watch x
330 r swapdb 0 1 ; # no key replaced with expired key => no change
331 r multi
332 r ping
333 assert_equal {PONG} [r exec]
334 r debug set-active-expire 1
335 } {OK} {singledb:skip needs:debug}
336
337 test {WATCH is able to remember the DB a key belongs to} {
338 r select 5
339 r set x 30
340 r watch x
341 r select 1
342 r set x 10
343 r select 5
344 r multi
345 r ping
346 set res [r exec]
347 # Restore original DB
348 r select 9
349 set res
350 } {PONG} {singledb:skip}
351
352 test {WATCH will consider touched keys target of EXPIRE} {
353 r del x
354 r set x foo
355 r watch x
356 r expire x 10
357 r multi
358 r ping
359 r exec
360 } {}
361
362 test {WATCH will consider touched expired keys} {
363 r flushall
364 r del x
365 r set x foo
366 r expire x 1
367 r watch x
368
369 # Wait for the keys to expire.
370 wait_for_dbsize 0
371
372 r multi
373 r ping
374 r exec
375 } {}
376
377 test {DISCARD should clear the WATCH dirty flag on the client} {
378 r watch x
379 r set x 10
380 r multi
381 r discard
382 r multi
383 r incr x
384 r exec
385 } {11}
386
387 test {DISCARD should UNWATCH all the keys} {
388 r watch x
389 r set x 10
390 r multi
391 r discard
392 r set x 10
393 r multi
394 r incr x
395 r exec
396 } {11}
397
398 test {MULTI / EXEC is not propagated (single write command)} {
399 set repl [attach_to_replication_stream]
400 r multi
401 r set foo bar
402 r exec
403 r set foo2 bar
404 assert_replication_stream $repl {
405 {select *}
406 {set foo bar}
407 {set foo2 bar}
408 }
409 close_replication_stream $repl
410 } {} {needs:repl}
411
412 test {MULTI / EXEC is propagated correctly (multiple commands)} {
413 set repl [attach_to_replication_stream]
414 r multi
415 r set foo{t} bar
416 r get foo{t}
417 r set foo2{t} bar2
418 r get foo2{t}
419 r set foo3{t} bar3
420 r get foo3{t}
421 r exec
422
423 assert_replication_stream $repl {
424 {multi}
425 {select *}
426 {set foo{t} bar}
427 {set foo2{t} bar2}
428 {set foo3{t} bar3}
429 {exec}
430 }
431 close_replication_stream $repl
432 } {} {needs:repl}
433
434 test {MULTI / EXEC is propagated correctly (multiple commands with SELECT)} {
435 set repl [attach_to_replication_stream]
436 r multi
437 r select 1
438 r set foo{t} bar
439 r get foo{t}
440 r select 2
441 r set foo2{t} bar2
442 r get foo2{t}
443 r select 3
444 r set foo3{t} bar3
445 r get foo3{t}
446 r exec
447
448 assert_replication_stream $repl {
449 {multi}
450 {select *}
451 {set foo{t} bar}
452 {select *}
453 {set foo2{t} bar2}
454 {select *}
455 {set foo3{t} bar3}
456 {exec}
457 }
458 close_replication_stream $repl
459 } {} {needs:repl singledb:skip}
460
461 test {MULTI / EXEC is propagated correctly (empty transaction)} {
462 set repl [attach_to_replication_stream]
463 r multi
464 r exec
465 r set foo bar
466 assert_replication_stream $repl {
467 {select *}
468 {set foo bar}
469 }
470 close_replication_stream $repl
471 } {} {needs:repl}
472
473 test {MULTI / EXEC is propagated correctly (read-only commands)} {
474 r set foo value1
475 set repl [attach_to_replication_stream]
476 r multi
477 r get foo
478 r exec
479 r set foo value2
480 assert_replication_stream $repl {
481 {select *}
482 {set foo value2}
483 }
484 close_replication_stream $repl
485 } {} {needs:repl}
486
487 test {MULTI / EXEC is propagated correctly (write command, no effect)} {
488 r del bar
489 r del foo
490 set repl [attach_to_replication_stream]
491 r multi
492 r del foo
493 r exec
494
495 # add another command so that when we see it we know multi-exec wasn't
496 # propagated
497 r incr foo
498
499 assert_replication_stream $repl {
500 {select *}
501 {incr foo}
502 }
503 close_replication_stream $repl
504 } {} {needs:repl}
505
506 test {MULTI / EXEC with REPLICAOF} {
507 # This test verifies that if we demote a master to replica inside a transaction, the
508 # entire transaction is not propagated to the already-connected replica
509 set repl [attach_to_replication_stream]
510 r set foo bar
511 r multi
512 r set foo2 bar
513 r replicaof localhost 9999
514 r set foo3 bar
515 r exec
516 catch {r set foo4 bar} e
517 assert_match {READONLY*} $e
518 assert_replication_stream $repl {
519 {select *}
520 {set foo bar}
521 }
522 r replicaof no one
523 } {OK} {needs:repl cluster:skip}
524
525 test {DISCARD should not fail during OOM} {
526 set rd [redis_deferring_client]
527 $rd config set maxmemory 1
528 assert {[$rd read] eq {OK}}
529 r multi
530 catch {r set x 1} e
531 assert_match {OOM*} $e
532 r discard
533 $rd config set maxmemory 0
534 assert {[$rd read] eq {OK}}
535 $rd close
536 r ping
537 } {PONG} {needs:config-maxmemory}
538
539 test {MULTI and script timeout} {
540 # check that if MULTI arrives during timeout, it is either refused, or
541 # allowed to pass, and we don't end up executing half of the transaction
542 set rd1 [redis_deferring_client]
543 set r2 [redis_client]
544 r config set lua-time-limit 10
545 r set xx 1
546 $rd1 eval {while true do end} 0
547 after 200
548 catch { $r2 multi; } e
549 catch { $r2 incr xx; } e
550 r script kill
551 after 200 ; # Give some time to Lua to call the hook again...
552 catch { $r2 incr xx; } e
553 catch { $r2 exec; } e
554 assert_match {EXECABORT*previous errors*} $e
555 set xx [r get xx]
556 # make sure that either the whole transcation passed or none of it (we actually expect none)
557 assert { $xx == 1 || $xx == 3}
558 # check that the connection is no longer in multi state
559 set pong [$r2 ping asdf]
560 assert_equal $pong "asdf"
561 $rd1 close; $r2 close
562 }
563
564 test {EXEC and script timeout} {
565 # check that if EXEC arrives during timeout, we don't end up executing
566 # half of the transaction, and also that we exit the multi state
567 set rd1 [redis_deferring_client]
568 set r2 [redis_client]
569 r config set lua-time-limit 10
570 r set xx 1
571 catch { $r2 multi; } e
572 catch { $r2 incr xx; } e
573 $rd1 eval {while true do end} 0
574 after 200
575 catch { $r2 incr xx; } e
576 catch { $r2 exec; } e
577 assert_match {EXECABORT*BUSY*} $e
578 r script kill
579 after 200 ; # Give some time to Lua to call the hook again...
580 set xx [r get xx]
581 # make sure that either the whole transcation passed or none of it (we actually expect none)
582 assert { $xx == 1 || $xx == 3}
583 # check that the connection is no longer in multi state
584 set pong [$r2 ping asdf]
585 assert_equal $pong "asdf"
586 $rd1 close; $r2 close
587 }
588
589 test {MULTI-EXEC body and script timeout} {
590 # check that we don't run an incomplete transaction due to some commands
591 # arriving during busy script
592 set rd1 [redis_deferring_client]
593 set r2 [redis_client]
594 r config set lua-time-limit 10
595 r set xx 1
596 catch { $r2 multi; } e
597 catch { $r2 incr xx; } e
598 $rd1 eval {while true do end} 0
599 after 200
600 catch { $r2 incr xx; } e
601 r script kill
602 after 200 ; # Give some time to Lua to call the hook again...
603 catch { $r2 exec; } e
604 assert_match {EXECABORT*previous errors*} $e
605 set xx [r get xx]
606 # make sure that either the whole transcation passed or none of it (we actually expect none)
607 assert { $xx == 1 || $xx == 3}
608 # check that the connection is no longer in multi state
609 set pong [$r2 ping asdf]
610 assert_equal $pong "asdf"
611 $rd1 close; $r2 close
612 }
613
614 test {just EXEC and script timeout} {
615 # check that if EXEC arrives during timeout, we don't end up executing
616 # actual commands during busy script, and also that we exit the multi state
617 set rd1 [redis_deferring_client]
618 set r2 [redis_client]
619 r config set lua-time-limit 10
620 r set xx 1
621 catch { $r2 multi; } e
622 catch { $r2 incr xx; } e
623 $rd1 eval {while true do end} 0
624 after 200
625 catch { $r2 exec; } e
626 assert_match {EXECABORT*BUSY*} $e
627 r script kill
628 after 200 ; # Give some time to Lua to call the hook again...
629 set xx [r get xx]
630 # make we didn't execute the transaction
631 assert { $xx == 1}
632 # check that the connection is no longer in multi state
633 set pong [$r2 ping asdf]
634 assert_equal $pong "asdf"
635 $rd1 close; $r2 close
636 }
637
638 test {exec with write commands and state change} {
639 # check that exec that contains write commands fails if server state changed since they were queued
640 set r1 [redis_client]
641 r set xx 1
642 r multi
643 r incr xx
644 $r1 config set min-replicas-to-write 2
645 catch {r exec} e
646 assert_match {*EXECABORT*NOREPLICAS*} $e
647 set xx [r get xx]
648 # make sure that the INCR wasn't executed
649 assert { $xx == 1}
650 $r1 config set min-replicas-to-write 0
651 $r1 close
652 } {0} {needs:repl}
653
654 test {exec with read commands and stale replica state change} {
655 # check that exec that contains read commands fails if server state changed since they were queued
656 r config set replica-serve-stale-data no
657 set r1 [redis_client]
658 r set xx 1
659
660 # check that GET and PING are disallowed on stale replica, even if the replica becomes stale only after queuing.
661 r multi
662 r get xx
663 $r1 replicaof localhsot 0
664 catch {r exec} e
665 assert_match {*EXECABORT*MASTERDOWN*} $e
666
667 # reset
668 $r1 replicaof no one
669
670 r multi
671 r ping
672 $r1 replicaof localhsot 0
673 catch {r exec} e
674 assert_match {*EXECABORT*MASTERDOWN*} $e
675
676 # check that when replica is not stale, GET is allowed
677 # while we're at it, let's check that multi is allowed on stale replica too
678 r multi
679 $r1 replicaof no one
680 r get xx
681 set xx [r exec]
682 # make sure that the INCR was executed
683 assert { $xx == 1 }
684 $r1 close
685 } {0} {needs:repl cluster:skip}
686
687 test {EXEC with only read commands should not be rejected when OOM} {
688 set r2 [redis_client]
689
690 r set x value
691 r multi
692 r get x
693 r ping
694
695 # enforcing OOM
696 $r2 config set maxmemory 1
697
698 # finish the multi transaction with exec
699 assert { [r exec] == {value PONG} }
700
701 # releasing OOM
702 $r2 config set maxmemory 0
703 $r2 close
704 } {0} {needs:config-maxmemory}
705
706 test {EXEC with at least one use-memory command should fail} {
707 set r2 [redis_client]
708
709 r multi
710 r set x 1
711 r get x
712
713 # enforcing OOM
714 $r2 config set maxmemory 1
715
716 # finish the multi transaction with exec
717 catch {r exec} e
718 assert_match {EXECABORT*OOM*} $e
719
720 # releasing OOM
721 $r2 config set maxmemory 0
722 $r2 close
723 } {0} {needs:config-maxmemory}
724
725 test {Blocking commands ignores the timeout} {
726 r xgroup create s{t} g $ MKSTREAM
727
728 set m [r multi]
729 r blpop empty_list{t} 0
730 r brpop empty_list{t} 0
731 r brpoplpush empty_list1{t} empty_list2{t} 0
732 r blmove empty_list1{t} empty_list2{t} LEFT LEFT 0
733 r bzpopmin empty_zset{t} 0
734 r bzpopmax empty_zset{t} 0
735 r xread BLOCK 0 STREAMS s{t} $
736 r xreadgroup group g c BLOCK 0 STREAMS s{t} >
737 set res [r exec]
738
739 list $m $res
740 } {OK {{} {} {} {} {} {} {} {}}}
741
742 test {MULTI propagation of PUBLISH} {
743 set repl [attach_to_replication_stream]
744
745 r multi
746 r publish bla bla
747 r exec
748
749 assert_replication_stream $repl {
750 {select *}
751 {publish bla bla}
752 }
753 close_replication_stream $repl
754 } {} {needs:repl cluster:skip}
755
756 test {MULTI propagation of SCRIPT LOAD} {
757 set repl [attach_to_replication_stream]
758
759 # make sure that SCRIPT LOAD inside MULTI isn't propagated
760 r multi
761 r script load {redis.call('set', KEYS[1], 'foo')}
762 r set foo bar
763 set res [r exec]
764 set sha [lindex $res 0]
765
766 assert_replication_stream $repl {
767 {select *}
768 {set foo bar}
769 }
770 close_replication_stream $repl
771 } {} {needs:repl}
772
773 test {MULTI propagation of EVAL} {
774 set repl [attach_to_replication_stream]
775
776 # make sure that EVAL inside MULTI is propagated in a transaction in effects
777 r multi
778 r eval {redis.call('set', KEYS[1], 'bar')} 1 bar
779 r exec
780
781 assert_replication_stream $repl {
782 {select *}
783 {set bar bar}
784 }
785 close_replication_stream $repl
786 } {} {needs:repl}
787
788 test {MULTI propagation of SCRIPT FLUSH} {
789 set repl [attach_to_replication_stream]
790
791 # make sure that SCRIPT FLUSH isn't propagated
792 r multi
793 r script flush
794 r set foo bar
795 r exec
796
797 assert_replication_stream $repl {
798 {select *}
799 {set foo bar}
800 }
801 close_replication_stream $repl
802 } {} {needs:repl}
803
804 tags {"stream"} {
805 test {MULTI propagation of XREADGROUP} {
806 set repl [attach_to_replication_stream]
807
808 r XADD mystream * foo bar
809 r XADD mystream * foo2 bar2
810 r XADD mystream * foo3 bar3
811 r XGROUP CREATE mystream mygroup 0
812
813 # make sure the XCALIM (propagated by XREADGROUP) is indeed inside MULTI/EXEC
814 r multi
815 r XREADGROUP GROUP mygroup consumer1 COUNT 2 STREAMS mystream ">"
816 r XREADGROUP GROUP mygroup consumer1 STREAMS mystream ">"
817 r exec
818
819 assert_replication_stream $repl {
820 {select *}
821 {xadd *}
822 {xadd *}
823 {xadd *}
824 {xgroup CREATE *}
825 {multi}
826 {xclaim *}
827 {xclaim *}
828 {xgroup SETID * ENTRIESREAD *}
829 {xclaim *}
830 {xgroup SETID * ENTRIESREAD *}
831 {exec}
832 }
833 close_replication_stream $repl
834 } {} {needs:repl}
835 }
836
837 foreach {cmd} {SAVE SHUTDOWN} {
838 test "MULTI with $cmd" {
839 r del foo
840 r multi
841 r set foo bar
842 catch {r $cmd} e1
843 catch {r exec} e2
844 assert_match {*Command not allowed inside a transaction*} $e1
845 assert_match {EXECABORT*} $e2
846 r get foo
847 } {}
848 }
849
850 test "MULTI with BGREWRITEAOF" {
851 set forks [s total_forks]
852 r multi
853 r set foo bar
854 r BGREWRITEAOF
855 set res [r exec]
856 assert_match "*rewriting scheduled*" [lindex $res 1]
857 wait_for_condition 50 100 {
858 [s total_forks] > $forks
859 } else {
860 fail "aofrw didn't start"
861 }
862 waitForBgrewriteaof r
863 } {} {external:skip}
864
865 test "MULTI with config set appendonly" {
866 set lines [count_log_lines 0]
867 set forks [s total_forks]
868 r multi
869 r set foo bar
870 r config set appendonly yes
871 r exec
872 verify_log_message 0 "*AOF background was scheduled*" $lines
873 wait_for_condition 50 100 {
874 [s total_forks] > $forks
875 } else {
876 fail "aofrw didn't start"
877 }
878 waitForBgrewriteaof r
879 } {} {external:skip}
880
881 test "MULTI with config error" {
882 r multi
883 r set foo bar
884 r config set maxmemory bla
885
886 # letting the redis parser read it, it'll throw an exception instead of
887 # reply with an array that contains an error, so we switch to reading
888 # raw RESP instead
889 r readraw 1
890
891 set res [r exec]
892 assert_equal $res "*2"
893 set res [r read]
894 assert_equal $res "+OK"
895 set res [r read]
896 r readraw 0
897 set _ $res
898 } {*CONFIG SET failed*}
899
900 test "Flushall while watching several keys by one client" {
901 r flushall
902 r mset a{t} a b{t} b
903 r watch b{t} a{t}
904 r flushall
905 r ping
906 }
907}
908
909start_server {overrides {appendonly {yes} appendfilename {appendonly.aof} appendfsync always} tags {external:skip}} {
910 test {MULTI with FLUSHALL and AOF} {
911 set aof [get_last_incr_aof_path r]
912 r multi
913 r set foo bar
914 r flushall
915 r exec
916 assert_aof_content $aof {
917 {multi}
918 {select *}
919 {set *}
920 {flushall}
921 {exec}
922 }
923 r get foo
924 } {}
925}