mirror of
https://github.com/kopia/kopia.git
synced 2026-02-26 03:16:49 -05:00
* refactor(repository): moved format blob management to separate package This is completely mechanical, no behavior changes, only: - moved types and functions to a new package - adjusted visibility where needed - added missing godoc - renamed some identifiers to align with current usage - mechanically converted some top-level functions into member functions - fixed some mis-named variables * refactor(repository): moved content.FormatingOptions to format.ContentFormat
232 lines
9.9 KiB
Go
232 lines
9.9 KiB
Go
package cli_test
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/kopia/kopia/cli"
|
|
"github.com/kopia/kopia/internal/blobtesting"
|
|
"github.com/kopia/kopia/internal/repotesting"
|
|
"github.com/kopia/kopia/internal/testutil"
|
|
"github.com/kopia/kopia/repo/blob"
|
|
"github.com/kopia/kopia/repo/format"
|
|
"github.com/kopia/kopia/tests/testenv"
|
|
)
|
|
|
|
func (s *formatSpecificTestSuite) setupInMemoryRepo(t *testing.T) *testenv.CLITest {
|
|
t.Helper()
|
|
|
|
runner := testenv.NewInProcRunner(t)
|
|
env := testenv.NewCLITest(t, s.formatFlags, runner)
|
|
st := repotesting.NewReconnectableStorage(t, blobtesting.NewVersionedMapStorage(nil))
|
|
|
|
env.RunAndExpectSuccess(t, "repo", "create", "in-memory", "--uuid",
|
|
st.ConnectionInfo().Config.(*repotesting.ReconnectableStorageOptions).UUID)
|
|
|
|
return env
|
|
}
|
|
|
|
func (s *formatSpecificTestSuite) TestRepositorySetParameters(t *testing.T) {
|
|
env := s.setupInMemoryRepo(t)
|
|
out := env.RunAndExpectSuccess(t, "repository", "status")
|
|
|
|
// default values
|
|
require.Contains(t, out, "Max pack length: 20 MiB")
|
|
require.Contains(t, out, fmt.Sprintf("Format version: %d", s.formatVersion))
|
|
|
|
// failure cases
|
|
env.RunAndExpectFailure(t, "repository", "set-parameters")
|
|
env.RunAndExpectFailure(t, "repository", "set-parameters", "--index-version=33")
|
|
env.RunAndExpectFailure(t, "repository", "set-parameters", "--max-pack-size-mb=9")
|
|
env.RunAndExpectFailure(t, "repository", "set-parameters", "--max-pack-size-mb=121")
|
|
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--index-version=2", "--max-pack-size-mb=33")
|
|
out = env.RunAndExpectSuccess(t, "repository", "status")
|
|
require.Contains(t, out, "Max pack length: 33 MiB")
|
|
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--max-pack-size-mb=44")
|
|
out = env.RunAndExpectSuccess(t, "repository", "status")
|
|
require.Contains(t, out, "Max pack length: 44 MiB")
|
|
}
|
|
|
|
func (s *formatSpecificTestSuite) TestRepositorySetParametersRetention(t *testing.T) {
|
|
env := s.setupInMemoryRepo(t)
|
|
|
|
// set retention
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--retention-mode", blob.Compliance.String(),
|
|
"--retention-period", "24h")
|
|
|
|
out := env.RunAndExpectSuccess(t, "repository", "status")
|
|
require.Contains(t, out, "Blob retention mode: COMPLIANCE")
|
|
require.Contains(t, out, "Blob retention period: 24h0m0s")
|
|
|
|
// update retention
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--retention-mode", blob.Governance.String(),
|
|
"--retention-period", "24h1m")
|
|
|
|
out = env.RunAndExpectSuccess(t, "repository", "status")
|
|
require.Contains(t, out, "Blob retention mode: GOVERNANCE")
|
|
require.Contains(t, out, "Blob retention period: 24h1m0s")
|
|
|
|
// clear retention settings
|
|
_, out = env.RunAndExpectSuccessWithErrOut(t, "repository", "set-parameters", "--retention-mode", "none")
|
|
require.Contains(t, out, "disabling blob retention")
|
|
|
|
out = env.RunAndExpectSuccess(t, "repository", "status")
|
|
require.NotContains(t, out, "Blob retention mode")
|
|
require.NotContains(t, out, "Blob retention period")
|
|
|
|
// invalid retention settings
|
|
env.RunAndExpectFailure(t, "repository", "set-parameters", "--retention-mode", "invalid-mode")
|
|
env.RunAndExpectFailure(t, "repository", "set-parameters", "--retention-mode", "COMPLIANCE", "--retention-period", "0h")
|
|
env.RunAndExpectFailure(t, "repository", "set-parameters", "--retention-mode", "COMPLIANCE", "--retention-period", "6h") // less than 24hr
|
|
|
|
// set retention again after clear
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--retention-mode", "COMPLIANCE", "--retention-period", "24h")
|
|
out = env.RunAndExpectSuccess(t, "repository", "status")
|
|
require.Contains(t, out, "Blob retention mode: COMPLIANCE")
|
|
require.Contains(t, out, "Blob retention period: 24h0m0s")
|
|
|
|
// update without period
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--retention-period", "25h")
|
|
out = env.RunAndExpectSuccess(t, "repository", "status")
|
|
require.Contains(t, out, "Blob retention mode: COMPLIANCE")
|
|
require.Contains(t, out, "Blob retention period: 25h0m0s")
|
|
|
|
// update without mode
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--retention-mode", "GOVERNANCE")
|
|
out = env.RunAndExpectSuccess(t, "repository", "status")
|
|
require.Contains(t, out, "Blob retention mode: GOVERNANCE")
|
|
require.Contains(t, out, "Blob retention period: 25h0m0s")
|
|
|
|
// update retention (use days, weeks, nanoseconds)
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--retention-mode", blob.Compliance.String(),
|
|
"--retention-period", "1w2d6h3ns")
|
|
|
|
out = env.RunAndExpectSuccess(t, "repository", "status")
|
|
require.Contains(t, out, "Blob retention mode: COMPLIANCE")
|
|
require.Contains(t, out, "Blob retention period: 222h0m0.000000003s")
|
|
|
|
// update retention (use days)
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--retention-mode", blob.Compliance.String(),
|
|
"--retention-period", "7d")
|
|
|
|
out = env.RunAndExpectSuccess(t, "repository", "status")
|
|
require.Contains(t, out, "Blob retention mode: COMPLIANCE")
|
|
require.Contains(t, out, "Blob retention period: 168h0m0s")
|
|
}
|
|
|
|
func (s *formatSpecificTestSuite) TestRepositorySetParametersUpgrade(t *testing.T) {
|
|
env := s.setupInMemoryRepo(t)
|
|
out := env.RunAndExpectSuccess(t, "repository", "status")
|
|
|
|
// default values
|
|
require.Contains(t, out, "Max pack length: 20 MiB")
|
|
|
|
switch s.formatVersion {
|
|
case format.FormatVersion1:
|
|
require.Contains(t, out, "Format version: 1")
|
|
require.Contains(t, out, "Epoch Manager: disabled")
|
|
env.RunAndExpectFailure(t, "index", "epoch", "list")
|
|
case format.FormatVersion2:
|
|
require.Contains(t, out, "Format version: 2")
|
|
require.Contains(t, out, "Epoch Manager: enabled")
|
|
env.RunAndExpectSuccess(t, "index", "epoch", "list")
|
|
default:
|
|
require.Contains(t, out, "Format version: 3")
|
|
require.Contains(t, out, "Epoch Manager: enabled")
|
|
env.RunAndExpectSuccess(t, "index", "epoch", "list")
|
|
}
|
|
|
|
env.Environment["KOPIA_UPGRADE_LOCK_ENABLED"] = "1"
|
|
|
|
{
|
|
cmd := []string{
|
|
"repository", "upgrade",
|
|
"--upgrade-owner-id", "owner",
|
|
"--io-drain-timeout", "1s", "--allow-unsafe-upgrade",
|
|
"--status-poll-interval", "1s",
|
|
}
|
|
|
|
cli.MaxPermittedClockDrift = func() time.Duration { return time.Second }
|
|
|
|
// You can only upgrade when you are not already upgraded
|
|
if s.formatVersion < format.MaxFormatVersion {
|
|
env.RunAndExpectSuccess(t, cmd...)
|
|
} else {
|
|
env.RunAndExpectFailure(t, cmd...)
|
|
}
|
|
}
|
|
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--upgrade")
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--epoch-min-duration", "3h")
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--epoch-cleanup-safety-margin", "23h")
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--epoch-advance-on-size-mb", "77")
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--epoch-advance-on-count", "22")
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--epoch-checkpoint-frequency", "9")
|
|
|
|
env.RunAndExpectFailure(t, "repository", "set-parameters", "--epoch-min-duration", "1s")
|
|
env.RunAndExpectFailure(t, "repository", "set-parameters", "--epoch-refresh-frequency", "10h")
|
|
env.RunAndExpectFailure(t, "repository", "set-parameters", "--epoch-checkpoint-frequency", "-10")
|
|
env.RunAndExpectFailure(t, "repository", "set-parameters", "--epoch-cleanup-safety-margin", "10s")
|
|
env.RunAndExpectFailure(t, "repository", "set-parameters", "--epoch-advance-on-count", "1")
|
|
|
|
out = env.RunAndExpectSuccess(t, "repository", "status")
|
|
require.Contains(t, out, "Epoch Manager: enabled")
|
|
require.Contains(t, out, "Index Format: v2")
|
|
require.Contains(t, out, "Format version: 3")
|
|
require.Contains(t, out, "Epoch cleanup margin: 23h0m0s")
|
|
require.Contains(t, out, "Epoch advance on: 22 blobs or 77 MiB, minimum 3h0m0s")
|
|
require.Contains(t, out, "Epoch checkpoint every: 9 epochs")
|
|
|
|
env.RunAndExpectSuccess(t, "index", "epoch", "list")
|
|
}
|
|
|
|
func (s *formatSpecificTestSuite) TestRepositorySetParametersRequiredFeatures(t *testing.T) {
|
|
env := s.setupInMemoryRepo(t)
|
|
|
|
env.RunAndExpectSuccess(t, "repository", "status")
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--add-required-feature", "no-such-feature")
|
|
env.RunAndExpectFailure(t, "repository", "status")
|
|
env.RunAndExpectSuccess(t, "repository", "status", "--ignore-missing-required-features")
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--remove-required-feature", "no-such-feature", "--ignore-missing-required-features")
|
|
env.RunAndExpectSuccess(t, "repository", "status")
|
|
|
|
// now require a feature but with a warning
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--add-required-feature", "no-such-feature", "--warn-on-missing-required-feature")
|
|
env.RunAndExpectSuccess(t, "repository", "status")
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--remove-required-feature", "no-such-feature")
|
|
}
|
|
|
|
func (s *formatSpecificTestSuite) TestRepositorySetParametersRequiredFeatures_ServerMode(t *testing.T) {
|
|
env := s.setupInMemoryRepo(t)
|
|
|
|
env.RunAndExpectSuccess(t, "repo", "set-client", "--repository-format-cache-duration=1s")
|
|
|
|
var sp testutil.ServerParameters
|
|
|
|
snapDir := testutil.TempDirectory(t)
|
|
|
|
// create a snapshot that will be created every second
|
|
env.RunAndExpectSuccess(t, "snapshot", "create", snapDir)
|
|
env.RunAndExpectSuccess(t, "policy", "set", "--snapshot-interval=1s", snapDir)
|
|
|
|
wait, _ := env.RunAndProcessStderr(t, sp.ProcessOutput,
|
|
"server", "start",
|
|
"--address=localhost:0",
|
|
"--server-control-password=admin-pwd",
|
|
"--tls-generate-cert",
|
|
"--tls-generate-rsa-key-size=2048", // use shorter key size to speed up generation
|
|
)
|
|
|
|
// now introduce required parameters while the server is running
|
|
env.RunAndExpectSuccess(t, "repository", "set-parameters", "--add-required-feature", "no-such-feature")
|
|
|
|
// we are aggressively creating snapshots every second,
|
|
// the server will soon notice the new required feature and shut down.
|
|
require.ErrorContains(t, wait(), "no-such-feature")
|
|
}
|