This is an automated email from the ASF dual-hosted git repository.

twice pushed a commit to branch unstable
in repository https://gitbox.apache.org/repos/asf/incubator-kvrocks.git


The following commit(s) were added to refs/heads/unstable by this push:
     new 8e3a0ae  Move `runtest` to `x.py` with customized server/cli path 
(#765)
8e3a0ae is described below

commit 8e3a0ae0b806546fa844b48282b02abdb41b4186
Author: Twice <[email protected]>
AuthorDate: Wed Aug 3 15:39:57 2022 +0800

    Move `runtest` to `x.py` with customized server/cli path (#765)
---
 .github/workflows/kvrocks.yaml     |  4 +--
 tests/tcl/runtest                  | 18 ----------
 tests/tcl/tests/support/cli.tcl    |  4 +--
 tests/tcl/tests/support/server.tcl |  6 ++--
 tests/tcl/tests/test_helper.tcl    | 11 ++++++
 x.py                               | 73 +++++++++++++++++++++++++++-----------
 6 files changed, 70 insertions(+), 46 deletions(-)

diff --git a/.github/workflows/kvrocks.yaml b/.github/workflows/kvrocks.yaml
index 432e03e..a6106ff 100644
--- a/.github/workflows/kvrocks.yaml
+++ b/.github/workflows/kvrocks.yaml
@@ -163,9 +163,7 @@ jobs:
       - name: Run Redis Tcl Test
         run: |
           export ${{ matrix.runtime_env_vars }}
-          cp $HOME/local/bin/redis-cli tests/tcl/redis-cli
-          cd tests/tcl
-          ./runtest --dont-clean
+          ./x.py test tcl build --cli-path $HOME/local/bin/redis-cli 
--dont-clean
           SANITIZER_OUTPUT=$(grep "Sanitizer:" tests/tmp -r || true)
           if [[ $SANITIZER_OUTPUT ]]; then
             echo "$SANITIZER_OUTPUT"
diff --git a/tests/tcl/runtest b/tests/tcl/runtest
deleted file mode 100755
index 83bae7b..0000000
--- a/tests/tcl/runtest
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/sh
-TCL_VERSIONS="8.5 8.6"
-TCLSH=""
-
-for VERSION in $TCL_VERSIONS; do
- TCL=`which tclsh$VERSION 2>/dev/null` && TCLSH=$TCL
-done
-
-if [ -z $TCLSH ]
-then
-    echo "You need tcl 8.5 or newer in order to run the Redis test"
-    exit 1
-fi
-
-cp ../../build/kvrocks redis-server && $TCLSH tests/test_helper.tcl "${@}"
-status=$?
-rm ./redis-server
-exit $status
diff --git a/tests/tcl/tests/support/cli.tcl b/tests/tcl/tests/support/cli.tcl
index abf43d9..d6ebad8 100644
--- a/tests/tcl/tests/support/cli.tcl
+++ b/tests/tcl/tests/support/cli.tcl
@@ -36,7 +36,7 @@ proc rediscli_tls_config {testsdir} {
 
 # Returns command line for executing redis-cli
 proc rediscli {host port {opts {}}} {
-    set cmd [list ./redis-cli -h $host -p $port]
+    set cmd [list $::redis_cli_path -h $host -p $port]
     lappend cmd {*}[rediscli_tls_config "tests"]
     lappend cmd {*}$opts
     return $cmd
@@ -44,7 +44,7 @@ proc rediscli {host port {opts {}}} {
 
 # Returns command line for executing redis-cli with a unix socket address
 proc rediscli_unixsocket {unixsocket {opts {}}} {
-    return [list ./redis-cli -s $unixsocket {*}$opts]
+    return [list $::redis_cli_path -s $unixsocket {*}$opts]
 }
 
 # Run redis-cli with specified args on the server of specified level.
diff --git a/tests/tcl/tests/support/server.tcl 
b/tests/tcl/tests/support/server.tcl
index c4bb718..3e61084 100644
--- a/tests/tcl/tests/support/server.tcl
+++ b/tests/tcl/tests/support/server.tcl
@@ -235,11 +235,11 @@ proc create_server_config_file {filename config} {
 
 proc spawn_server {config_file stdout stderr} {
     if {$::valgrind} {
-        set pid [exec valgrind --track-origins=yes --trace-children=yes 
--suppressions=[pwd]/src/valgrind.sup --show-reachable=no 
--show-possibly-lost=no --leak-check=full ./redis-server -c $config_file >> 
$stdout 2>> $stderr &]
+        set pid [exec valgrind --track-origins=yes --trace-children=yes 
--suppressions=[pwd]/src/valgrind.sup --show-reachable=no 
--show-possibly-lost=no --leak-check=full $::redis_server_path -c $config_file 
>> $stdout 2>> $stderr &]
     } elseif ($::stack_logging) {
-        set pid [exec /usr/bin/env MallocStackLogging=1 
MallocLogFile=/tmp/malloc_log.txt ./redis-server -c $config_file >> $stdout 2>> 
$stderr &]
+        set pid [exec /usr/bin/env MallocStackLogging=1 
MallocLogFile=/tmp/malloc_log.txt $::redis_server_path -c $config_file >> 
$stdout 2>> $stderr &]
     } else {
-        set pid [exec ./redis-server -c $config_file >> $stdout 2>> $stderr &]
+        set pid [exec $::redis_server_path -c $config_file >> $stdout 2>> 
$stderr &]
     }
 
     if {$::wait_server} {
diff --git a/tests/tcl/tests/test_helper.tcl b/tests/tcl/tests/test_helper.tcl
index e550137..eea6b4f 100644
--- a/tests/tcl/tests/test_helper.tcl
+++ b/tests/tcl/tests/test_helper.tcl
@@ -551,10 +551,15 @@ proc print_help_screen {} {
         "--port <port>      TCP port to use against external host."
         "--baseport <port>  Initial port number for spawned redis servers."
         "--portcount <num>  Port range for spawned redis servers."
+        "--server-path <p>  Path for redis server (default ./redis-server)."
+        "--cli-path <path>  Path for redis CLI (default ./redis-cli)."
         "--help             Print this help screen."
     } "\n"]
 }
 
+set ::redis_server_path ./redis-server
+set ::redis_cli_path ./redis-cli
+
 # parse arguments
 for {set j 0} {$j < [llength $argv]} {incr j} {
     set opt [lindex $argv $j]
@@ -655,6 +660,12 @@ for {set j 0} {$j < [llength $argv]} {incr j} {
     } elseif {$opt eq {--timeout}} {
         set ::timeout $arg
         incr j
+    } elseif {$opt eq {--server-path}} {
+        set ::redis_server_path $arg
+        incr j
+    } elseif {$opt eq {--cli-path}} {
+        set ::redis_cli_path $arg
+        incr j
     } elseif {$opt eq {--help}} {
         print_help_screen
         exit 0
diff --git a/x.py b/x.py
index c0f8a3b..46c012e 100755
--- a/x.py
+++ b/x.py
@@ -17,17 +17,19 @@
 # specific language governing permissions and limitations
 # under the License.
 
-from argparse import Namespace, ArgumentParser, ArgumentDefaultsHelpFormatter
+from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter, REMAINDER
 from glob import glob
 from os import makedirs
 from pathlib import Path
 import re
 from subprocess import Popen, PIPE
 import sys
-from typing import Callable, List, Any, Optional, TextIO
+from typing import List, Any, Optional, TextIO, Tuple
 from shutil import copyfile
 
 CMAKE_REQUIRE_VERSION = (3, 13, 0)
+TCL_REQUIRE_VERSION = (8, 5, 0)
+
 SEMVER_REGEX = re.compile(
     r"""
         ^
@@ -49,7 +51,7 @@ SEMVER_REGEX = re.compile(
     re.VERBOSE,
 )
 
-def run(*args: str, msg: Optional[str]=None, verbose: bool=False, **kwargs: 
Any) -> Popen:
+def run(*args: str, msg: Optional[str]=None, verbose: bool=False, **kwargs: 
Any) -> Popen[Any]:
     sys.stdout.flush()
     if verbose:
         print(f"$ {' '.join(args)}")
@@ -57,11 +59,9 @@ def run(*args: str, msg: Optional[str]=None, verbose: 
bool=False, **kwargs: Any)
     p = Popen(args, **kwargs)
     code = p.wait()
     if code != 0:
-        err = f"""
-failed to run: {args}
-exit with code: {code}
-error message: {msg}
-"""
+        err = f"\nfailed to run: {args}\nexit with code: {code}\n"
+        if msg:
+            err += f"error message: {msg}\n"
         raise RuntimeError(err)
     
     return p
@@ -70,9 +70,19 @@ def run_pipe(*args: str, msg: Optional[str]=None, verbose: 
bool=False, **kwargs:
     p = run(*args, msg=msg, verbose=verbose, stdout=PIPE, text=True, **kwargs)
     return p.stdout # type: ignore
 
-def find_command(command: str, msg: Optional[str]=None):
+def find_command(command: str, msg: Optional[str]=None) -> str:
     return run_pipe("which", command, msg=msg).read().strip()
 
+def check_version(current: str, required: Tuple[int, int, int], prog_name: 
Optional[str] = None) -> None:
+    require_version = '.'.join(map(str, required))
+    semver_match = SEMVER_REGEX.match(current)
+    if semver_match is None:
+        raise RuntimeError(f"{prog_name} {require_version} or higher is 
required, got: {current}")
+    semver_dict = semver_match.groupdict()
+    semver = (int(semver_dict["major"]), int(semver_dict["minor"]), 
int(semver_dict["patch"]))
+    if semver < required:
+        raise RuntimeError(f"{prog_name} {require_version} or higher is 
required, got: {current}")
+
 def build(dir: str, jobs: int, ghproxy: bool, ninja: bool, unittest: bool, 
compiler: str, cmake_path: str, D: List[str]) -> None:
     basedir = Path(__file__).parent.absolute()
 
@@ -83,14 +93,7 @@ def build(dir: str, jobs: int, ghproxy: bool, ninja: bool, 
unittest: bool, compi
     output = run_pipe("head", "-n", "1", stdin=output)
     output = run_pipe("sed", "s/[^0-9.]*//g", stdin=output)
     cmake_version = output.read().strip()
-    cmake_require_version = '.'.join(map(str, CMAKE_REQUIRE_VERSION))
-    cmake_semver_match = SEMVER_REGEX.match(cmake_version)
-    if cmake_semver_match is None:
-        raise RuntimeError(f"CMake {cmake_require_version} or higher is 
required, got: {cmake_version}")
-    cmake_semver_dict = cmake_semver_match.groupdict()
-    cmake_semver = (int(cmake_semver_dict["major"]), 
int(cmake_semver_dict["minor"]), int(cmake_semver_dict["patch"]))
-    if cmake_semver < CMAKE_REQUIRE_VERSION:
-        raise RuntimeError(f"CMake {cmake_require_version} or higher is 
required, got: {cmake_version}")
+    check_version(cmake_version, CMAKE_REQUIRE_VERSION, "CMake")
 
     makedirs(dir, exist_ok=True)
 
@@ -116,7 +119,7 @@ def cpplint() -> None:
     command = find_command("cpplint", msg="cpplint is required")
     options = ["--linelength=120", 
"--filter=-build/include_subdir,-legal/copyright,-build/c++11"]
     sources = [*glob("src/*.h"), *glob("src/*.cc")]
-    run(command, *options, *sources)
+    run(command, *options, *sources, verbose=True)
 
 def cppcheck() -> None:
     command = find_command("cppcheck", msg="cppcheck is required")
@@ -132,7 +135,7 @@ def cppcheck() -> None:
 
     sources = ["src"]
 
-    run(command, *options, *sources)
+    run(command, *options, *sources, verbose=True)
 
 def write_version(release_version: str) -> str:
     version = release_version.strip()
@@ -204,7 +207,20 @@ def package_fpm(package_type: str, release_version: str, 
dir: str, jobs: int) ->
         '--license', 'Apache-2.0'
     ]
 
-    run(fpm, *fpm_opts)
+    run(fpm, *fpm_opts, verbose=True)
+
+def test_tcl(dir: str, rest: List[str]) -> None:
+    tclsh = find_command('tclsh', msg='TCL is required for testing')
+
+    output = run_pipe('echo', 'puts [info patchlevel];exit 0')
+    output = run_pipe(tclsh, stdin=output)
+    tcl_version = output.read().strip()
+    check_version(tcl_version, TCL_REQUIRE_VERSION, "tclsh")
+
+    tcldir = Path(__file__).parent.absolute() / 'tests' / 'tcl'
+    run(tclsh, 'tests/test_helper.tcl', '--server-path', 
str(Path(dir).absolute() / 'kvrocks'), *rest, 
+        cwd=str(tcldir), verbose=True
+    )
 
 if __name__ == '__main__':
     parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormatter)
@@ -273,6 +289,23 @@ if __name__ == '__main__':
     parser_package_fpm.add_argument('-j', '--jobs', default=4, metavar='N', 
help='execute N build jobs concurrently')
     parser_package_fpm.set_defaults(func=package_fpm)
 
+    parser_test = subparsers.add_parser(
+        'test',
+        description="Test against a specific kvrocks build",
+        help="Test against a specific kvrocks build",
+        formatter_class=ArgumentDefaultsHelpFormatter,
+    )
+    parser_test.set_defaults(func=parser_test.print_help)
+    parser_test_subparsers = parser_test.add_subparsers()
+    parser_test_tcl = parser_test_subparsers.add_parser(
+        'tcl',
+        description="Test kvrocks via TCL scripts",
+        help="Test kvrocks via TCL scripts",
+    )
+    parser_test_tcl.add_argument('dir', metavar='BUILD_DIR', nargs='?', 
default='build', help="directory including kvrocks build files")
+    parser_test_tcl.add_argument('rest', nargs=REMAINDER, help="the rest of 
arguments to forward to TCL scripts")
+    parser_test_tcl.set_defaults(func=test_tcl)
+
     args = parser.parse_args()
 
     arg_dict = dict(vars(args))

Reply via email to