diff --git a/store/snapshots/manager.go b/store/snapshots/manager.go index 4d75690c396..17c318a94be 100644 --- a/store/snapshots/manager.go +++ b/store/snapshots/manager.go @@ -388,8 +388,11 @@ func (m *Manager) doRestoreSnapshot(snapshot types.Snapshot, chChunks <-chan io. return errorsmod.Wrapf(err, "extension %s restore", metadata.Name) } - if nextItem.GetExtensionPayload() != nil { + payload := nextItem.GetExtensionPayload() + if payload != nil && len(payload.Payload) != 0 { return fmt.Errorf("extension %s don't exhausted payload stream", metadata.Name) + } else { + break } } return nil diff --git a/store/v2/snapshots/manager.go b/store/v2/snapshots/manager.go index 7e12e4503de..85d2cf26be2 100644 --- a/store/v2/snapshots/manager.go +++ b/store/v2/snapshots/manager.go @@ -437,8 +437,11 @@ func (m *Manager) doRestoreSnapshot(snapshot types.Snapshot, chChunks <-chan io. return errorsmod.Wrapf(err, "extension %s restore", metadata.Name) } - if nextItem.GetExtensionPayload() != nil { + payload := nextItem.GetExtensionPayload() + if payload != nil && len(payload.Payload) != 0 { return fmt.Errorf("extension %s don't exhausted payload stream", metadata.Name) + } else { + break } } diff --git a/tests/systemtests/cli.go b/tests/systemtests/cli.go index fcc6bb518c0..d7ac2368ae7 100644 --- a/tests/systemtests/cli.go +++ b/tests/systemtests/cli.go @@ -179,6 +179,13 @@ func (c CLIWrapper) RunAndWait(args ...string) string { return txResult } +// RunCommandWithArgs use for run cli command, not tx +func (c CLIWrapper) RunCommandWithArgs(args ...string) string { + c.t.Helper() + execOutput, _ := c.run(args) + return execOutput +} + // AwaitTxCommitted wait for tx committed on chain // returns the server execution result and true when found within 3 blocks. func (c CLIWrapper) AwaitTxCommitted(submitResp string, timeout ...time.Duration) (string, bool) { diff --git a/tests/systemtests/snapshots_test.go b/tests/systemtests/snapshots_test.go new file mode 100644 index 00000000000..42569a03179 --- /dev/null +++ b/tests/systemtests/snapshots_test.go @@ -0,0 +1,98 @@ +//go:build system_test + +package systemtests + +import ( + "fmt" + "github.com/stretchr/testify/require" + "os" + "testing" +) + +func TestSnapshots(t *testing.T) { + + sut.ResetChain(t) + cli := NewCLIWrapper(t, sut, verbose) + sut.StartChain(t) + + // Wait for chain produce some blocks + sut.AwaitNBlocks(t, 6) + // Stop all nodes + sut.StopChain() + + var ( + command string + restoreableDirs []string + ) + node0Dir := sut.NodeDir(0) + if isV2() { + command = "store" + restoreableDirs = []string{fmt.Sprintf("%s/data/application.db", node0Dir), fmt.Sprintf("%s/data/ss", node0Dir)} + } else { + command = "snapshots" + restoreableDirs = []string{fmt.Sprintf("%s/data/application.db", node0Dir)} + } + + // export snapshot at height 5 + res := cli.RunCommandWithArgs(command, "export", "--height=5", fmt.Sprintf("--home=%s", node0Dir)) + require.Contains(t, res, "Snapshot created at height 5") + require.DirExists(t, fmt.Sprintf("%s/data/snapshots/5/3", node0Dir)) + + // Check snapshots list + res = cli.RunCommandWithArgs(command, "list", fmt.Sprintf("--home=%s", node0Dir)) + require.Contains(t, res, "height: 5") + + // Dump snapshot + res = cli.RunCommandWithArgs(command, "dump", "5", "3", fmt.Sprintf("--home=%s", node0Dir), fmt.Sprintf("--output=%s/5-3.tar.gz", node0Dir)) + // Check if output file exist + require.FileExists(t, fmt.Sprintf("%s/5-3.tar.gz", node0Dir)) + + // Delete snapshots + res = cli.RunCommandWithArgs(command, "delete", "5", "3", fmt.Sprintf("--home=%s", node0Dir)) + require.NoDirExists(t, fmt.Sprintf("%s/data/snapshots/5/3", node0Dir)) + + // Load snapshot from file + res = cli.RunCommandWithArgs(command, "load", fmt.Sprintf("%s/5-3.tar.gz", node0Dir), fmt.Sprintf("--home=%s", node0Dir)) + require.DirExists(t, fmt.Sprintf("%s/data/snapshots/5/3", node0Dir)) + + // Restore from snapshots + for _, dir := range restoreableDirs { + require.NoError(t, os.RemoveAll(dir)) + } + // Remove database + err := os.RemoveAll(fmt.Sprintf("%s/data/application.db", node0Dir)) + require.NoError(t, err) + if isV2() { + require.NoError(t, os.RemoveAll(fmt.Sprintf("%s/data/ss", node0Dir))) + } + + res = cli.RunCommandWithArgs(command, "restore", "5", "3", fmt.Sprintf("--home=%s", node0Dir)) + for _, dir := range restoreableDirs { + require.DirExists(t, dir) + } +} + +func TestPrune(t *testing.T) { + sut.ResetChain(t) + cli := NewCLIWrapper(t, sut, verbose) + + sut.StartChain(t) + + // Wait for chain produce some blocks + sut.AwaitNBlocks(t, 6) + + // Stop all nodes + sut.StopChain() + + node0Dir := sut.NodeDir(0) + + // prune + var command []string + if isV2() { + command = []string{"store", "prune", "--keep-recent=1"} + } else { + command = []string{"prune", "everything"} + } + res := cli.RunCommandWithArgs(append(command, fmt.Sprintf("--home=%s", node0Dir))...) + require.Contains(t, res, "successfully pruned the application root multi stores") +} diff --git a/tests/systemtests/system.go b/tests/systemtests/system.go index 8505d20d786..d76d482b89e 100644 --- a/tests/systemtests/system.go +++ b/tests/systemtests/system.go @@ -360,7 +360,13 @@ func (s *SystemUnderTest) PrintBuffer() { }) } -// AwaitBlockHeight blocks until te target height is reached. An optional timeout parameter can be passed to abort early +// AwaitNBlocks blocks until the current height + n block is reached. An optional timeout parameter can be passed to abort early +func (s *SystemUnderTest) AwaitNBlocks(t *testing.T, n int64, timeout ...time.Duration) { + t.Helper() + s.AwaitBlockHeight(t, s.CurrentHeight()+n, timeout...) +} + +// AwaitBlockHeight blocks until the target height is reached. An optional timeout parameter can be passed to abort early func (s *SystemUnderTest) AwaitBlockHeight(t *testing.T, targetHeight int64, timeout ...time.Duration) { t.Helper() require.Greater(t, targetHeight, s.currentHeight.Load()) @@ -577,6 +583,7 @@ func (s *SystemUnderTest) startNodesAsync(t *testing.T, xargs ...string) { }) } +// tracks the PID in state with a go routine waiting for the shutdown completion to unregister func (s *SystemUnderTest) awaitProcessCleanup(cmd *exec.Cmd) { pid := cmd.Process.Pid s.pidsLock.Lock() @@ -597,6 +604,11 @@ func (s *SystemUnderTest) withEachNodeHome(cb func(i int, home string)) { } } +// NodeDir returns the workdir and path to the node home folder. +func (s *SystemUnderTest) NodeDir(i int) string { + return filepath.Join(WorkDir, s.nodePath(i)) +} + // nodePath returns the path of the node within the work dir. not absolute func (s *SystemUnderTest) nodePath(i int) string { return NodePath(i, s.outputDir, s.projectName) diff --git a/tests/systemtests/testnet_init.go b/tests/systemtests/testnet_init.go index c3cd9c0f73e..21f237ec78c 100644 --- a/tests/systemtests/testnet_init.go +++ b/tests/systemtests/testnet_init.go @@ -13,6 +13,12 @@ import ( "github.com/creachadair/tomledit/parser" ) +// isV2 checks if the tests run with simapp v2 +func isV2() bool { + buildOptions := os.Getenv("COSMOS_BUILD_OPTIONS") + return strings.Contains(buildOptions, "v2") +} + // SingleHostTestnetCmdInitializer default testnet cmd that supports the --single-host param type SingleHostTestnetCmdInitializer struct { execBinary string @@ -53,10 +59,16 @@ func (s SingleHostTestnetCmdInitializer) Initialize() { "--output-dir=" + s.outputDir, "--validator-count=" + strconv.Itoa(s.initialNodesCount), "--keyring-backend=test", - "--minimum-gas-prices=" + s.minGasPrice, "--commit-timeout=" + s.commitTimeout.String(), "--single-host", } + + if isV2() { + args = append(args, "--server.minimum-gas-prices="+s.minGasPrice) + } else { + args = append(args, "--minimum-gas-prices="+s.minGasPrice) + } + s.log(fmt.Sprintf("+++ %s %s\n", s.execBinary, strings.Join(args, " "))) out, err := RunShellCmd(s.execBinary, args...) if err != nil { @@ -108,8 +120,14 @@ func (s ModifyConfigYamlInitializer) Initialize() { "--output-dir=" + s.outputDir, "--v=" + strconv.Itoa(s.initialNodesCount), "--keyring-backend=test", - "--minimum-gas-prices=" + s.minGasPrice, } + + if isV2() { + args = append(args, "--server.minimum-gas-prices="+s.minGasPrice) + } else { + args = append(args, "--minimum-gas-prices="+s.minGasPrice) + } + s.log(fmt.Sprintf("+++ %s %s\n", s.execBinary, strings.Join(args, " "))) out, err := RunShellCmd(s.execBinary, args...)