chore(general): enable forcetypeassert linter (#4624)

- enable `forcetypeassert` linter in non-test files
- add `//nolint` annotations
- add `testutil.EnsureType` helper for type assertions
- enable `forcetypeassert` linter in test files
This commit is contained in:
Julio Lopez
2025-05-31 23:17:38 -07:00
committed by GitHub
parent 44566ec50c
commit d91a5a8f94
32 changed files with 156 additions and 99 deletions

View File

@@ -84,7 +84,6 @@ linters:
default: all
disable:
- exhaustruct
- forcetypeassert
- funcorder
- gochecknoglobals
- gochecknoinits
@@ -120,7 +119,6 @@ linters:
- contextcheck
- errcheck
- errchkjson
- forcetypeassert
- funlen
- gochecknoglobals
- gocognit

View File

@@ -20,9 +20,9 @@ func (s *formatSpecificTestSuite) setupInMemoryRepo(t *testing.T) *testenv.CLITe
runner := testenv.NewInProcRunner(t)
env := testenv.NewCLITest(t, s.formatFlags, runner)
st := repotesting.NewReconnectableStorage(t, blobtesting.NewVersionedMapStorage(nil))
o := testutil.EnsureType[*repotesting.ReconnectableStorageOptions](t, st.ConnectionInfo().Config)
env.RunAndExpectSuccess(t, "repo", "create", "in-memory", "--uuid",
st.ConnectionInfo().Config.(*repotesting.ReconnectableStorageOptions).UUID)
env.RunAndExpectSuccess(t, "repo", "create", "in-memory", "--uuid", o.UUID)
return env
}

View File

@@ -255,12 +255,12 @@ func (s *eventuallyConsistentStorage) ListBlobs(ctx context.Context, prefix blob
// process recently deleted items and resurrect them with some probability
s.recentlyDeleted.Range(func(key, value any) bool {
blobID := key.(blob.ID)
blobID := key.(blob.ID) //nolint:forcetypeassert
if !strings.HasPrefix(string(blobID), string(prefix)) {
return true
}
bm := value.(blob.Metadata)
bm := value.(blob.Metadata) //nolint:forcetypeassert
if age := now.Sub(bm.Timestamp); s.shouldApplyInconsistency(ctx, age, "resurrect recently deleted "+string(bm.BlobID)) {
if resultErr = callback(bm); resultErr != nil {
return false

View File

@@ -15,6 +15,7 @@
"github.com/kopia/kopia/internal/cache"
"github.com/kopia/kopia/internal/gather"
"github.com/kopia/kopia/internal/testlogging"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/repo/blob"
)
@@ -89,7 +90,7 @@ func testContentCachePrefetchBlocksGetContent(t *testing.T, newCache newContentC
faulty := blobtesting.NewFaultyStorage(underlying)
cacheData := blobtesting.DataMap{}
metadataCacheStorage := blobtesting.NewMapStorage(cacheData, nil, nil).(cache.Storage)
metadataCacheStorage := testutil.EnsureType[cache.Storage](t, blobtesting.NewMapStorage(cacheData, nil, nil))
dataCache, err := newCache(ctx, faulty, metadataCacheStorage)
require.NoError(t, err)
@@ -157,7 +158,7 @@ func testGetContentForDifferentContentIDsExecutesInParallel(t *testing.T, newCac
faulty := blobtesting.NewFaultyStorage(underlying)
cacheData := blobtesting.DataMap{}
metadataCacheStorage := blobtesting.NewMapStorage(cacheData, nil, nil).(cache.Storage)
metadataCacheStorage := testutil.EnsureType[cache.Storage](t, blobtesting.NewMapStorage(cacheData, nil, nil))
dataCache, err := newCache(ctx, faulty, metadataCacheStorage)
require.NoError(t, err)
@@ -203,7 +204,7 @@ func testGetContentForDifferentBlobsExecutesInParallel(t *testing.T, newCache ne
faulty := blobtesting.NewFaultyStorage(underlying)
cacheData := blobtesting.DataMap{}
metadataCacheStorage := blobtesting.NewMapStorage(cacheData, nil, nil).(cache.Storage)
metadataCacheStorage := testutil.EnsureType[cache.Storage](t, blobtesting.NewMapStorage(cacheData, nil, nil))
dataCache, err := newCache(ctx, faulty, metadataCacheStorage)
require.NoError(t, err)
@@ -251,7 +252,7 @@ func testGetContentRaceFetchesOnce(t *testing.T, newCache newContentCacheFunc) {
faulty := blobtesting.NewFaultyStorage(underlying)
cacheData := blobtesting.DataMap{}
metadataCacheStorage := blobtesting.NewMapStorage(cacheData, nil, nil).(cache.Storage)
metadataCacheStorage := testutil.EnsureType[cache.Storage](t, blobtesting.NewMapStorage(cacheData, nil, nil))
dataCache, err := newCache(ctx, faulty, metadataCacheStorage)
require.NoError(t, err)

View File

@@ -9,6 +9,7 @@
"github.com/kopia/kopia/internal/cache"
"github.com/kopia/kopia/internal/gather"
"github.com/kopia/kopia/internal/testlogging"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/repo/blob"
)
@@ -19,7 +20,7 @@ func TestContentCacheForData(t *testing.T) {
underlying := blobtesting.NewMapStorage(underlyingData, nil, nil)
cacheData := blobtesting.DataMap{}
cacheStorage := blobtesting.NewMapStorage(cacheData, nil, nil).(cache.Storage)
cacheStorage := testutil.EnsureType[cache.Storage](t, blobtesting.NewMapStorage(cacheData, nil, nil))
dataCache, err := cache.NewContentCache(ctx, underlying, cache.Options{
Storage: cacheStorage,

View File

@@ -108,13 +108,13 @@ func verifyCacheExpiration(t *testing.T, sweepSettings cache.SweepSettings, want
return currentTime
}
cacheStorage := blobtesting.NewMapStorage(cacheData, nil, movingTimeFunc)
cacheStorage := testutil.EnsureType[cache.Storage](t, blobtesting.NewMapStorage(cacheData, nil, movingTimeFunc))
underlyingStorage := newUnderlyingStorageForContentCacheTesting(t)
ctx := testlogging.Context(t)
cc, err := cache.NewContentCache(ctx, underlyingStorage, cache.Options{
Storage: cacheStorage.(cache.Storage),
Storage: cacheStorage,
Sweep: sweepSettings,
TimeNow: movingTimeFunc,
}, nil)

View File

@@ -25,7 +25,7 @@ func TestPersistentLRUCache(t *testing.T) {
const maxSizeBytes = 1000
cs := blobtesting.NewMapStorageWithLimit(blobtesting.DataMap{}, nil, nil, maxSizeBytes).(cache.Storage)
cs := testutil.EnsureType[cache.Storage](t, blobtesting.NewMapStorageWithLimit(blobtesting.DataMap{}, nil, nil, maxSizeBytes))
pc, err := cache.NewPersistentCache(ctx, "testing", cs, cacheprot.ChecksumProtection([]byte{1, 2, 3}), cache.SweepSettings{
MaxSizeBytes: maxSizeBytes,

View File

@@ -13,6 +13,7 @@
"github.com/kopia/kopia/internal/connection"
"github.com/kopia/kopia/internal/testlogging"
"github.com/kopia/kopia/internal/testutil"
)
var (
@@ -74,7 +75,8 @@ func TestConnection(t *testing.T) {
r := connection.NewReconnector(fc)
v, err := connection.UsingConnection(ctx, r, "first", func(cli connection.Connection) (any, error) {
require.EqualValues(t, 1, cli.(*fakeConnection).id)
require.EqualValues(t, 1, testutil.EnsureType[*fakeConnection](t, cli).id)
return "foo", nil
})
@@ -84,20 +86,22 @@ func TestConnection(t *testing.T) {
cnt := 0
r.UsingConnectionNoResult(ctx, "second", func(cli connection.Connection) error {
t.Logf("second called with %v", cli.(*fakeConnection).id)
fcon := testutil.EnsureType[*fakeConnection](t, cli)
t.Log("second called with", fcon.id)
// still using connection # 1
if cnt == 0 {
cnt++
require.EqualValues(t, 1, cli.(*fakeConnection).id)
require.EqualValues(t, 1, fcon.id)
cli.(*fakeConnection).isClosed = true
fcon.isClosed = true
return errFakeConnectionFailed
}
require.EqualValues(t, 2, cli.(*fakeConnection).id)
require.EqualValues(t, 2, fcon.id)
return nil
})
@@ -105,8 +109,10 @@ func TestConnection(t *testing.T) {
require.EqualValues(t, 2, fc.nextConnectionID.Load())
r.UsingConnectionNoResult(ctx, "third", func(cli connection.Connection) error {
t.Logf("third called with %v", cli.(*fakeConnection).id)
require.EqualValues(t, 2, cli.(*fakeConnection).id)
id0 := testutil.EnsureType[*fakeConnection](t, cli).id
t.Log("third called with", id0)
require.EqualValues(t, 2, id0)
return nil
})
@@ -114,12 +120,16 @@ func TestConnection(t *testing.T) {
require.EqualValues(t, 2, fc.nextConnectionID.Load())
r.UsingConnectionNoResult(ctx, "parallel-1", func(cli connection.Connection) error {
t.Logf("parallel-1 called with %v", cli.(*fakeConnection).id)
require.EqualValues(t, 2, cli.(*fakeConnection).id)
id1 := testutil.EnsureType[*fakeConnection](t, cli).id
t.Log("parallel-1 called with", id1)
require.EqualValues(t, 2, id1)
r.UsingConnectionNoResult(ctx, "parallel-2", func(cli connection.Connection) error {
t.Logf("parallel-2 called with %v", cli.(*fakeConnection).id)
require.EqualValues(t, 2, cli.(*fakeConnection).id)
id2 := testutil.EnsureType[*fakeConnection](t, cli).id
t.Log("parallel-2 called with", id2)
require.EqualValues(t, 2, id2)
return nil
})
@@ -130,8 +140,10 @@ func TestConnection(t *testing.T) {
r.CloseActiveConnection(ctx)
require.NoError(t, r.UsingConnectionNoResult(ctx, "fourth", func(cli connection.Connection) error {
t.Logf("fourth called with %v", cli.(*fakeConnection).id)
require.EqualValues(t, 3, cli.(*fakeConnection).id)
id3 := testutil.EnsureType[*fakeConnection](t, cli).id
t.Log("fourth called with", id3)
require.EqualValues(t, 3, id3)
return nil
}))
@@ -148,8 +160,10 @@ func TestConnection(t *testing.T) {
fc.nextError = errFakeConnectionFailed
require.NoError(t, r.UsingConnectionNoResult(ctx, "sixth", func(cli connection.Connection) error {
t.Logf("sixth called with %v", cli.(*fakeConnection).id)
require.EqualValues(t, 4, cli.(*fakeConnection).id)
id4 := testutil.EnsureType[*fakeConnection](t, cli).id
t.Log("sixth called with", id4)
require.EqualValues(t, 4, id4)
return nil
}))
@@ -159,7 +173,7 @@ func TestConnection(t *testing.T) {
eg.Go(func() error {
return r.UsingConnectionNoResult(ctx, "parallel-a", func(cli connection.Connection) error {
time.Sleep(500 * time.Millisecond)
t.Logf("parallel-a called with %v", cli.(*fakeConnection).id)
t.Log("parallel-a called with", testutil.EnsureType[*fakeConnection](t, cli).id)
return nil
})
@@ -167,7 +181,7 @@ func TestConnection(t *testing.T) {
eg.Go(func() error {
return r.UsingConnectionNoResult(ctx, "parallel-b", func(cli connection.Connection) error {
time.Sleep(300 * time.Millisecond)
t.Logf("parallel-b called with %v", cli.(*fakeConnection).id)
t.Log("parallel-b called with", testutil.EnsureType[*fakeConnection](t, cli).id)
return nil
})
@@ -175,7 +189,7 @@ func TestConnection(t *testing.T) {
eg.Go(func() error {
return r.UsingConnectionNoResult(ctx, "parallel-c", func(cli connection.Connection) error {
time.Sleep(100 * time.Millisecond)
t.Logf("parallel-c called with %v", cli.(*fakeConnection).id)
t.Log("parallel-c called with", testutil.EnsureType[*fakeConnection](t, cli).id)
return nil
})

View File

@@ -862,7 +862,7 @@ func verifySequentialWrites(t *testing.T, te *epochManagerTestEnv) {
func TestIndexEpochManager_Disabled(t *testing.T) {
te := newTestEnv(t)
te.mgr.paramProvider.(parameterProvider).Enabled = false
testutil.EnsureType[parameterProvider](t, te.mgr.paramProvider).Enabled = false
_, err := te.mgr.Current(testlogging.Context(t))
require.Error(t, err)

View File

@@ -73,7 +73,7 @@ type fuseFileNode struct {
}
func (f *fuseFileNode) Open(ctx context.Context, _ uint32) (gofusefs.FileHandle, uint32, syscall.Errno) {
reader, err := f.entry.(fs.File).Open(ctx)
reader, err := f.entry.(fs.File).Open(ctx) //nolint:forcetypeassert
if err != nil {
log(ctx).Errorf("error opening %v: %v", f.entry.Name(), err)
@@ -198,7 +198,7 @@ type fuseSymlinkNode struct {
}
func (sl *fuseSymlinkNode) Readlink(ctx context.Context) ([]byte, syscall.Errno) {
v, err := sl.entry.(fs.Symlink).Readlink(ctx)
v, err := sl.entry.(fs.Symlink).Readlink(ctx) //nolint:forcetypeassert
if err != nil {
log(ctx).Errorf("error reading symlink %v: %v", sl.entry.Name(), err)
return nil, syscall.EIO

View File

@@ -10,6 +10,8 @@
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
"github.com/kopia/kopia/internal/testutil"
)
var sample1 = []byte("hello! how are you? nice to meet you.")
@@ -236,7 +238,7 @@ func TestGatherBytesReaderAtErrorResponses(t *testing.T) {
defer reader.Close() //nolint:errcheck
// get the reader as a ReaderAt
readerAt := reader.(io.ReaderAt)
readerAt := testutil.EnsureType[io.ReaderAt](t, reader)
// make an output buffer of the required length
bs := make([]byte, tc.inBsLen)

View File

@@ -11,6 +11,7 @@
"github.com/kopia/kopia/internal/faketime"
"github.com/kopia/kopia/internal/gather"
"github.com/kopia/kopia/internal/testlogging"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/repo/blob"
)
@@ -22,7 +23,9 @@ func TestListCache(t *testing.T) {
cacheTime := faketime.NewTimeAdvance(time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC))
cachest := blobtesting.NewMapStorage(blobtesting.DataMap{}, nil, cacheTime.NowFunc())
lc := NewWrapper(realStorage, cachest, []blob.ID{"n", "xe", "xb"}, []byte("hmac-secret"), 1*time.Minute).(*listCacheStorage)
w := NewWrapper(realStorage, cachest, []blob.ID{"n", "xe", "xb"}, []byte("hmac-secret"), 1*time.Minute)
lc := testutil.EnsureType[*listCacheStorage](t, w)
lc.cacheTimeFunc = cacheTime.NowFunc()
ctx := testlogging.Context(t)

View File

@@ -10,6 +10,7 @@
"github.com/kopia/kopia/internal/faketime"
"github.com/kopia/kopia/internal/gather"
"github.com/kopia/kopia/internal/testlogging"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/repo/blob"
)
@@ -23,7 +24,7 @@ func TestOwnWrites(t *testing.T) {
ec := blobtesting.NewEventuallyConsistentStorage(realStorage, 1*time.Hour, realStorageTime.NowFunc())
ow := NewWrapper(ec, cachest, []blob.ID{"n"}, testCacheDuration)
ow.(*CacheStorage).cacheTimeFunc = cacheTime.NowFunc()
testutil.EnsureType[*CacheStorage](t, ow).cacheTimeFunc = cacheTime.NowFunc()
ctx := testlogging.Context(t)

View File

@@ -67,7 +67,7 @@ func New(ctx context.Context, opt *ReconnectableStorageOptions, isCreate bool) (
return nil, errors.Errorf("reconnectable storage not found: %v", opt.UUID)
}
return v.(blob.Storage), nil
return v.(blob.Storage), nil //nolint:forcetypeassert
}
func init() {

View File

@@ -45,7 +45,7 @@ type Options struct {
// RepositoryMetrics returns metrics.Registry associated with a repository.
func (e *Environment) RepositoryMetrics() *metrics.Registry {
return e.Repository.(interface {
return e.Repository.(interface { //nolint:forcetypeassert
Metrics() *metrics.Registry
}).Metrics()
}
@@ -53,7 +53,7 @@ func (e *Environment) RepositoryMetrics() *metrics.Registry {
// RootStorage returns the base storage map that implements the base in-memory
// map at the base of all storage wrappers on top.
func (e *Environment) RootStorage() blob.Storage {
return e.st.(reconnectableStorage).Storage
return e.st.(reconnectableStorage).Storage //nolint:forcetypeassert
}
// setup sets up a test environment.
@@ -126,7 +126,7 @@ func (e *Environment) setup(tb testing.TB, version format.Version, opts ...Optio
e.Repository = rep
_, e.RepositoryWriter, err = rep.(repo.DirectRepository).NewDirectWriter(ctx, repo.WriteSessionOptions{Purpose: "test"})
_, e.RepositoryWriter, err = testutil.EnsureType[repo.DirectRepository](tb, rep).NewDirectWriter(ctx, repo.WriteSessionOptions{Purpose: "test"})
require.NoError(tb, err)
tb.Cleanup(func() {
@@ -177,7 +177,7 @@ func (e *Environment) MustReopen(tb testing.TB, openOpts ...func(*repo.Options))
tb.Cleanup(func() { rep.Close(ctx) })
_, e.RepositoryWriter, err = rep.(repo.DirectRepository).NewDirectWriter(ctx, repo.WriteSessionOptions{Purpose: "test"})
_, e.RepositoryWriter, err = testutil.EnsureType[repo.DirectRepository](tb, rep).NewDirectWriter(ctx, repo.WriteSessionOptions{Purpose: "test"})
require.NoError(tb, err)
}

View File

@@ -9,6 +9,7 @@
"github.com/kopia/kopia/internal/faketime"
"github.com/kopia/kopia/internal/gather"
"github.com/kopia/kopia/internal/mockfs"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/repo"
"github.com/kopia/kopia/repo/content"
"github.com/kopia/kopia/snapshot"
@@ -27,7 +28,7 @@ func TestTimeFuncWiring(t *testing.T) {
t.Fatal("Failed to open repo:", err)
}
r0 := rep.(repo.DirectRepository)
r0 := testutil.EnsureType[repo.DirectRepository](t, rep)
_, env.RepositoryWriter, err = r0.NewDirectWriter(ctx, repo.WriteSessionOptions{Purpose: "test"})
require.NoError(t, err)

View File

@@ -177,3 +177,17 @@ func MustGetTotalDirSize(t *testing.T, dirpath string) int64 {
return total
}
// EnsureType asserts that v of type E.
func EnsureType[E any](tb testing.TB, v any) E {
tb.Helper()
var e E
// require.IsType would not elide the forced type assertion
e, ok := v.(E)
require.Truef(tb, ok, "%T is not of type %T", v, e)
return e
}

View File

@@ -102,7 +102,7 @@ func TestFileStorageTouch(t *testing.T) {
t.Errorf("unexpected result: %v %v", r, err)
}
fs := r.(*fsStorage)
fs := testutil.EnsureType[*fsStorage](t, r)
assertNoError(t, fs.PutBlob(ctx, t1, gather.FromSlice([]byte{1}), blob.PutOptions{}))
time.Sleep(2 * time.Second) // sleep a bit to accommodate Apple filesystems with low timestamp resolution
assertNoError(t, fs.PutBlob(ctx, t2, gather.FromSlice([]byte{1}), blob.PutOptions{}))
@@ -232,12 +232,20 @@ func TestFileStorage_GetMetadata_RetriesOnError(t *testing.T) {
require.NoError(t, st.PutBlob(ctx, "someblob1234567812345678", gather.FromSlice([]byte{1, 2, 3}), blob.PutOptions{}))
st.(*fsStorage).Impl.(*fsImpl).osi = osi
asFsImpl(t, st).osi = osi
_, err = st.GetMetadata(ctx, "someblob1234567812345678")
require.NoError(t, err)
}
func asFsImpl(t *testing.T, st blob.Storage) *fsImpl {
t.Helper()
fsSt := testutil.EnsureType[*fsStorage](t, st)
return testutil.EnsureType[*fsImpl](t, fsSt.Impl)
}
func TestFileStorage_PutBlob_RetriesOnErrors(t *testing.T) {
t.Parallel()
@@ -269,7 +277,7 @@ func TestFileStorage_PutBlob_RetriesOnErrors(t *testing.T) {
}, true)
require.NoError(t, err)
st.(*fsStorage).Impl.(*fsImpl).osi = osi
asFsImpl(t, st).osi = osi
defer st.Close(ctx)
@@ -310,7 +318,7 @@ func TestFileStorage_DeleteBlob_ErrorHandling(t *testing.T) {
}, true)
require.NoError(t, err)
st.(*fsStorage).Impl.(*fsImpl).osi = osi
asFsImpl(t, st).osi = osi
defer st.Close(ctx)
@@ -381,7 +389,7 @@ func TestFileStorage_ListBlobs_ErrorHandling(t *testing.T) {
}, true)
require.NoError(t, err)
st.(*fsStorage).Impl.(*fsImpl).osi = osi
asFsImpl(t, st).osi = osi
defer st.Close(ctx)
@@ -419,7 +427,7 @@ func TestFileStorage_TouchBlob_ErrorHandling(t *testing.T) {
}, true)
require.NoError(t, err)
st.(*fsStorage).Impl.(*fsImpl).osi = osi
asFsImpl(t, st).osi = osi
defer st.Close(ctx)
@@ -427,7 +435,7 @@ func TestFileStorage_TouchBlob_ErrorHandling(t *testing.T) {
osi.statRemainingErrors.Store(1)
_, err = st.(*fsStorage).TouchBlob(ctx, "someblob1234567812345678", 0)
_, err = testutil.EnsureType[*fsStorage](t, st).TouchBlob(ctx, "someblob1234567812345678", 0)
require.NoError(t, err)
}

View File

@@ -33,9 +33,10 @@ func TestFileStorage_ESTALE_ErrorHandling(t *testing.T) {
}, true)
require.NoError(t, err)
st.(*fsStorage).Impl.(*fsImpl).osi = osi
fsi := asFsImpl(t, st)
fsi.osi = osi
require.False(t, st.(*fsStorage).Impl.(*fsImpl).isRetriable(syscall.ESTALE), "ESTALE should not be retryable")
require.False(t, fsi.isRetriable(syscall.ESTALE), "ESTALE should not be retryable")
defer st.Close(ctx)

View File

@@ -8,6 +8,7 @@
"github.com/stretchr/testify/require"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/repo/blob"
)
@@ -35,9 +36,11 @@ func TestRegistry(t *testing.T) {
}, true)
require.NoError(t, err)
require.IsType(t, (*myStorage)(nil), st)
require.Equal(t, 4, st.(*myStorage).cfg.Field)
require.True(t, st.(*myStorage).create)
mySt := testutil.EnsureType[*myStorage](t, st)
require.Equal(t, 4, mySt.cfg.Field)
require.True(t, mySt.create)
_, err = blob.NewStorage(context.Background(), blob.ConnectionInfo{
Type: "unknownstorage",

View File

@@ -11,6 +11,7 @@
"github.com/kopia/kopia/internal/blobtesting"
"github.com/kopia/kopia/internal/faketime"
"github.com/kopia/kopia/internal/repotesting"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/repo"
"github.com/kopia/kopia/repo/blob"
"github.com/kopia/kopia/repo/encryption"
@@ -57,7 +58,7 @@ func (s *formatSpecificTestSuite) TestExtendBlobRetention(t *testing.T) {
}
lastBlobIdx := len(blobsBefore) - 1
st := env.RootStorage().(blobtesting.RetentionStorage)
st := testutil.EnsureType[blobtesting.RetentionStorage](t, env.RootStorage())
// Verify that file is locked
gotMode, expiry, err := st.GetRetention(ctx, blobsBefore[lastBlobIdx].BlobID)

View File

@@ -5,6 +5,7 @@
"github.com/stretchr/testify/require"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/repo/encryption"
)
@@ -114,7 +115,8 @@ func testRsCrc32ChangeInData(t *testing.T, opts *Options, originalSize, changedB
testPutAndGet(t, opts, originalSize, expectedEccSize, expectedSuccess,
func(impl encryption.Encryptor, data []byte) {
sizes := impl.(*ReedSolomonCrcECC).computeSizesFromOriginal(originalSize)
ecc := testutil.EnsureType[*ReedSolomonCrcECC](t, impl)
sizes := ecc.computeSizesFromOriginal(originalSize)
parity := sizes.ParityShards * (crcSize + sizes.ShardSize) * sizes.Blocks
for i := range changedBytes {
@@ -128,7 +130,8 @@ func testRsCrc32ChangeInDataCrc(t *testing.T, opts *Options, originalSize, chang
testPutAndGet(t, opts, originalSize, expectedEccSize, expectedSuccess,
func(impl encryption.Encryptor, data []byte) {
sizes := impl.(*ReedSolomonCrcECC).computeSizesFromOriginal(originalSize)
ecc := testutil.EnsureType[*ReedSolomonCrcECC](t, impl)
sizes := ecc.computeSizesFromOriginal(originalSize)
parity := sizes.ParityShards * (crcSize + sizes.ShardSize) * sizes.Blocks
for i := range changedBytes {
@@ -142,7 +145,8 @@ func testRsCrc32ChangeInParity(t *testing.T, opts *Options, originalSize, change
testPutAndGet(t, opts, originalSize, expectedEccSize, expectedSuccess,
func(impl encryption.Encryptor, data []byte) {
sizes := impl.(*ReedSolomonCrcECC).computeSizesFromOriginal(originalSize)
ecc := testutil.EnsureType[*ReedSolomonCrcECC](t, impl)
sizes := ecc.computeSizesFromOriginal(originalSize)
for i := range changedBytes {
flipByte(data, i*(crcSize+sizes.ShardSize)+crcSize)
@@ -155,7 +159,8 @@ func testRsCrc32ChangeInParityCrc(t *testing.T, opts *Options, originalSize, cha
testPutAndGet(t, opts, originalSize, expectedEccSize, expectedSuccess,
func(impl encryption.Encryptor, data []byte) {
sizes := impl.(*ReedSolomonCrcECC).computeSizesFromOriginal(originalSize)
ecc := testutil.EnsureType[*ReedSolomonCrcECC](t, impl)
sizes := ecc.computeSizesFromOriginal(originalSize)
for i := range changedBytes {
flipByte(data, i*(crcSize+sizes.ShardSize))

View File

@@ -171,7 +171,7 @@ func TestFormatUpgradeMultipleLocksRollback(t *testing.T) {
// second lock from a random owner
secondL := l.Clone()
secondL.OwnerID = "another-upgrade-owner"
_, err = secondWriter.(repo.DirectRepositoryWriter).FormatManager().SetUpgradeLockIntent(ctx, *secondL)
_, err = testutil.EnsureType[repo.DirectRepositoryWriter](t, secondWriter).FormatManager().SetUpgradeLockIntent(ctx, *secondL)
require.NoError(t, err)
// verify that we have two repository backups, the second one will contain
@@ -290,31 +290,33 @@ func(ctx context.Context, id blob.ID, _ *blob.PutOptions) error {
r, err := repo.Open(testlogging.Context(t), configFile, "password", &repo.Options{UpgradeOwnerID: "allowed-upgrade-owner"})
require.NoError(t, err)
_, err = r.(repo.DirectRepositoryWriter).FormatManager().SetUpgradeLockIntent(testlogging.Context(t), *faultyLock)
drw := testutil.EnsureType[repo.DirectRepositoryWriter](t, r)
_, err = drw.FormatManager().SetUpgradeLockIntent(testlogging.Context(t), *faultyLock)
require.EqualError(t, err, "failed to backup the repo format blob: unable to write format blob \"kopia.repository.backup.faulty-upgrade-owner\": unexpected error")
_, err = r.(repo.DirectRepositoryWriter).FormatManager().SetUpgradeLockIntent(testlogging.Context(t), allowedLock)
_, err = drw.FormatManager().SetUpgradeLockIntent(testlogging.Context(t), allowedLock)
require.NoError(t, err)
require.EqualError(t, r.(repo.DirectRepositoryWriter).FormatManager().RollbackUpgrade(testlogging.Context(t)),
require.EqualError(t, drw.FormatManager().RollbackUpgrade(testlogging.Context(t)),
"failed to delete the format blob backup \"kopia.repository.backup.allowed-upgrade-owner\": unexpected error")
require.EqualError(t, r.(repo.DirectRepositoryWriter).FormatManager().RollbackUpgrade(testlogging.Context(t)),
require.EqualError(t, drw.FormatManager().RollbackUpgrade(testlogging.Context(t)),
"failed to delete the format blob backup \"kopia.repository.backup.allowed-upgrade-owner\": unexpected error")
allowPuts = false
require.EqualError(t, r.(repo.DirectRepositoryWriter).FormatManager().RollbackUpgrade(testlogging.Context(t)),
require.EqualError(t, drw.FormatManager().RollbackUpgrade(testlogging.Context(t)),
"failed to restore format blob from backup \"kopia.repository.backup.allowed-upgrade-owner\": unexpected error")
allowGets = false
require.EqualError(t, r.(repo.DirectRepositoryWriter).FormatManager().RollbackUpgrade(testlogging.Context(t)),
require.EqualError(t, drw.FormatManager().RollbackUpgrade(testlogging.Context(t)),
"failed to read from backup \"kopia.repository.backup.allowed-upgrade-owner\": unexpected error on get")
allowPuts, allowGets, allowDeletes = true, true, true
require.NoError(t, r.(repo.DirectRepositoryWriter).FormatManager().RollbackUpgrade(testlogging.Context(t)))
require.NoError(t, drw.FormatManager().RollbackUpgrade(testlogging.Context(t)))
}
func TestFormatUpgradeDuringOngoingWriteSessions(t *testing.T) {
@@ -330,7 +332,7 @@ func TestFormatUpgradeDuringOngoingWriteSessions(t *testing.T) {
rep := env.Repository // read-only
lw := rep.(repo.RepositoryWriter)
lw := testutil.EnsureType[repo.DirectRepositoryWriter](t, rep)
// w1, w2, w3 are independent sessions.
_, w1, err := rep.NewWriter(ctx, repo.WriteSessionOptions{Purpose: "writer1"})
@@ -370,7 +372,7 @@ func TestFormatUpgradeDuringOngoingWriteSessions(t *testing.T) {
}
// set upgrade lock using independent client
_, err = env.MustConnectOpenAnother(t).(repo.DirectRepositoryWriter).FormatManager().SetUpgradeLockIntent(ctx, l)
_, err = testutil.EnsureType[repo.DirectRepositoryWriter](t, env.MustConnectOpenAnother(t)).FormatManager().SetUpgradeLockIntent(ctx, l)
require.NoError(t, err)
// ongoing writes should NOT get interrupted because the upgrade lock
@@ -395,7 +397,6 @@ func TestFormatUpgradeDuringOngoingWriteSessions(t *testing.T) {
// ongoing writes should get interrupted this time
require.ErrorIs(t, w1.Flush(ctx), repo.ErrRepositoryUnavailableDueToUpgradeInProgress)
require.ErrorIs(t, w2.Flush(ctx), repo.ErrRepositoryUnavailableDueToUpgradeInProgress)
require.ErrorIs(t, w3.Flush(ctx), repo.ErrRepositoryUnavailableDueToUpgradeInProgress)
require.ErrorIs(t, lw.Flush(ctx), repo.ErrRepositoryUnavailableDueToUpgradeInProgress)

View File

@@ -12,6 +12,7 @@
"github.com/kopia/kopia/internal/cache"
"github.com/kopia/kopia/internal/faketime"
"github.com/kopia/kopia/internal/repotesting"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/repo"
"github.com/kopia/kopia/repo/blob"
"github.com/kopia/kopia/repo/encryption"
@@ -56,7 +57,7 @@ func (s *formatSpecificTestSuite) TestExtendBlobRetentionTime(t *testing.T) {
require.Len(t, blobsBefore, 4, "unexpected number of blobs after writing")
lastBlobIdx := len(blobsBefore) - 1
st := env.RootStorage().(blobtesting.RetentionStorage)
st := testutil.EnsureType[blobtesting.RetentionStorage](t, env.RootStorage())
gotMode, expiry, err := st.GetRetention(ctx, blobsBefore[lastBlobIdx].BlobID)
require.NoError(t, err, "getting blob retention info")
@@ -111,7 +112,7 @@ func (s *formatSpecificTestSuite) TestExtendBlobRetentionTimeDisabled(t *testing
// Need to continue using TouchBlob because the environment only supports the
// locking map if no retention time is given.
lastBlobIdx := len(blobsBefore) - 1
st := env.RootStorage().(cache.Storage)
st := testutil.EnsureType[cache.Storage](t, env.RootStorage())
ta.Advance(7 * 24 * time.Hour)

View File

@@ -498,7 +498,7 @@ func TestIndirection(t *testing.T) {
contentBytes := make([]byte, c.dataLength)
writer := om.NewWriter(ctx, WriterOptions{MetadataCompressor: c.metadataCompressor})
writer.(*objectWriter).splitter = splitterFactory()
testutil.EnsureType[*objectWriter](t, writer).splitter = splitterFactory()
if _, err := writer.Write(contentBytes); err != nil {
t.Errorf("write error: %v", err)

View File

@@ -310,7 +310,7 @@ func TestWriterScope(t *testing.T) {
rep := env.Repository // read-only
lw := rep.(repo.RepositoryWriter)
lw := testutil.EnsureType[repo.DirectRepositoryWriter](t, rep)
// w1, w2, w3 are independent sessions.
_, w1, err := rep.NewWriter(ctx, repo.WriteSessionOptions{Purpose: "writer1"})
@@ -572,7 +572,7 @@ func TestObjectWritesWithRetention(t *testing.T) {
var prefixesWithRetention []string
versionedMap := env.RootStorage().(cache.Storage)
versionedMap := testutil.EnsureType[cache.Storage](t, env.RootStorage())
for _, prefix := range content.PackBlobIDPrefixes {
prefixesWithRetention = append(prefixesWithRetention, string(prefix))
@@ -891,7 +891,7 @@ func TestDeriveKey(t *testing.T) {
})
// prepare upgrade
dw1Upgraded := env.Repository.(repo.DirectRepositoryWriter)
dw1Upgraded := testutil.EnsureType[repo.DirectRepositoryWriter](t, env.Repository)
cf := dw1Upgraded.ContentReader().ContentFormat()
mp, mperr := cf.GetMutableParameters(ctx)
@@ -908,7 +908,7 @@ func TestDeriveKey(t *testing.T) {
require.NoError(t, dw1Upgraded.FormatManager().SetParameters(ctx, mp, blobCfg, feat))
return env.MustConnectOpenAnother(t).(repo.DirectRepositoryWriter)
return testutil.EnsureType[repo.DirectRepositoryWriter](t, env.MustConnectOpenAnother(t))
}
// we verify that repositories started on V1 will continue to derive keys from

View File

@@ -2,6 +2,7 @@
import (
"context"
"maps"
"testing"
"time"
@@ -10,6 +11,7 @@
"github.com/kopia/kopia/fs"
"github.com/kopia/kopia/internal/mockfs"
"github.com/kopia/kopia/internal/repotesting"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/repo"
"github.com/kopia/kopia/snapshot"
"github.com/kopia/kopia/snapshot/snapshotfs"
@@ -87,11 +89,10 @@ func iterateAllNames(ctx context.Context, t *testing.T, dir fs.Directory, prefix
err := fs.IterateEntries(ctx, dir, func(innerCtx context.Context, ent fs.Entry) error {
if ent.IsDir() {
result[prefix+ent.Name()+"/"] = struct{}{}
childEntries := iterateAllNames(ctx, t, ent.(fs.Directory), prefix+ent.Name()+"/")
for k, v := range childEntries {
result[k] = v
}
childEntries := iterateAllNames(ctx, t, testutil.EnsureType[fs.Directory](t, ent), prefix+ent.Name()+"/")
maps.Copy(result, childEntries)
} else {
result[prefix+ent.Name()] = struct{}{}
}

View File

@@ -15,6 +15,7 @@
"github.com/kopia/kopia/internal/mockfs"
"github.com/kopia/kopia/internal/repotesting"
"github.com/kopia/kopia/internal/testlogging"
"github.com/kopia/kopia/internal/testutil"
"github.com/kopia/kopia/repo"
"github.com/kopia/kopia/repo/content"
"github.com/kopia/kopia/repo/format"
@@ -132,7 +133,7 @@ func (s *formatSpecificTestSuite) TestMaintenanceReuseDirManifest(t *testing.T)
err = snapshotmaintenance.Run(ctx, th.RepositoryWriter, maintenance.ModeFull, true, maintenance.SafetyFull)
require.NoError(t, err)
info, err := r2.(repo.DirectRepository).ContentInfo(ctx, mustGetContentID(t, s2.RootObjectID()))
info, err := testutil.EnsureType[repo.DirectRepository](t, r2).ContentInfo(ctx, mustGetContentID(t, s2.RootObjectID()))
require.NoError(t, err)
require.False(t, info.Deleted, "content must not be deleted")

View File

@@ -203,7 +203,7 @@ func findAllEntries(t *testing.T, ctx context.Context, dir fs.Directory) []entry
entries := []entry{}
fs.IterateEntries(ctx, dir, func(ctx context.Context, e fs.Entry) error {
oid, err := object.ParseID(e.(object.HasObjectID).ObjectID().String())
oid, err := object.ParseID(testutil.EnsureType[object.HasObjectID](t, e).ObjectID().String())
require.NoError(t, err)
entries = append(entries, entry{
@@ -211,7 +211,7 @@ func findAllEntries(t *testing.T, ctx context.Context, dir fs.Directory) []entry
objectID: oid,
})
if e.IsDir() {
entries = append(entries, findAllEntries(t, ctx, e.(fs.Directory))...)
entries = append(entries, findAllEntries(t, ctx, testutil.EnsureType[fs.Directory](t, e))...)
}
return nil
@@ -290,7 +290,7 @@ func TestUploadMetadataCompression(t *testing.T) {
s1, err := u.Upload(ctx, th.sourceDir, policyTree, snapshot.SourceInfo{})
require.NoError(t, err, "upload error")
dir := snapshotfs.EntryFromDirEntry(th.repo, s1.RootEntry).(fs.Directory)
dir := testutil.EnsureType[fs.Directory](t, snapshotfs.EntryFromDirEntry(th.repo, s1.RootEntry))
entries := findAllEntries(t, ctx, dir)
verifyMetadataCompressor(t, ctx, th.repo, entries, compID)
})
@@ -1253,21 +1253,19 @@ func TestParallelUploadOfLargeFiles(t *testing.T) {
t.Logf("man: %v", man.RootObjectID())
dir := snapshotfs.EntryFromDirEntry(th.repo, man.RootEntry).(fs.Directory)
dir := testutil.EnsureType[fs.Directory](t, snapshotfs.EntryFromDirEntry(th.repo, man.RootEntry))
successCount := 0
fs.IterateEntries(ctx, dir, func(ctx context.Context, e fs.Entry) error {
if f, ok := e.(fs.File); ok {
hoid, hasObjectId := f.(object.HasObjectID)
require.True(t, hasObjectId)
hoid := testutil.EnsureType[object.HasObjectID](t, f)
oids := hoid.ObjectID().String()
oid, err := object.ParseID(strings.TrimPrefix(oids, "I"))
require.NoError(t, err, "failed to parse object id", oids)
entries, err := object.LoadIndexObject(ctx, th.repo.(repo.DirectRepositoryWriter).ContentManager(), oid)
entries, err := object.LoadIndexObject(ctx, testutil.EnsureType[repo.DirectRepositoryWriter](t, th.repo).ContentManager(), oid)
require.NoError(t, err, "failed to parse indirect object id", oid)
// ensure that index object contains breakpoints at all multiples of 'chunkSize'.

View File

@@ -50,7 +50,7 @@ func (d webdavDirWithFakeClock) OpenFile(ctx context.Context, fname string, flag
}
// change file time after creation to simulate fake time scale.
osf := f.(*os.File)
osf := f.(*os.File) //nolint:forcetypeassert
now := d.fts.Now()
if err := os.Chtimes(osf.Name(), now, now); err != nil {

View File

@@ -303,7 +303,7 @@ func longLivedRepositoryTest(ctx context.Context, t *testing.T, openID, configFi
for i := range opt.SessionsPerOpenRepository {
ors := or.NewSession(fmt.Sprintf("session-%v", i))
_, w, err := rep.(repo.DirectRepository).NewDirectWriter(ctx, repo.WriteSessionOptions{
_, w, err := testutil.EnsureType[repo.DirectRepository](t, rep).NewDirectWriter(ctx, repo.WriteSessionOptions{
Purpose: fmt.Sprintf("longLivedRepositoryTest-w%v", i),
})
if err != nil {

View File

@@ -43,7 +43,7 @@ func TestServerControlSocketActivated(t *testing.T) {
l1.Close()
}()
port = l1.Addr().(*net.TCPAddr).Port
port = testutil.EnsureType[*net.TCPAddr](t, l1.Addr()).Port
t.Logf("Activating socket on port %v", port)
@@ -53,7 +53,7 @@ func TestServerControlSocketActivated(t *testing.T) {
var sp testutil.ServerParameters
go func() {
l1File, err := l1.(*net.TCPListener).File()
l1File, err := testutil.EnsureType[*net.TCPListener](t, l1).File()
if err != nil {
t.Log("ERROR: Failed to get filehandle for socket")
close(serverStarted)
@@ -121,14 +121,16 @@ func TestServerControlSocketActivatedTooManyFDs(t *testing.T) {
l1.Close()
}()
port = l1.Addr().(*net.TCPAddr).Port
port = testutil.EnsureType[*net.TCPAddr](t, l1.Addr()).Port
t.Logf("Activating socket on port %v", port)
serverStarted := make(chan []string)
go func() {
l1File, err := l1.(*net.TCPListener).File()
listener := testutil.EnsureType[*net.TCPListener](t, l1)
l1File, err := listener.File()
if err != nil {
t.Log("Failed to get filehandle for socket")
close(serverStarted)
@@ -136,7 +138,7 @@ func TestServerControlSocketActivatedTooManyFDs(t *testing.T) {
return
}
l2File, err := l1.(*net.TCPListener).File()
l2File, err := listener.File()
if err != nil {
t.Log("Failed to get 2nd filehandle for socket")
close(serverStarted)