Files
tidb/br/pkg/aws/ebs_test.go

224 lines
5.7 KiB
Go

// Copyright 2022 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
package aws
import (
"context"
"testing"
awsapi "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/aws/aws-sdk-go/service/ec2/ec2iface"
"github.com/stretchr/testify/require"
)
func TestEC2SessionExtractSnapProgress(t *testing.T) {
tests := []struct {
str *string
want int64
}{
{nil, 0},
{awsapi.String("12.12%"), 12},
{awsapi.String("44.99%"), 44},
{awsapi.String(" 89.89% "), 89},
{awsapi.String("100%"), 100},
{awsapi.String("111111%"), 100},
}
e := &EC2Session{}
for _, tt := range tests {
require.Equal(t, tt.want, e.extractSnapProgress(tt.str))
}
}
func createVolume(snapshotId string, volumeId string, state string) *ec2.Volume {
return &ec2.Volume{
Attachments: nil,
AvailabilityZone: awsapi.String("us-west-2"),
CreateTime: nil,
Encrypted: awsapi.Bool(true),
FastRestored: awsapi.Bool(true),
Iops: awsapi.Int64(3000),
KmsKeyId: nil,
MultiAttachEnabled: awsapi.Bool(true),
OutpostArn: awsapi.String("arn:12342"),
Size: awsapi.Int64(1),
SnapshotId: awsapi.String(snapshotId),
State: awsapi.String(state),
Tags: nil,
Throughput: nil,
VolumeId: awsapi.String(volumeId),
VolumeType: awsapi.String("gp3"),
}
}
func TestHandleDescribeVolumesResponse(t *testing.T) {
curentVolumesStates := &ec2.DescribeVolumesOutput{
NextToken: awsapi.String("fake token"),
Volumes: []*ec2.Volume{
createVolume("snap-0873674883", "vol-98768979", "available"),
createVolume("snap-0873674883", "vol-98768979", "creating"),
createVolume("snap-0873674883", "vol-98768979", "available"),
createVolume("snap-0873674883", "vol-98768979", "available"),
createVolume("snap-0873674883", "vol-98768979", "available"),
},
}
e := &EC2Session{}
createdVolumeSize, unfinishedVolumes, _ := e.HandleDescribeVolumesResponse(curentVolumesStates, false)
require.Equal(t, int64(4), createdVolumeSize)
require.Equal(t, 1, len(unfinishedVolumes))
}
type mockEC2 struct {
ec2iface.EC2API
output ec2.DescribeSnapshotsOutput
}
func (m mockEC2) DescribeSnapshots(*ec2.DescribeSnapshotsInput) (*ec2.DescribeSnapshotsOutput, error) {
return &m.output, nil
}
func NewMockEc2Session(mock mockEC2) *EC2Session {
return &EC2Session{
ec2: mock,
}
}
func TestWaitSnapshotsCreated(t *testing.T) {
snapIdMap := map[string]string{
"vol-1": "snap-1",
"vol-2": "snap-2",
}
cases := []struct {
desc string
snapshotsOutput ec2.DescribeSnapshotsOutput
expectedSize int64
expectErr bool
expectTimeout bool
}{
{
desc: "snapshots are all completed",
snapshotsOutput: ec2.DescribeSnapshotsOutput{
Snapshots: []*ec2.Snapshot{
{
SnapshotId: awsapi.String("snap-1"),
VolumeSize: awsapi.Int64(1),
State: awsapi.String(ec2.SnapshotStateCompleted),
},
{
SnapshotId: awsapi.String("snap-2"),
VolumeSize: awsapi.Int64(2),
State: awsapi.String(ec2.SnapshotStateCompleted),
},
},
},
expectedSize: 3,
expectErr: false,
},
{
desc: "snapshot failed",
snapshotsOutput: ec2.DescribeSnapshotsOutput{
Snapshots: []*ec2.Snapshot{
{
SnapshotId: awsapi.String("snap-1"),
VolumeSize: awsapi.Int64(1),
State: awsapi.String(ec2.SnapshotStateCompleted),
},
{
SnapshotId: awsapi.String("snap-2"),
State: awsapi.String(ec2.SnapshotStateError),
StateMessage: awsapi.String("snapshot failed"),
},
},
},
expectedSize: 0,
expectErr: true,
},
{
desc: "snapshot failed w/out state message",
snapshotsOutput: ec2.DescribeSnapshotsOutput{
Snapshots: []*ec2.Snapshot{
{
SnapshotId: awsapi.String("snap-1"),
VolumeSize: awsapi.Int64(1),
State: awsapi.String(ec2.SnapshotStateCompleted),
},
{
SnapshotId: awsapi.String("snap-2"),
State: awsapi.String(ec2.SnapshotStateError),
StateMessage: nil,
},
},
},
expectedSize: 0,
expectErr: true,
},
{
desc: "snapshots pending",
snapshotsOutput: ec2.DescribeSnapshotsOutput{
Snapshots: []*ec2.Snapshot{
{
SnapshotId: awsapi.String("snap-1"),
VolumeSize: awsapi.Int64(1),
State: awsapi.String(ec2.SnapshotStateCompleted),
},
{
SnapshotId: awsapi.String("snap-2"),
State: awsapi.String(ec2.SnapshotStatePending),
},
},
},
expectTimeout: true,
},
}
for _, c := range cases {
e := NewMockEc2Session(mockEC2{
output: c.snapshotsOutput,
})
if c.expectTimeout {
func() {
// We wait 5s before checking snapshots
ctx, cancel := context.WithTimeout(context.Background(), 6)
defer cancel()
done := make(chan struct{})
go func() {
_, _ = e.WaitSnapshotsCreated(snapIdMap, nil)
done <- struct{}{}
}()
select {
case <-done:
t.Fatal("WaitSnapshotsCreated should not return before timeout")
case <-ctx.Done():
require.True(t, true)
}
}()
continue
}
size, err := e.WaitSnapshotsCreated(snapIdMap, nil)
if c.expectErr {
require.Error(t, err)
} else {
require.NoError(t, err)
}
require.Equal(t, c.expectedSize, size)
}
}