2023-04-20 12:40:22 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
2023-08-11 13:12:13 +00:00
|
|
|
// SPDX-License-Identifier: BUSL-1.1
|
2023-04-20 12:40:22 +00:00
|
|
|
|
2023-04-04 16:30:06 +00:00
|
|
|
package inmem_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
|
|
|
"github.com/hashicorp/consul/internal/storage"
|
|
|
|
"github.com/hashicorp/consul/internal/storage/inmem"
|
|
|
|
"github.com/hashicorp/consul/proto-public/pbresource"
|
|
|
|
"github.com/hashicorp/consul/proto/private/prototest"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestSnapshotRestore(t *testing.T) {
|
|
|
|
oldStore, err := inmem.NewStore()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
a := &pbresource.Resource{
|
|
|
|
Id: &pbresource.ID{
|
|
|
|
Type: &pbresource.Type{
|
|
|
|
Group: "mesh",
|
|
|
|
GroupVersion: "v1",
|
|
|
|
Kind: "service",
|
|
|
|
},
|
|
|
|
Tenancy: &pbresource.Tenancy{
|
|
|
|
Partition: "default",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Name: "billing",
|
|
|
|
Uid: "a",
|
|
|
|
},
|
|
|
|
Version: "1",
|
|
|
|
}
|
|
|
|
require.NoError(t, oldStore.WriteCAS(a, ""))
|
|
|
|
|
|
|
|
newStore, err := inmem.NewStore()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Write something to the new store to make sure it gets blown away.
|
|
|
|
b := &pbresource.Resource{
|
|
|
|
Id: &pbresource.ID{
|
|
|
|
Type: &pbresource.Type{
|
|
|
|
Group: "mesh",
|
|
|
|
GroupVersion: "v1",
|
|
|
|
Kind: "service",
|
|
|
|
},
|
|
|
|
Tenancy: &pbresource.Tenancy{
|
|
|
|
Partition: "default",
|
|
|
|
Namespace: "default",
|
|
|
|
},
|
|
|
|
Name: "api",
|
|
|
|
Uid: "a",
|
|
|
|
},
|
|
|
|
Version: "1",
|
|
|
|
}
|
|
|
|
require.NoError(t, newStore.WriteCAS(b, ""))
|
|
|
|
|
|
|
|
snap, err := oldStore.Snapshot()
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
// Start a watch on the new store to make sure it gets closed.
|
|
|
|
watch, err := newStore.WatchList(storage.UnversionedTypeFrom(b.Id.Type), b.Id.Tenancy, "")
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
t.Cleanup(cancel)
|
|
|
|
|
|
|
|
// Expect the initial state on the watch.
|
2024-02-02 21:11:05 +00:00
|
|
|
got, err := watch.Next(ctx)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, got.GetUpsert())
|
|
|
|
|
|
|
|
// expect to get snapshot end op
|
|
|
|
got, err = watch.Next(ctx)
|
2023-04-04 16:30:06 +00:00
|
|
|
require.NoError(t, err)
|
2024-02-02 21:11:05 +00:00
|
|
|
require.NotNil(t, got.GetEndOfSnapshot())
|
2023-04-04 16:30:06 +00:00
|
|
|
|
|
|
|
restore, err := newStore.Restore()
|
|
|
|
require.NoError(t, err)
|
|
|
|
defer restore.Abort()
|
|
|
|
|
|
|
|
for r := snap.Next(); r != nil; r = snap.Next() {
|
|
|
|
restore.Apply(r)
|
|
|
|
}
|
|
|
|
restore.Commit()
|
|
|
|
|
|
|
|
// Check that resource we wrote to oldStore has been restored to newStore.
|
|
|
|
rsp, err := newStore.Read(a.Id)
|
|
|
|
require.NoError(t, err)
|
|
|
|
prototest.AssertDeepEqual(t, a, rsp)
|
|
|
|
|
|
|
|
// Check that resource written to newStore was removed by snapshot restore.
|
|
|
|
_, err = newStore.Read(b.Id)
|
|
|
|
require.ErrorIs(t, err, storage.ErrNotFound)
|
|
|
|
|
|
|
|
// Check the watch has been closed.
|
|
|
|
_, err = watch.Next(ctx)
|
|
|
|
require.ErrorIs(t, err, storage.ErrWatchClosed)
|
|
|
|
}
|