Skip to content

Commit

Permalink
cat/play: tip that multiple files can be processed
Browse files Browse the repository at this point in the history
Closes #1018
Closes #1019
  • Loading branch information
patapenka-alexey authored and dmyger committed Nov 28, 2024
1 parent 5ff57a5 commit 084955f
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 191 deletions.
4 changes: 2 additions & 2 deletions cli/cmd/cat.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,15 @@ var catFlags = checkpoint.Opts{
func NewCatCmd() *cobra.Command {
var catCmd = &cobra.Command{
Use: "cat <FILE>...",
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,
internalCatModule, args)
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,
Expand Down
4 changes: 2 additions & 2 deletions cli/cmd/play.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ var (
func NewPlayCmd() *cobra.Command {
var playCmd = &cobra.Command{
Use: "play <URI> <FILE>...",
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,
internalPlayModule, args)
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")
Expand Down
177 changes: 85 additions & 92 deletions test/integration/cat/test_cat.py
Original file line number Diff line number Diff line change
@@ -1,122 +1,115 @@
import datetime
import io
import os
import re
import shutil

import pytest

from utils import run_command_and_get_output


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)

@pytest.mark.parametrize("args, found", [
(
# Testing with unset .xlog or .snap file.
(),
"it is required to specify at least one .xlog or .snap file",
),
(
"path-to-non-existent-file",
"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)

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"]
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"No such file or directory", output)
assert found in 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)
@pytest.mark.parametrize("args, found", [
(
("test.snap", "--show-system", "--space=320", "--space=296", "--from=423", "--to=513"),
("lsn: 423", "lsn: 512", "space_id: 320", "space_id: 296"),
),
(
("test.xlog", "--show-system", "--replica=1"),
("replica_id: 1"),
),
(
("test.xlog", "test.snap"),
('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 item in output


def test_cat_xlog_file(tt_cmd, tmp_path):
@pytest.mark.parametrize("input, error", [
(
"abcdef",
'failed to parse a timestamp: parsing time "abcdef"',
),
(
"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, error):
# 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", f"--timestamp={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")


def make_test_cat_timestamp_param(
input="",
cat_result=0,
found={},
not_found={},
):
return pytest.param(input, cat_result, found, not_found)
assert rc == 1
assert error in output


@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,
found={"lsn: 12"},
),
make_test_cat_timestamp_param(
input="1731592956.8182",
cat_result=0,
found={"lsn: 6",
"timestamp: 1731592956.8181"},
not_found={"lsn: 8",
"timestamp: 1731592956.8184"},
),
make_test_cat_timestamp_param(
input="2024-11-14T14:02:36.818299999Z",
cat_result=0,
found={"lsn: 6",
"timestamp: 1731592956.8181"},
not_found={"lsn: 8",
"timestamp: 1731592956.8184"},
),
make_test_cat_timestamp_param(
input="2024-11-14T14:02:35+00:00",
cat_result=0,
not_found={"lsn: 6",
"timestamp: 1731592956.8181",
"lsn: 8",
"timestamp: 1731592956.8184"},
),
@pytest.mark.parametrize("input", [
1731592956.1182,
1731592956.8182,
"2024-11-14T14:02:36.818+00:00",
"2024-11-14T14:02:35+00:00",
])
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):
# 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)]
cmd = [tt_cmd, "cat", "timestamp.xlog", f"--timestamp={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

# Convert input to timestamp
input_ts = 0
if type(input) is float or type(input) is int:
input_ts = float(input)
if type(input) is str:
input_ts = float(datetime.datetime.fromisoformat(input).timestamp())

# Compare input value and record's timestamp
buf = io.StringIO(output)
while (line := buf.readline()) != "":
if "timestamp:" in line:
index = line.find(':')
record_ts = line[index+1:].strip()
assert input_ts > float(record_ts)
1 change: 1 addition & 0 deletions test/integration/play/test_file/remote_instance_cfg.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ local function configure_instance()
tester:create_index('primary', {type = 'tree', parts = {'id'}})
box.schema.user.grant('guest', 'read,write', 'space', 'tester')
box.schema.user.create('test_user', { password = 'secret' })
box.schema.user.grant('test_user', 'execute', 'universe')
box.schema.user.grant('test_user', 'super')
end

Expand Down
3 changes: 3 additions & 0 deletions test/integration/play/test_file/timestamp/create_space.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
box.schema.space.create('test', { id = 512 })

return box.space.test:create_index('0')
1 change: 1 addition & 0 deletions test/integration/play/test_file/timestamp/get_data.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
return box.space.test:select()
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit 084955f

Please sign in to comment.