mirror of
https://github.com/kopia/kopia.git
synced 2026-05-14 01:37:07 -04:00
205 lines
5.0 KiB
Go
205 lines
5.0 KiB
Go
package blob_test
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/kopia/kopia/internal/blobtesting"
|
|
"github.com/kopia/kopia/internal/gather"
|
|
"github.com/kopia/kopia/repo/blob"
|
|
)
|
|
|
|
func TestListAllBlobs(t *testing.T) {
|
|
data := blobtesting.DataMap{}
|
|
st := blobtesting.NewMapStorage(data, nil, nil)
|
|
ctx := context.Background()
|
|
st.PutBlob(ctx, "foo", gather.FromSlice([]byte{1, 2, 3}), blob.PutOptions{})
|
|
st.PutBlob(ctx, "boo", gather.FromSlice([]byte{2, 3, 4}), blob.PutOptions{})
|
|
st.PutBlob(ctx, "bar", gather.FromSlice([]byte{3, 4, 5}), blob.PutOptions{})
|
|
|
|
result1, err := blob.ListAllBlobs(ctx, st, "")
|
|
require.NoError(t, err)
|
|
require.ElementsMatch(t, []blob.ID{"foo", "boo", "bar"}, blob.IDsFromMetadata(result1))
|
|
|
|
result2, err := blob.ListAllBlobs(ctx, st, "b")
|
|
require.NoError(t, err)
|
|
require.ElementsMatch(t, []blob.ID{"boo", "bar"}, blob.IDsFromMetadata(result2))
|
|
|
|
result3, err := blob.ListAllBlobs(ctx, st, "c")
|
|
require.NoError(t, err)
|
|
require.ElementsMatch(t, []blob.ID{}, blob.IDsFromMetadata(result3))
|
|
}
|
|
|
|
func TestIterateAllPrefixesInParallel(t *testing.T) {
|
|
data := blobtesting.DataMap{}
|
|
st := blobtesting.NewMapStorage(data, nil, nil)
|
|
ctx := context.Background()
|
|
st.PutBlob(ctx, "foo", gather.FromSlice([]byte{1, 2, 3}), blob.PutOptions{})
|
|
st.PutBlob(ctx, "boo", gather.FromSlice([]byte{2, 3, 4}), blob.PutOptions{})
|
|
st.PutBlob(ctx, "bar", gather.FromSlice([]byte{3, 4, 5}), blob.PutOptions{})
|
|
|
|
var (
|
|
mu sync.Mutex
|
|
got []blob.ID
|
|
)
|
|
|
|
require.NoError(t, blob.IterateAllPrefixesInParallel(ctx, 10, st, []blob.ID{
|
|
"b",
|
|
"c",
|
|
}, func(m blob.Metadata) error {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
|
|
got = append(got, m.BlobID)
|
|
|
|
return nil
|
|
}))
|
|
|
|
require.ElementsMatch(t, []blob.ID{"boo", "bar"}, got)
|
|
|
|
got = nil
|
|
|
|
require.NoError(t, blob.IterateAllPrefixesInParallel(ctx, 0, st, []blob.ID{
|
|
"f",
|
|
}, func(m blob.Metadata) error {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
|
|
got = append(got, m.BlobID)
|
|
|
|
return nil
|
|
}))
|
|
|
|
require.ElementsMatch(t, []blob.ID{"foo"}, got)
|
|
|
|
got = nil
|
|
|
|
require.NoError(t, blob.IterateAllPrefixesInParallel(ctx, 0, st, []blob.ID{
|
|
"f",
|
|
"b",
|
|
}, func(m blob.Metadata) error {
|
|
mu.Lock()
|
|
defer mu.Unlock()
|
|
|
|
got = append(got, m.BlobID)
|
|
|
|
return nil
|
|
}))
|
|
|
|
require.ElementsMatch(t, []blob.ID{"foo", "bar", "boo"}, got)
|
|
|
|
errDummy := errors.New("dummy")
|
|
|
|
require.ErrorIs(t, errDummy, blob.IterateAllPrefixesInParallel(ctx, 10, st, []blob.ID{
|
|
"b",
|
|
"c",
|
|
}, func(m blob.Metadata) error {
|
|
return errDummy
|
|
}))
|
|
}
|
|
|
|
func TestEnsureLengthExactly(t *testing.T) {
|
|
require.NoError(t, blob.EnsureLengthExactly(3, 3))
|
|
require.NoError(t, blob.EnsureLengthExactly(3, -1))
|
|
require.Error(t, blob.EnsureLengthExactly(3, 4))
|
|
require.Error(t, blob.EnsureLengthExactly(3, 2))
|
|
}
|
|
|
|
func TestIDsFromMetadata(t *testing.T) {
|
|
require.Equal(t,
|
|
[]blob.ID{"foo", "bar", "baz"},
|
|
blob.IDsFromMetadata([]blob.Metadata{
|
|
{BlobID: "foo", Length: 11},
|
|
{BlobID: "bar", Length: 22},
|
|
{BlobID: "baz", Length: 55},
|
|
}))
|
|
}
|
|
|
|
func TestMaxTimestamp(t *testing.T) {
|
|
t0 := time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC)
|
|
t1 := t0.Add(1 * time.Hour)
|
|
t2 := t0.Add(-1 * time.Hour)
|
|
|
|
require.Equal(t,
|
|
t1,
|
|
blob.MaxTimestamp([]blob.Metadata{
|
|
{BlobID: "foo", Timestamp: t0},
|
|
{BlobID: "bar", Timestamp: t1},
|
|
{BlobID: "baz", Timestamp: t2},
|
|
}))
|
|
|
|
require.Equal(t, time.Time{}, blob.MaxTimestamp([]blob.Metadata{}))
|
|
}
|
|
|
|
func TestMinTimestamp(t *testing.T) {
|
|
t0 := time.Date(2020, 1, 2, 3, 4, 5, 6, time.UTC)
|
|
t1 := t0.Add(1 * time.Hour)
|
|
t2 := t0.Add(-1 * time.Hour)
|
|
|
|
require.Equal(t,
|
|
t2,
|
|
blob.MinTimestamp([]blob.Metadata{
|
|
{BlobID: "foo", Timestamp: t0},
|
|
{BlobID: "bar", Timestamp: t1},
|
|
{BlobID: "baz", Timestamp: t2},
|
|
}))
|
|
|
|
require.Equal(t, time.Time{}, blob.MinTimestamp([]blob.Metadata{}))
|
|
}
|
|
|
|
func TestTotalLength(t *testing.T) {
|
|
require.Equal(t,
|
|
int64(357),
|
|
blob.TotalLength([]blob.Metadata{
|
|
{BlobID: "foo", Length: 123},
|
|
{BlobID: "bar", Length: 234},
|
|
}))
|
|
}
|
|
|
|
func TestDeleteMultiple(t *testing.T) {
|
|
data := blobtesting.DataMap{
|
|
"foo": []byte{1, 2, 3},
|
|
"bar": []byte{1, 2, 4},
|
|
"baz": []byte{1, 2, 5},
|
|
"qux": []byte{1, 2, 6},
|
|
}
|
|
|
|
st := blobtesting.NewMapStorage(data, nil, nil)
|
|
|
|
require.NoError(t, blob.DeleteMultiple(context.Background(), st, []blob.ID{"bar", "qux"}, 4))
|
|
|
|
require.Equal(t, blobtesting.DataMap{
|
|
"foo": []byte{1, 2, 3},
|
|
"baz": []byte{1, 2, 5},
|
|
}, data)
|
|
}
|
|
|
|
func TestMetataJSONString(t *testing.T) {
|
|
bm := blob.Metadata{
|
|
BlobID: "foo",
|
|
Length: 12345,
|
|
Timestamp: time.Date(2000, 1, 2, 3, 4, 5, 6, time.UTC),
|
|
}
|
|
|
|
require.JSONEq(t, `{"id":"foo","length":12345,"timestamp":"2000-01-02T03:04:05.000000006Z"}`, bm.String())
|
|
}
|
|
|
|
func TestPutBlobAndGetMetadata(t *testing.T) {
|
|
data := blobtesting.DataMap{}
|
|
|
|
fixedTime := time.Date(2000, 1, 2, 3, 4, 5, 6, time.UTC)
|
|
|
|
st := blobtesting.NewMapStorage(data, nil, func() time.Time {
|
|
return fixedTime
|
|
})
|
|
|
|
bm, err := blob.PutBlobAndGetMetadata(context.Background(), st, "foo", gather.FromSlice([]byte{1, 2, 3}), blob.PutOptions{})
|
|
require.NoError(t, err)
|
|
require.Equal(t, fixedTime, bm.Timestamp)
|
|
}
|