diff --git a/cli/cmd/cat.go b/cli/cmd/cat.go index a3730b541..978b689d0 100644 --- a/cli/cmd/cat.go +++ b/cli/cmd/cat.go @@ -33,7 +33,7 @@ var catFlags = checkpoint.Opts{ func NewCatCmd() *cobra.Command { var catCmd = &cobra.Command{ Use: "cat ...", - Short: "Print into stdout the contents of .snap/.xlog files", + Short: "Print into stdout the contents of .snap/.xlog FILE(s)", Run: func(cmd *cobra.Command, args []string) { cmdCtx.CommandName = cmd.Name() err := modules.RunCmd(&cmdCtx, cmd.CommandPath(), &modulesInfo, @@ -41,7 +41,7 @@ func NewCatCmd() *cobra.Command { util.HandleCmdErr(cmd, err) }, Example: "tt cat /path/to/xlog --timestamp 2024-11-13T14:02:36.818700000+00:00\n" + - " tt cat /path/to/snap --timestamp=1731592956.818", + " tt cat /path/to/1.snap /path/to/2.snap --timestamp=1731592956.818", } catCmd.Flags().Uint64Var(&catFlags.To, "to", catFlags.To, diff --git a/cli/cmd/play.go b/cli/cmd/play.go index 932cf26d2..f80ff83ca 100644 --- a/cli/cmd/play.go +++ b/cli/cmd/play.go @@ -40,7 +40,7 @@ var ( func NewPlayCmd() *cobra.Command { var playCmd = &cobra.Command{ Use: "play ...", - Short: "Play the contents of .snap/.xlog files to another Tarantool instance", + Short: "Play the contents of .snap/.xlog FILE(s) to another Tarantool instance", Run: func(cmd *cobra.Command, args []string) { cmdCtx.CommandName = cmd.Name() err := modules.RunCmd(&cmdCtx, cmd.CommandPath(), &modulesInfo, @@ -48,7 +48,7 @@ func NewPlayCmd() *cobra.Command { util.HandleCmdErr(cmd, err) }, Example: "tt play uri /path/to/xlog --timestamp 2024-11-13T14:02:36.818700000+00:00\n" + - " tt play uri /path/to/xlog --timestamp=1731592956.818", + " tt play uri /path/to/1.xlog /path/to/2.xlog --timestamp=1731592956.818", } playCmd.Flags().StringVarP(&playUsername, "username", "u", "", "username") diff --git a/test/integration/cat/test_cat.py b/test/integration/cat/test_cat.py index 9075302f5..d26e74daa 100644 --- a/test/integration/cat/test_cat.py +++ b/test/integration/cat/test_cat.py @@ -6,51 +6,65 @@ from utils import run_command_and_get_output +TEST_CAT_ARGS_CCONFIG = ("args, cat_result, found, not_found") -def test_cat_unset_arg(tt_cmd, tmp_path): - # Testing with unset .xlog or .snap file. - cmd = [tt_cmd, "cat"] - rc, output = run_command_and_get_output(cmd, cwd=tmp_path) - assert rc == 1 - assert re.search(r"it is required to specify at least one .xlog or .snap file", output) - - -def test_cat_non_existent_file(tt_cmd, tmp_path): - # Testing with non-existent .xlog or .snap file. - cmd = [tt_cmd, "cat", "path-to-non-existent-file"] - rc, output = run_command_and_get_output(cmd, cwd=tmp_path) - assert rc == 1 - assert re.search(r"No such file or directory", output) - - -def test_cat_snap_file(tt_cmd, tmp_path): - # Copy the .snap file to the "run" directory. - test_app_path = os.path.join(os.path.dirname(__file__), "test_file", "test.snap") - shutil.copy(test_app_path, tmp_path) - # Testing .snap file. - cmd = [ - tt_cmd, "cat", "test.snap", "--show-system", - "--space=320", "--space=296", "--from=423", "--to=513" - ] - rc, output = run_command_and_get_output(cmd, cwd=tmp_path) - assert rc == 0 - assert re.search(r"lsn: 423", output) - assert re.search(r"lsn: 512", output) - assert re.search(r"space_id: 320", output) - assert re.search(r"space_id: 296", output) +def make_test_cat_args_param( + args=[], + cat_result=0, + found={}, + not_found={}, +): + return pytest.param(args, cat_result, found, not_found) -def test_cat_xlog_file(tt_cmd, tmp_path): +@pytest.mark.parametrize(TEST_CAT_ARGS_CCONFIG, [ + make_test_cat_args_param( + # Testing with unset .xlog or .snap file. + cat_result=1, + found={"it is required to specify at least one .xlog or .snap file"}, + ), + make_test_cat_args_param( + args=["path-to-non-existent-file"], + cat_result=1, + found={"No such file or directory"}, + ), + make_test_cat_args_param( + args=["test.snap", "--show-system", "--space=320", + "--space=296", "--from=423", "--to=513"], + cat_result=0, + found={"lsn: 423", + "lsn: 512", + "space_id: 320", + "space_id: 296"}, + ), + make_test_cat_args_param( + args=["test.xlog", "--show-system", "--replica=1"], + cat_result=0, + found={"replica_id: 1"}, + ), + make_test_cat_args_param( + args=["test.xlog", "test.snap"], + cat_result=0, + found={"Result of cat: the file \"test.xlog\" is processed below", + "Result of cat: the file \"test.snap\" is processed below"}, + ), +]) +def test_cat_args_tests(tt_cmd, tmp_path, args, cat_result, found, not_found): # Copy the .xlog file to the "run" directory. - test_app_path = os.path.join(os.path.dirname(__file__), "test_file", "test.xlog") - shutil.copy(test_app_path, tmp_path) + test_xlog_file = os.path.join(os.path.dirname(__file__), "test_file", "test.xlog") + test_snap_file = os.path.join(os.path.dirname(__file__), "test_file", "test.snap") + shutil.copy(test_xlog_file, tmp_path) + shutil.copy(test_snap_file, tmp_path) - # Testing .xlog file. - cmd = [tt_cmd, "cat", "test.xlog", "--show-system", "--replica=1"] + cmd = [tt_cmd, "cat"] + cmd.extend(args) rc, output = run_command_and_get_output(cmd, cwd=tmp_path) - assert rc == 0 - assert re.search(r"replica_id: 1", output) + assert rc == cat_result + for item in found: + assert re.search(r"{0}".format(item), output) + for item in not_found: + assert not re.search(r"{0}".format(item), output) TEST_CAT_TIMESTAMP_PARAMS_CCONFIG = ("input, cat_result, found, not_found") @@ -106,8 +120,8 @@ def make_test_cat_timestamp_param( "timestamp: 1731592956.8184"}, ), ]) -def test_cat_test_remote_instance_timestamp(tt_cmd, tmp_path, input, - cat_result, found, not_found): +def test_cat_test_timestamp(tt_cmd, tmp_path, input, + cat_result, found, not_found): # Copy the .xlog file to the "run" directory. test_app_path = os.path.join(os.path.dirname(__file__), "test_file", "timestamp.xlog") shutil.copy(test_app_path, tmp_path) @@ -115,8 +129,7 @@ def test_cat_test_remote_instance_timestamp(tt_cmd, tmp_path, input, cmd = [tt_cmd, "cat", "timestamp.xlog", "--timestamp={0}".format(input)] rc, output = run_command_and_get_output(cmd, cwd=tmp_path) assert rc == cat_result - if cat_result == 0: - for item in found: - assert re.search(r"{0}".format(item), output) - for item in not_found: - assert not re.search(r"{0}".format(item), output) + for item in found: + assert re.search(r"{0}".format(item), output) + for item in not_found: + assert not re.search(r"{0}".format(item), output) diff --git a/test/integration/play/test_play.py b/test/integration/play/test_play.py index 1b88e80ab..0bb21ccf9 100644 --- a/test/integration/play/test_play.py +++ b/test/integration/play/test_play.py @@ -21,14 +21,6 @@ def test_instance(request, tmp_path): return inst -def test_play_unset_arg(tt_cmd, tmp_path): - # Testing with unset uri and .xlog or .snap file. - cmd = [tt_cmd, "play"] - rc, output = run_command_and_get_output(cmd, cwd=tmp_path) - assert rc == 1 - assert re.search(r"required to specify an URI and at least one .xlog or .snap file", output) - - def test_play_non_existent_uri(tt_cmd, tmp_path): # Testing with non-existent uri. cmd = [tt_cmd, "play", "127.0.0.1:0", "_"] @@ -37,100 +29,99 @@ def test_play_non_existent_uri(tt_cmd, tmp_path): assert re.search(r"no connection to the host", output) -def test_play_non_existent_file(tt_cmd, tmp_path, test_instance): - # Run play with non-existent file. - cmd = [tt_cmd, "play", "127.0.0.1:" + test_instance.port, "path-to-non-existent-file"] - rc, output = run_command_and_get_output(cmd, cwd=tmp_path) - assert rc == 1 - assert re.search(r"No such file or directory", output) - - -def test_play_test_remote_instance(tt_cmd, test_instance): - # Play .xlog file to the remote instance. - cmd = [tt_cmd, "play", "127.0.0.1:" + test_instance.port, "test.xlog", "--space=999"] - rc, output = run_command_and_get_output(cmd, cwd=test_instance._tmpdir) - assert rc == 0 - assert re.search(r"Play result: completed successfully", output) - - # Testing played .xlog file from the remote instance. - cmd = [tt_cmd, "cat", "00000000000000000000.xlog", "--space=999"] - rc, output = run_command_and_get_output(cmd, cwd=test_instance._tmpdir) - assert rc == 0 - assert re.search(r"space_id: 999", output) - assert re.search(r"[1, 'Roxette', 1986]", output) - assert re.search(r"[2, 'Scorpions', 2015]", output) - assert re.search(r"[3, 'Ace of Base', 1993]", output) - - -TEST_PLAY_TIMESTAMP_PARAMS_CCONFIG = ("input, play_result, found, not_found") +TEST_PLAY_PARAMS_CCONFIG = ("args, play_result, play_error, found, not_found") def make_test_play_timestamp_param( - input="", + args=[], play_result=0, + play_error="", found={}, not_found={}, ): - return pytest.param(input, play_result, found, not_found) + return pytest.param(args, play_result, play_error, found, not_found) -@pytest.mark.parametrize(TEST_PLAY_TIMESTAMP_PARAMS_CCONFIG, [ +@pytest.mark.parametrize(TEST_PLAY_PARAMS_CCONFIG, [ make_test_play_timestamp_param( - input="abcdef", + # Testing with unset uri and .xlog or .snap file. play_result=1, - found={"failed to parse a timestamp: parsing time \"abcdef\""}, + play_error="required to specify an URI and at least one .xlog or .snap file", ), make_test_play_timestamp_param( - input="2024-11-14T14:02:36.abc", + args=["path-to-non-existent-file"], play_result=1, - found={"failed to parse a timestamp: parsing time \"2024-11-14T14:02:36.abc\""}, + play_error="No such file or directory", ), make_test_play_timestamp_param( - input="", - play_result=0, + # Testing with multiple files specified + args=["test.xlog", "test.xlog"], + play_result=1, + play_error="ER_TUPLE_FOUND: Duplicate key exists in unique index", + ), + make_test_play_timestamp_param( + args=["test.xlog", "--timestamp=abcdef", "--space=999"], + play_result=1, + play_error="failed to parse a timestamp: parsing time \"abcdef\"", + ), + make_test_play_timestamp_param( + args=["test.xlog", "--timestamp=2024-11-14T14:02:36.abc", "--space=999"], + play_result=1, + play_error="failed to parse a timestamp: parsing time \"2024-11-14T14:02:36.abc\"", + ), + make_test_play_timestamp_param( + # Play .xlog file to the remote instance. + args=["test.xlog", "--space=999"], + found={"space_id: 999", + "[1, 'Roxette', 1986]", + "[2, 'Scorpions', 2015]", + "[3, 'Ace of Base', 1993]"}, + ), + make_test_play_timestamp_param( + # Testing timestamp default value. + args=["test.xlog", "--timestamp=", "--space=999"], found={"[3, 'Ace of Base', 1993]"}, ), make_test_play_timestamp_param( - input="1651130533.1534", - play_result=0, + args=["test.xlog", "--timestamp=1651130533.1534", "--space=999"], found={"space_id: 999", "[1, 'Roxette', 1986]", "[2, 'Scorpions', 2015]"}, not_found={"Ace of Base"}, ), make_test_play_timestamp_param( - input="2022-04-28T07:22:13.1534+00:00", - play_result=0, + args=["test.xlog", "--timestamp=1651130533.1534", "--space=999"], found={"space_id: 999", "[1, 'Roxette', 1986]", "[2, 'Scorpions', 2015]"}, not_found={"Ace of Base"}, ), make_test_play_timestamp_param( - input="2022-04-28T07:22:12+00:00", - play_result=0, + args=["test.xlog", "--timestamp=2022-04-28T07:22:12+00:00", "--space=999"], found={"space_id: 999", "[1, 'Roxette', 1986]"}, not_found={"Scorpions", "Ace of Base"}, ), ]) -def test_play_test_remote_instance_timestamp(tt_cmd, test_instance, input, - play_result, found, not_found): +def test_play_test_remote_instance_timestamp(tt_cmd, test_instance, args, + play_result, play_error, found, not_found): # Play .xlog file to the remote instance. - cmd = [tt_cmd, "play", "127.0.0.1:" + test_instance.port, "test.xlog", - "--timestamp={0}".format(input), "--space=999"] - rc, output = run_command_and_get_output(cmd, cwd=test_instance._tmpdir) + cmd = [tt_cmd, "play", "127.0.0.1:" + test_instance.port] + cmd.extend(args) + rc, play_output = run_command_and_get_output(cmd, cwd=test_instance._tmpdir) assert rc == play_result - if play_result == 0: + if play_result == 1: + assert re.search(r"{0}".format(play_error), play_output) + else: # Testing played .xlog file from the remote instance. cmd = [tt_cmd, "cat", "00000000000000000000.xlog", "--space=999"] - rc, output = run_command_and_get_output(cmd, cwd=test_instance._tmpdir) + rc, cat_output = run_command_and_get_output(cmd, cwd=test_instance._tmpdir) assert rc == 0 for item in found: - assert re.search(r"{0}".format(item), output) + assert re.search(r"{0}".format(item), cat_output) for item in not_found: - assert not re.search(r"{0}".format(item), output) + assert not re.search(r"{0}".format(item), cat_output) @pytest.mark.parametrize("opts", [