diff --git a/cli/cmd/cat.go b/cli/cmd/cat.go index a3730b541..3c1a41adc 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/file.xlog /path/to/file.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..ca8ccad63 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/file.xlog /path/to/file.snap --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..b59e4b921 100644 --- a/test/integration/cat/test_cat.py +++ b/test/integration/cat/test_cat.py @@ -7,116 +7,140 @@ from utils import run_command_and_get_output -def test_cat_unset_arg(tt_cmd, tmp_path): - # Testing with unset .xlog or .snap file. +# Failed `args` tests +def make_test_cat_args_param_failed( + args={}, + found={}, +): + return pytest.param(args, found) + + +@pytest.mark.parametrize("args, found", [ + make_test_cat_args_param_failed( + # Testing with unset .xlog or .snap file. + found={"it is required to specify at least one .xlog or .snap file"}, + ), + make_test_cat_args_param_failed( + args={"path-to-non-existent-file"}, + found={"No such file or directory"}, + ), +]) +def test_cat_args_tests_failed(tt_cmd, tmp_path, args, found): + # Copy the .xlog file to the "run" directory. + 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) + cmd = [tt_cmd, "cat"] + cmd.extend(args) 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) + for item in found: + assert re.search(r"{0}".format(item), 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) +# Successful args tests +def make_test_cat_args_param_valid( + args={}, + found={}, +): + return pytest.param(args, found) -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) +@pytest.mark.parametrize("args, found", [ + make_test_cat_args_param_valid( + args={"test.snap", "--show-system", "--space=320", + "--space=296", "--from=423", "--to=513"}, + found={"lsn: 423", "lsn: 512", + "space_id: 320", "space_id: 296"}, + ), + make_test_cat_args_param_valid( + args={"test.xlog", "--show-system", "--replica=1"}, + found={"replica_id: 1"}, + ), + make_test_cat_args_param_valid( + args={"test.xlog", "test.snap"}, + 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_successed(tt_cmd, tmp_path, args, found): + # Copy the .xlog file to the "run" directory. + 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 .snap file. - cmd = [ - tt_cmd, "cat", "test.snap", "--show-system", - "--space=320", "--space=296", "--from=423", "--to=513" - ] + 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"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) + for item in found: + assert re.search(r"{0}".format(item), output) -def test_cat_xlog_file(tt_cmd, tmp_path): +# Failed `timestamp` tests +@pytest.mark.parametrize("input, found", [ + pytest.param( + "abcdef", + {'failed to parse a timestamp: parsing time "abcdef"'}, + ), + pytest.param( + "2024-11-14T14:02:36.abc", + {'failed to parse a timestamp: parsing time "2024-11-14T14:02:36.abc"'}, + ), +]) +def test_cat_test_timestamp_failed(tt_cmd, tmp_path, input, found): # Copy the .xlog file to the "run" directory. - test_app_path = os.path.join(os.path.dirname(__file__), "test_file", "test.xlog") + test_app_path = os.path.join(os.path.dirname(__file__), "test_file", "timestamp.xlog") shutil.copy(test_app_path, tmp_path) - # Testing .xlog file. - cmd = [tt_cmd, "cat", "test.xlog", "--show-system", "--replica=1"] + cmd = [tt_cmd, "cat", "timestamp.xlog", "--timestamp={0}".format(input)] rc, output = run_command_and_get_output(cmd, cwd=tmp_path) - assert rc == 0 - assert re.search(r"replica_id: 1", output) - - -TEST_CAT_TIMESTAMP_PARAMS_CCONFIG = ("input, cat_result, found, not_found") + assert rc == 1 + for item in found: + assert re.search(r"{0}".format(item), output) -def make_test_cat_timestamp_param( +# Successful `timestamp` tests +def make_test_cat_timestamp_param_valid( input="", - cat_result=0, found={}, not_found={}, ): - return pytest.param(input, cat_result, found, not_found) + return pytest.param(input, found, not_found) -@pytest.mark.parametrize(TEST_CAT_TIMESTAMP_PARAMS_CCONFIG, [ - make_test_cat_timestamp_param( - input="abcdef", - cat_result=1, - found={"failed to parse a timestamp: parsing time \"abcdef\""}, - ), - make_test_cat_timestamp_param( - input="2024-11-14T14:02:36.abc", - cat_result=1, - found={"failed to parse a timestamp: parsing time \"2024-11-14T14:02:36.abc\""}, - ), - make_test_cat_timestamp_param( - input="", - cat_result=0, +@pytest.mark.parametrize("input, found, not_found", [ + make_test_cat_timestamp_param_valid( found={"lsn: 12"}, ), - make_test_cat_timestamp_param( + make_test_cat_timestamp_param_valid( input="1731592956.8182", - cat_result=0, - found={"lsn: 6", - "timestamp: 1731592956.8181"}, - not_found={"lsn: 8", - "timestamp: 1731592956.8184"}, + found={"lsn: 6", "timestamp: 1731592956.8181"}, + not_found={"lsn: 8", "timestamp: 1731592956.8184"}, ), - make_test_cat_timestamp_param( + make_test_cat_timestamp_param_valid( input="2024-11-14T14:02:36.818299999Z", - cat_result=0, - found={"lsn: 6", - "timestamp: 1731592956.8181"}, - not_found={"lsn: 8", - "timestamp: 1731592956.8184"}, + found={"lsn: 6", "timestamp: 1731592956.8181"}, + not_found={"lsn: 8", "timestamp: 1731592956.8184"}, ), - make_test_cat_timestamp_param( + make_test_cat_timestamp_param_valid( input="2024-11-14T14:02:35+00:00", - cat_result=0, - not_found={"lsn: 6", - "timestamp: 1731592956.8181", - "lsn: 8", - "timestamp: 1731592956.8184"}, + not_found={"lsn: 6", "timestamp: 1731592956.8181", + "lsn: 8", "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_successed(tt_cmd, tmp_path, input, 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) 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) + assert rc == 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) diff --git a/test/integration/play/test_play.py b/test/integration/play/test_play.py index 1b88e80ab..1143e9e8b 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,109 @@ 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) +# ----------------------------------------------------------------------------- +# Failed tests +def make_test_play_param_failed( + args={}, + play_error="", +): + return pytest.param(args, play_error) -def test_play_test_remote_instance(tt_cmd, test_instance): +@pytest.mark.parametrize("args, play_error", [ + make_test_play_param_failed( + # Testing with unset uri and .xlog or .snap file. + play_error="required to specify an URI and at least one .xlog or .snap file", + ), + make_test_play_param_failed( + args={"path-to-non-existent-file"}, + play_error="No such file or directory", + ), + make_test_play_param_failed( + args={"test.xlog", "--timestamp=abcdef", "--space=999"}, + play_error='failed to parse a timestamp: parsing time "abcdef"', + ), + make_test_play_param_failed( + args={"test.xlog", "--timestamp=2024-11-14T14:02:36.abc", "--space=999"}, + play_error='failed to parse a timestamp: parsing time "2024-11-14T14:02:36.abc"', + ), +]) +def test_play_test_remote_instance_timestamp(tt_cmd, test_instance, args, play_error): # 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") + 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 == 1 + assert re.search(r"{0}".format(play_error), play_output) -def make_test_play_timestamp_param( - input="", - play_result=0, +# ----------------------------------------------------------------------------- +# Successful tests +def make_test_play_timestamp_param_valid( + args={}, found={}, not_found={}, ): - return pytest.param(input, play_result, found, not_found) + return pytest.param(args, found, not_found) -@pytest.mark.parametrize(TEST_PLAY_TIMESTAMP_PARAMS_CCONFIG, [ - make_test_play_timestamp_param( - input="abcdef", - play_result=1, - found={"failed to parse a timestamp: parsing time \"abcdef\""}, - ), - make_test_play_timestamp_param( - input="2024-11-14T14:02:36.abc", - play_result=1, - found={"failed to parse a timestamp: parsing time \"2024-11-14T14:02:36.abc\""}, +@pytest.mark.parametrize("args, found, not_found", [ + make_test_play_timestamp_param_valid( + # 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( - input="", - play_result=0, + make_test_play_timestamp_param_valid( + # 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, + make_test_play_timestamp_param_valid( + 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, + make_test_play_timestamp_param_valid( + 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, + make_test_play_timestamp_param_valid( + 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"}, ), + make_test_play_timestamp_param_valid( + # Testing with multiple files specified + args={"test.xlog", "test.snap"}, + found={"space_id: 999", + "[1, 'Roxette', 1986]"}, + ), ]) -def test_play_test_remote_instance_timestamp(tt_cmd, test_instance, input, - play_result, found, not_found): +def test_play_remote_instance_timestamp_valid(tt_cmd, test_instance, + args, 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) - assert rc == play_result - if play_result == 0: - # 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 - 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) + cmd = [tt_cmd, "play", "127.0.0.1:" + test_instance.port] + cmd.extend(args) + rc, _ = run_command_and_get_output(cmd, cwd=test_instance._tmpdir) + assert rc == 0 + # Testing played .xlog file from the remote instance. + cmd = [tt_cmd, "cat", "00000000000000000000.xlog", "--space=999"] + 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), cat_output) + for item in not_found: + assert not re.search(r"{0}".format(item), cat_output) @pytest.mark.parametrize("opts", [