From 5b8350aaaa1b10efc49ee6b3c15a0559c69c9b20 Mon Sep 17 00:00:00 2001
From: Yossi Gottlieb <yossigo@gmail.com>
Date: Sun, 7 Feb 2021 12:37:24 +0200
Subject: [PATCH] Add --dump-logs tests option. (#8459)

Dump the entire server log if a test failed, to easy troubleshooting
with no access to log files.
---
 .github/workflows/daily.yml | 24 ++++++++++++------------
 tests/support/server.tcl    | 14 ++++++++++++++
 tests/test_helper.tcl       |  4 ++++
 3 files changed, 30 insertions(+), 12 deletions(-)

diff --git a/.github/workflows/daily.yml b/.github/workflows/daily.yml
index 589694f38..e3cb1a344 100644
--- a/.github/workflows/daily.yml
+++ b/.github/workflows/daily.yml
@@ -21,7 +21,7 @@ jobs:
     - name: test
       run: |
         sudo apt-get install tcl8.5
-        ./runtest --accurate --verbose
+        ./runtest --accurate --verbose --dump-logs
     - name: module api test
       run: ./runtest-moduleapi --verbose
     - name: sentinel tests
@@ -40,7 +40,7 @@ jobs:
     - name: test
       run: |
         sudo apt-get install tcl8.5
-        ./runtest --accurate --verbose
+        ./runtest --accurate --verbose --dump-logs
     - name: module api test
       run: ./runtest-moduleapi --verbose
     - name: sentinel tests
@@ -61,7 +61,7 @@ jobs:
     - name: test
       run: |
         sudo apt-get install tcl8.5
-        ./runtest --accurate --verbose
+        ./runtest --accurate --verbose --dump-logs
     - name: module api test
       run: |
         make -C tests/modules 32bit # the script below doesn't have an argument, we must build manually ahead of time
@@ -84,8 +84,8 @@ jobs:
       run: |
         sudo apt-get install tcl8.5 tcl-tls
         ./utils/gen-test-certs.sh
-        ./runtest --accurate --verbose --tls
-        ./runtest --accurate --verbose
+        ./runtest --accurate --verbose --tls --dump-logs
+        ./runtest --accurate --verbose --dump-logs
     - name: module api test
       run: |
         ./runtest-moduleapi --verbose --tls
@@ -111,7 +111,7 @@ jobs:
     - name: test
       run: |
         sudo apt-get install tcl8.5 tcl-tls
-        ./runtest --config io-threads 4 --config io-threads-do-reads yes --accurate --verbose --tags network
+        ./runtest --config io-threads 4 --config io-threads-do-reads yes --accurate --verbose --tags network --dump-logs
     - name: cluster tests
       run: |
         ./runtest-cluster --config io-threads 4 --config io-threads-do-reads yes
@@ -128,7 +128,7 @@ jobs:
       run: |
         sudo apt-get update
         sudo apt-get install tcl8.5 valgrind -y
-        ./runtest --valgrind --verbose --clients 1
+        ./runtest --valgrind --verbose --clients 1 --dump-logs
     - name: module api test
       run: ./runtest-moduleapi --valgrind --verbose --clients 1
 
@@ -146,7 +146,7 @@ jobs:
     - name: test
       run: |
         yum -y install which tcl
-        ./runtest --accurate --verbose
+        ./runtest --accurate --verbose --dump-logs
     - name: module api test
       run: ./runtest-moduleapi --verbose
     - name: sentinel tests
@@ -170,8 +170,8 @@ jobs:
       run: |
         yum -y install tcl tcltls
         ./utils/gen-test-certs.sh
-        ./runtest --accurate --verbose --tls
-        ./runtest --accurate --verbose
+        ./runtest --accurate --verbose --tls --dump-logs
+        ./runtest --accurate --verbose --dump-logs
     - name: module api test
       run: |
         ./runtest-moduleapi --verbose --tls
@@ -195,7 +195,7 @@ jobs:
       run: make
     - name: test
       run: |
-        ./runtest --accurate --verbose --no-latency
+        ./runtest --accurate --verbose --no-latency --dump-logs
     - name: module api test
       run: ./runtest-moduleapi --verbose
     - name: sentinel tests
@@ -217,7 +217,7 @@ jobs:
         prepare: pkg install -y bash gmake lang/tcl86
         run: >
           gmake &&
-          ./runtest --accurate --verbose --no-latency &&
+          ./runtest --accurate --verbose --no-latency --dump-logs &&
           MAKE=gmake ./runtest-moduleapi --verbose &&
           ./runtest-sentinel &&
           ./runtest-cluster
diff --git a/tests/support/server.tcl b/tests/support/server.tcl
index 0d36d46be..4fbb99920 100644
--- a/tests/support/server.tcl
+++ b/tests/support/server.tcl
@@ -259,6 +259,13 @@ proc wait_server_started {config_file stdout pid} {
     return $port_busy
 }
 
+proc dump_server_log {srv} {
+    set pid [dict get $srv "pid"]
+    puts "\n===== Start of server log (pid $pid) =====\n"
+    puts [exec cat [dict get $srv "stdout"]]
+    puts "===== End of server log (pid $pid) =====\n"
+}
+
 proc start_server {options {code undefined}} {
     # setup defaults
     set baseconfig "default.conf"
@@ -492,6 +499,9 @@ proc start_server {options {code undefined}} {
         # connect client (after server dict is put on the stack)
         reconnect
 
+        # remember previous num_failed to catch new errors
+        set prev_num_failed $::num_failed
+
         # execute provided block
         set num_tests $::num_tests
         if {[catch { uplevel 1 $code } error]} {
@@ -529,6 +539,10 @@ proc start_server {options {code undefined}} {
                 # Re-raise, let handler up the stack take care of this.
                 error $error $backtrace
             }
+        } else {
+            if {$::dump_logs && $prev_num_failed != $::num_failed} {
+                dump_server_log $srv
+            }
         }
 
         # fetch srv back from the server list, in case it was restarted by restart_server (new PID)
diff --git a/tests/test_helper.tcl b/tests/test_helper.tcl
index 2b7854780..eb14b5ee9 100644
--- a/tests/test_helper.tcl
+++ b/tests/test_helper.tcl
@@ -110,6 +110,7 @@ set ::active_servers {} ; # Pids of active Redis instances.
 set ::dont_clean 0
 set ::wait_server 0
 set ::stop_on_failure 0
+set ::dump_logs 0
 set ::loop 0
 set ::tlsdir "tests/tls"
 
@@ -555,6 +556,7 @@ proc print_help_screen {} {
         "--stop             Blocks once the first test fails."
         "--loop             Execute the specified set of tests forever."
         "--wait-server      Wait after server is started (so that you can attach a debugger)."
+        "--dump-logs        Dump server log on test failure."
         "--tls              Run tests in TLS mode."
         "--host <addr>      Run tests against an external host."
         "--port <port>      TCP port to use against external host."
@@ -657,6 +659,8 @@ for {set j 0} {$j < [llength $argv]} {incr j} {
         set ::no_latency 1
     } elseif {$opt eq {--wait-server}} {
         set ::wait_server 1
+    } elseif {$opt eq {--dump-logs}} {
+        set ::dump_logs 1
     } elseif {$opt eq {--stop}} {
         set ::stop_on_failure 1
     } elseif {$opt eq {--loop}} {