CloudMigrations: Add unit tests for snapshot management (#89521)

* add regex support for api tests

* revert dumb thing

* add api tests

* add unit test for core async workflow

* add xorm store unit tests

* fix typo

* remove unnecessary assignment
This commit is contained in:
Michael Mandrus
2024-06-21 09:35:15 -04:00
committed by GitHub
parent 70cd002826
commit 89337ea01f
9 changed files with 377 additions and 22 deletions
@@ -582,6 +582,10 @@ func (s *Service) UploadSnapshot(ctx context.Context, sessionUid string, snapsho
return nil
}
func (s *Service) CancelSnapshot(ctx context.Context, sessionUid string, snapshotUid string) error {
panic("not implemented")
}
func (s *Service) parseCloudMigrationConfig() (string, error) {
if s.cfg == nil {
return "", fmt.Errorf("cfg cannot be nil")
@@ -75,3 +75,7 @@ func (s *NoopServiceImpl) GetSnapshotList(ctx context.Context, query cloudmigrat
func (s *NoopServiceImpl) UploadSnapshot(ctx context.Context, sessionUid string, snapshotUid string) error {
return cloudmigration.ErrFeatureDisabledError
}
func (s *NoopServiceImpl) CancelSnapshot(ctx context.Context, sessionUid string, snapshotUid string) error {
return cloudmigration.ErrFeatureDisabledError
}
@@ -109,6 +109,63 @@ func Test_CreateGetRunMigrationsAndRuns(t *testing.T) {
require.NotNil(t, createResp.UID, delMigResp.UID)
}
func Test_ExecuteAsyncWorkflow(t *testing.T) {
s := setUpServiceTest(t, false)
createTokenResp, err := s.CreateToken(context.Background())
assert.NoError(t, err)
assert.NotEmpty(t, createTokenResp.Token)
cmd := cloudmigration.CloudMigrationSessionRequest{
AuthToken: createTokenResp.Token,
}
createResp, err := s.CreateSession(context.Background(), cmd)
require.NoError(t, err)
require.NotEmpty(t, createResp.UID)
require.NotEmpty(t, createResp.Slug)
getSessionResp, err := s.GetSession(context.Background(), createResp.UID)
require.NoError(t, err)
require.NotNil(t, getSessionResp)
require.Equal(t, createResp.UID, getSessionResp.UID)
require.Equal(t, createResp.Slug, getSessionResp.Slug)
listResp, err := s.GetSessionList(context.Background())
require.NoError(t, err)
require.NotNil(t, listResp)
require.Equal(t, 1, len(listResp.Sessions))
require.Equal(t, createResp.UID, listResp.Sessions[0].UID)
require.Equal(t, createResp.Slug, listResp.Sessions[0].Slug)
sessionUid := createResp.UID
snapshotResp, err := s.CreateSnapshot(ctxWithSignedInUser(), sessionUid)
require.NoError(t, err)
require.NotEmpty(t, snapshotResp.UID)
require.Equal(t, sessionUid, snapshotResp.SessionUID)
snapshotUid := snapshotResp.UID
snapshot, err := s.GetSnapshot(ctxWithSignedInUser(), sessionUid, snapshotUid)
require.NoError(t, err)
assert.Equal(t, snapshotResp.UID, snapshot.UID)
assert.Equal(t, snapshotResp.EncryptionKey, snapshot.EncryptionKey)
assert.Empty(t, snapshot.Result) // will change once we create a new table for migration items
snapshots, err := s.GetSnapshotList(ctxWithSignedInUser(), cloudmigration.ListSnapshotsQuery{SessionUID: sessionUid, Limit: 100})
require.NoError(t, err)
assert.Len(t, snapshots, 1)
assert.Equal(t, snapshotResp.UID, snapshots[0].UID)
assert.Equal(t, snapshotResp.EncryptionKey, snapshots[0].EncryptionKey)
assert.Empty(t, snapshots[0].Result) // should remain this way even after we create a new table
err = s.UploadSnapshot(ctxWithSignedInUser(), sessionUid, snapshotUid)
require.NoError(t, err)
assert.Panics(t, func() {
err = s.CancelSnapshot(ctxWithSignedInUser(), sessionUid, snapshotUid)
})
}
func ctxWithSignedInUser() context.Context {
c := &contextmodel.ReqContext{
SignedInUser: &user.SignedInUser{OrgID: 1},
@@ -8,7 +8,6 @@ import (
"github.com/grafana/grafana/pkg/services/cloudmigration"
"github.com/grafana/grafana/pkg/services/gcom"
"github.com/grafana/grafana/pkg/util"
)
var fixedDate = time.Date(2024, 6, 5, 17, 30, 40, 0, time.UTC)
@@ -140,7 +139,7 @@ func (m FakeServiceImpl) CreateSnapshot(ctx context.Context, sessionUid string)
return nil, fmt.Errorf("mock error")
}
return &cloudmigration.CloudMigrationSnapshot{
UID: util.GenerateShortUID(),
UID: "fake_uid",
SessionUID: sessionUid,
Status: cloudmigration.SnapshotStatusUnknown,
}, nil
@@ -151,8 +150,8 @@ func (m FakeServiceImpl) GetSnapshot(ctx context.Context, sessionUid string, sna
return nil, fmt.Errorf("mock error")
}
return &cloudmigration.CloudMigrationSnapshot{
UID: util.GenerateShortUID(),
SessionUID: sessionUid,
UID: "fake_uid",
SessionUID: "fake_uid",
Status: cloudmigration.SnapshotStatusUnknown,
}, nil
}
@@ -163,12 +162,12 @@ func (m FakeServiceImpl) GetSnapshotList(ctx context.Context, query cloudmigrati
}
return []cloudmigration.CloudMigrationSnapshot{
{
UID: util.GenerateShortUID(),
UID: "fake_uid",
SessionUID: query.SessionUID,
Status: cloudmigration.SnapshotStatusUnknown,
},
{
UID: util.GenerateShortUID(),
UID: "fake_uid",
SessionUID: query.SessionUID,
Status: cloudmigration.SnapshotStatusUnknown,
},
@@ -181,3 +180,10 @@ func (m FakeServiceImpl) UploadSnapshot(ctx context.Context, sessionUid string,
}
return nil
}
func (m FakeServiceImpl) CancelSnapshot(ctx context.Context, sessionUid string, snapshotUid string) error {
if m.ReturnError {
return fmt.Errorf("mock error")
}
return nil
}
@@ -233,17 +233,23 @@ func (ss *sqlStore) GetSnapshotByUID(ctx context.Context, uid string) (*cloudmig
}
func (ss *sqlStore) GetSnapshotList(ctx context.Context, query cloudmigration.ListSnapshotsQuery) ([]cloudmigration.CloudMigrationSnapshot, error) {
var runs = make([]cloudmigration.CloudMigrationSnapshot, 0)
var snapshots = make([]cloudmigration.CloudMigrationSnapshot, 0)
err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
sess.Limit(query.Limit, query.Offset)
return sess.Find(&runs, &cloudmigration.CloudMigrationSnapshot{
return sess.Find(&snapshots, &cloudmigration.CloudMigrationSnapshot{
SessionUID: query.SessionUID,
})
})
if err != nil {
return nil, err
}
return runs, nil
for i, snapshot := range snapshots {
if err := ss.decryptKey(ctx, &snapshot); err != nil {
return nil, err
}
snapshots[i] = snapshot
}
return snapshots, nil
}
func (ss *sqlStore) encryptToken(ctx context.Context, cm *cloudmigration.CloudMigrationSession) error {
@@ -11,6 +11,7 @@ import (
fakeSecrets "github.com/grafana/grafana/pkg/services/secrets/fakes"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/tests/testsuite"
"github.com/grafana/grafana/pkg/util"
"github.com/stretchr/testify/require"
)
@@ -18,7 +19,7 @@ func TestMain(m *testing.M) {
testsuite.Run(m)
}
func Test_GetAllCloudMigrations(t *testing.T) {
func Test_GetAllCloudMigrationSessions(t *testing.T) {
_, s := setUpTest(t)
ctx := context.Background()
@@ -44,11 +45,11 @@ func Test_GetAllCloudMigrations(t *testing.T) {
})
}
func Test_CreateMigration(t *testing.T) {
func Test_CreateMigrationSession(t *testing.T) {
_, s := setUpTest(t)
ctx := context.Background()
t.Run("creates migrations and reads it from the db", func(t *testing.T) {
t.Run("creates a session and reads it from the db", func(t *testing.T) {
cm := cloudmigration.CloudMigrationSession{
AuthToken: encodeToken("token"),
Slug: "fake_stack",
@@ -56,15 +57,15 @@ func Test_CreateMigration(t *testing.T) {
RegionSlug: "fake_slug",
ClusterSlug: "fake_cluster_slug",
}
mig, err := s.CreateMigrationSession(ctx, cm)
sess, err := s.CreateMigrationSession(ctx, cm)
require.NoError(t, err)
require.NotEmpty(t, mig.ID)
require.NotEmpty(t, mig.UID)
require.NotEmpty(t, sess.ID)
require.NotEmpty(t, sess.UID)
getRes, err := s.GetMigrationSessionByUID(ctx, mig.UID)
getRes, err := s.GetMigrationSessionByUID(ctx, sess.UID)
require.NoError(t, err)
require.Equal(t, mig.ID, getRes.ID)
require.Equal(t, mig.UID, getRes.UID)
require.Equal(t, sess.ID, getRes.ID)
require.Equal(t, sess.UID, getRes.UID)
require.Equal(t, cm.AuthToken, getRes.AuthToken)
require.Equal(t, cm.Slug, getRes.Slug)
require.Equal(t, cm.StackID, getRes.StackID)
@@ -73,7 +74,7 @@ func Test_CreateMigration(t *testing.T) {
})
}
func Test_GetMigrationByUID(t *testing.T) {
func Test_GetMigrationSessionByUID(t *testing.T) {
_, s := setUpTest(t)
ctx := context.Background()
t.Run("find session by uid", func(t *testing.T) {
@@ -89,7 +90,7 @@ func Test_GetMigrationByUID(t *testing.T) {
})
}
func Test_DeleteMigration(t *testing.T) {
func Test_DeleteMigrationSession(t *testing.T) {
_, s := setUpTest(t)
ctx := context.Background()
@@ -161,6 +162,46 @@ func Test_GetMigrationStatusList(t *testing.T) {
})
}
func Test_SnapshotManagement(t *testing.T) {
_, s := setUpTest(t)
ctx := context.Background()
t.Run("tests the snapshot lifecycle", func(t *testing.T) {
var snapshotUid string
sessionUid := util.GenerateShortUID()
// create a snapshot
cmr := cloudmigration.CloudMigrationSnapshot{
SessionUID: sessionUid,
Status: "initializing",
}
snapshotUid, err := s.CreateSnapshot(ctx, cmr)
require.NoError(t, err)
require.NotEmpty(t, snapshotUid)
//retrieve it from the db
snapshot, err := s.GetSnapshotByUID(ctx, snapshotUid)
require.NoError(t, err)
require.Equal(t, cloudmigration.SnapshotStatusInitializing, string(snapshot.Status))
// update its status
err = s.UpdateSnapshot(ctx, cloudmigration.UpdateSnapshotCmd{UID: snapshotUid, Status: cloudmigration.SnapshotStatusCreating})
require.NoError(t, err)
//retrieve it again
snapshot, err = s.GetSnapshotByUID(ctx, snapshotUid)
require.NoError(t, err)
require.Equal(t, cloudmigration.SnapshotStatusCreating, string(snapshot.Status))
// lists snapshots and ensures it's in there
snapshots, err := s.GetSnapshotList(ctx, cloudmigration.ListSnapshotsQuery{SessionUID: sessionUid, Offset: 0, Limit: 100})
require.NoError(t, err)
require.Len(t, snapshots, 1)
require.Equal(t, *snapshot, snapshots[0])
})
}
func setUpTest(t *testing.T) (*sqlstore.SQLStore, *sqlStore) {
testDB := db.InitTestDB(t)
s := &sqlStore{