go-ceph/rbd/admin/task_test.go

425 lines
9.3 KiB
Go

//go:build !nautilus && ceph_preview
// +build !nautilus,ceph_preview
package admin
import (
"errors"
"testing"
"time"
"github.com/ceph/go-ceph/internal/commands"
"github.com/ceph/go-ceph/rbd"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
var tr1 = `
{
"sequence":1,
"id":"id-1",
"message":"Removing image pool/test from trash",
"refs":{
"action":"trash remove",
"pool_name":"pool",
"pool_namespace":"",
"image_id":"12345"
},
"retry_attempts":1,
"retry_time":"2021-09-13T05:58:24.826408"
}
`
var tr2 = `
{
"sequence":2,
"id":"id-2",
"message":"Removing image pool/test",
"refs":{
"action":"remove",
"pool_name":"pool",
"pool_namespace":"",
"image_name":"test",
"image_id":"123456"
},
"in_progress":true,
"progress":0.70
}
`
var trList = `[
{
"sequence":1,
"id":"id-1",
"message":"Removing image pool/test from trash",
"refs":{
"action":"trash remove",
"pool_name":"pool",
"pool_namespace":"",
"image_id":"12345"
},
"retry_attempts":1,
"retry_time":"2021-09-13T05:58:24.826408"
},
{
"sequence":2,
"id":"id-2",
"message":"Removing image pool/test",
"refs":{
"action":"remove",
"pool_name":"pool",
"pool_namespace":"",
"image_name":"test",
"image_id":"123456"
},
"in_progress":true,
"progress":0.70
}
]`
func TestParseTaskResponse(t *testing.T) {
type args struct {
res commands.Response
}
tests := []struct {
name string
args args
want TaskResponse
wantErr bool
}{
{
name: "",
args: args{
res: commands.NewResponse([]byte(tr1), "", nil),
},
want: TaskResponse{
Sequence: 1,
ID: "id-1",
Message: "Removing image pool/test from trash",
Refs: TaskRefs{
Action: "trash remove",
PoolName: "pool",
PoolNamespace: "",
ImageName: "",
ImageID: "12345",
},
InProgress: false,
Progress: 0,
RetryAttempts: 1,
RetryTime: "2021-09-13T05:58:24.826408",
RetryMessage: "",
},
wantErr: false,
},
{
name: "",
args: args{
res: commands.NewResponse([]byte(tr2), "", nil),
},
want: TaskResponse{
Sequence: 2,
ID: "id-2",
Message: "Removing image pool/test",
Refs: TaskRefs{
Action: "remove",
PoolName: "pool",
PoolNamespace: "",
ImageName: "test",
ImageID: "123456",
},
InProgress: true,
Progress: 0.70,
RetryAttempts: 0,
RetryTime: "",
RetryMessage: "",
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseTaskResponse(tt.args.res)
assert.NoError(t, err)
assert.Equal(t, tt.want, got)
})
}
}
func TesParseTaskResponseList(t *testing.T) {
type args struct {
res commands.Response
}
res1, err := parseTaskResponse(commands.NewResponse([]byte(tr1), "", nil))
assert.NoError(t, err)
res2, err := parseTaskResponse(commands.NewResponse([]byte(tr2), "", nil))
assert.NoError(t, err)
tests := []struct {
name string
args args
want []TaskResponse
wantErr bool
}{
{
name: "emptyList",
args: args{
res: commands.NewResponse([]byte(`[]`), "", nil),
},
want: []TaskResponse{},
wantErr: false,
},
{
name: "twoItemList",
args: args{
res: commands.NewResponse([]byte(trList), "", nil),
},
want: []TaskResponse{res1, res2},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := parseTaskResponseList(tt.args.res)
assert.NoError(t, err)
assert.Equal(t, tt.want, got)
})
}
}
var (
imageName = "img"
testNS = "test"
)
type args struct {
pool string
namespace string
imageName string
}
var tests = []struct {
name string
args args
}{
{
name: "onlyImageName",
args: args{
pool: "",
namespace: "",
imageName: imageName,
},
},
{
name: "Image&PoolName",
args: args{
pool: defaultPoolName,
namespace: "",
imageName: imageName,
},
},
{
name: "AllArgs",
args: args{
pool: defaultPoolName,
namespace: testNS,
imageName: imageName,
},
},
}
func TestTaskAdminAddRemove(t *testing.T) {
ensureDefaultPool(t)
conn := getConn(t)
ioctx, err := conn.OpenIOContext(defaultPoolName)
require.NoError(t, err)
defer ioctx.Destroy()
assert.NoError(t, rbd.NamespaceCreate(ioctx, testNS))
defer func() {
assert.NoError(t, rbd.NamespaceRemove(ioctx, testNS))
}()
ta := getAdmin(t).Task()
options := rbd.NewRbdImageOptions()
assert.NoError(t,
options.SetUint64(rbd.ImageOptionOrder, uint64(testImageOrder)))
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ioctx.SetNamespace(tt.args.namespace)
err = rbd.CreateImage(ioctx, tt.args.imageName, testImageSize, options)
assert.NoError(t, err)
tr, err := ta.AddRemove(NewImageSpec(tt.args.pool, tt.args.namespace, tt.args.imageName))
assert.NoError(t, err)
assert.Equal(t, tt.args.imageName, tr.Refs.ImageName)
assert.Equal(t, defaultPoolName, tr.Refs.PoolName)
assert.Equal(t, tt.args.namespace, tr.Refs.PoolNamespace)
assert.Equal(t, "remove", tr.Refs.Action)
found := false
// wait for the image to be deleted
for i := 0; i < 35; i++ {
imgList, err := rbd.GetImageNames(ioctx)
assert.NoError(t, err)
found = false
for _, img := range imgList {
if img == imageName {
found = true
break
}
}
if !found {
break
}
time.Sleep(time.Second)
}
assert.Equal(t, false, found)
})
}
}
func TestTaskAdminAddTrashRemove(t *testing.T) {
ensureDefaultPool(t)
conn := getConn(t)
ioctx, err := conn.OpenIOContext(defaultPoolName)
require.NoError(t, err)
defer ioctx.Destroy()
assert.NoError(t, rbd.NamespaceCreate(ioctx, testNS))
defer func() {
assert.NoError(t, rbd.NamespaceRemove(ioctx, testNS))
}()
ta := getAdmin(t).Task()
options := rbd.NewRbdImageOptions()
assert.NoError(t,
options.SetUint64(rbd.ImageOptionOrder, uint64(testImageOrder)))
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ioctx.SetNamespace(tt.args.namespace)
err = rbd.CreateImage(ioctx, tt.args.imageName, testImageSize, options)
assert.NoError(t, err)
img, err := rbd.OpenImage(ioctx, tt.args.imageName, rbd.NoSnapshot)
assert.NoError(t, err)
imageID, err := img.GetId()
assert.NoError(t, err)
assert.NoError(t, img.Trash(0))
assert.NoError(t, img.Close())
tr, err := ta.AddTrashRemove(NewImageSpec(tt.args.pool, tt.args.namespace, imageID))
assert.NoError(t, err)
assert.Equal(t, imageID, tr.Refs.ImageID)
assert.Equal(t, defaultPoolName, tr.Refs.PoolName)
assert.Equal(t, tt.args.namespace, tr.Refs.PoolNamespace)
assert.Equal(t, "trash remove", tr.Refs.Action)
trashList := []rbd.TrashInfo{}
// wait for the image to be deleted
for i := 0; i < 35; i++ {
trashList, err = rbd.GetTrashList(ioctx)
assert.NoError(t, err)
if len(trashList) == 0 {
break
}
time.Sleep(time.Second)
}
assert.Equal(t, 0, len(trashList))
})
}
}
func TestTaskAdminAddFlatten(t *testing.T) {
parentImageName := "parent"
ensureDefaultPool(t)
conn := getConn(t)
ioctx, err := conn.OpenIOContext(defaultPoolName)
require.NoError(t, err)
defer ioctx.Destroy()
assert.NoError(t, rbd.NamespaceCreate(ioctx, testNS))
defer func() {
assert.NoError(t, rbd.NamespaceRemove(ioctx, testNS))
}()
ta := getAdmin(t).Task()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ioctx.SetNamespace(tt.args.namespace)
options := rbd.NewRbdImageOptions()
assert.NoError(t,
options.SetUint64(rbd.ImageOptionOrder, uint64(testImageOrder)))
err = rbd.CreateImage(ioctx, parentImageName, testImageSize, options)
assert.NoError(t, err)
parentImage, err := rbd.OpenImage(ioctx, parentImageName, rbd.NoSnapshot)
assert.NoError(t, err)
defer func() {
assert.NoError(t, parentImage.Close())
assert.NoError(t, parentImage.Remove())
}()
snap, err := parentImage.CreateSnapshot(tt.args.imageName)
assert.NoError(t, err)
err = snap.Protect()
assert.NoError(t, err)
defer func() {
assert.NoError(t, snap.Unprotect())
assert.NoError(t, snap.Remove())
}()
assert.NoError(t, options.SetUint64(rbd.ImageOptionFormat, uint64(2)))
assert.NoError(t, rbd.CloneImage(ioctx, parentImageName, tt.args.imageName, ioctx, tt.args.imageName, options))
childImage, err := rbd.OpenImage(ioctx, tt.args.imageName, rbd.NoSnapshot)
assert.NoError(t, err)
defer func() {
assert.NoError(t, childImage.Close())
assert.NoError(t, childImage.Remove())
}()
parentInfo, err := childImage.GetParent()
assert.NoError(t, err)
assert.Equal(t, parentImageName, parentInfo.Image.ImageName)
assert.Equal(t, tt.args.imageName, parentInfo.Snap.SnapName)
tr, err := ta.AddFlatten(NewImageSpec(tt.args.pool, tt.args.namespace, tt.args.imageName))
assert.NoError(t, err)
assert.Equal(t, tt.args.imageName, tr.Refs.ImageName)
assert.Equal(t, defaultPoolName, tr.Refs.PoolName)
assert.Equal(t, tt.args.namespace, tr.Refs.PoolNamespace)
assert.Equal(t, "flatten", tr.Refs.Action)
// wait for the image to be flattened
for i := 0; i < 35; i++ {
_, err = childImage.GetParent()
if errors.Is(err, rbd.RbdErrorNotFound) {
break
}
assert.NoError(t, err)
time.Sleep(time.Second)
}
assert.Error(t, err)
})
}
}