rbd: add tests for DescriptionReplayStatus and UnmarshalDescriptionJSON

Add unit and simplistic functional tests for new JSON/status description
extraction functions.  Because these are preview functions we also add a
stub file to add a no-op function to be built on non-preview builds.
This avoids having to reimplement large parts of the existing mirroring
tests just to validate this small aspect of the SiteMirrorImageStatus
struct.

Signed-off-by: John Mulligan <jmulligan@redhat.com>
This commit is contained in:
John Mulligan 2023-03-06 15:24:13 -05:00 committed by mergify[bot]
parent f4f0d6dd9a
commit ab7955a236
3 changed files with 180 additions and 0 deletions

View File

@ -0,0 +1,164 @@
//go:build !nautilus && ceph_preview
// +build !nautilus,ceph_preview
// IMPORTANT - when removing ceph_preview from this file also delete
// rbd/mirror_stub_test.go as it will no longer serve a purpose.
package rbd
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestMirrorDescriptionJSON(t *testing.T) {
cases := []struct {
desc string
ok bool
}{
{
desc: "",
ok: false,
},
{
desc: "local image is primary",
ok: false,
},
{
desc: "status not found",
ok: false,
},
{
desc: "invalid {",
ok: false,
},
{
desc: "} invalid {",
ok: false,
},
{
desc: "phony, {}",
ok: true,
},
{
desc: `replaying, {"bytes_per_second":0.0,"bytes_per_snapshot":0.0,"last_snapshot_bytes":0,"last_snapshot_sync_seconds":0,"remote_snapshot_timestamp":1678125999,"replay_state":"idle"}`,
ok: true,
},
{
desc: "invalid-json, {:::...!}",
ok: false,
},
}
for _, tcase := range cases {
t.Run("testParse", func(t *testing.T) {
var data map[string]interface{}
s := SiteMirrorImageStatus{
Description: tcase.desc,
}
err := s.UnmarshalDescriptionJSON(&data)
if tcase.ok {
assert.NoError(t, err)
} else {
assert.Error(t, err)
}
})
}
}
func TestMirrorDescriptionReplayStatus(t *testing.T) {
cases := []struct {
desc string
ok bool
expected MirrorDescriptionReplayStatus
}{
{
desc: "",
ok: false,
},
{
desc: "local image is primary",
ok: false,
},
{
desc: "status not found",
ok: false,
},
{
desc: "invalid {",
ok: false,
},
{
desc: "} invalid {",
ok: false,
},
{
desc: "phony, {}",
ok: true,
},
{
desc: `replaying, {"bytes_per_second":0.0,"bytes_per_snapshot":0.0,"last_snapshot_bytes":0,"last_snapshot_sync_seconds":0,"remote_snapshot_timestamp":1678125999,"replay_state":"idle"}`,
ok: true,
expected: MirrorDescriptionReplayStatus{
ReplayState: "idle",
RemoteSnapshotTimestamp: 1678125999,
},
},
{
desc: `replaying, {"bytes_per_second":446028.87,"bytes_per_snapshot":559983.04,"last_snapshot_bytes":4030,"last_snapshot_sync_seconds":9087,"remote_snapshot_timestamp":1678125999,"replay_state":"syncing"}`,
ok: true,
expected: MirrorDescriptionReplayStatus{
ReplayState: "syncing",
RemoteSnapshotTimestamp: 1678125999,
BytesPerSecond: 446028.87,
BytesPerSnapshot: 559983.04,
LastSnapshotSyncSeconds: 9087,
LastSnapshotBytes: 4030,
},
},
{
desc: `something-or-other, {"bytes_per_second":446028.87,"bytes_per_snapshot":559983.04,"last_snapshot_bytes":4030,"last_snapshot_sync_seconds":9087,"remote_snapshot_timestamp":1678125999,"replay_state":"syncing","local_snapshot_timestamp":1674425567,"syncing_snapshot_timestamp":1674325567,"syncing_percent":31}`,
ok: true,
expected: MirrorDescriptionReplayStatus{
ReplayState: "syncing",
RemoteSnapshotTimestamp: 1678125999,
LocalSnapshotTimestamp: 1674425567,
SyncingSnapshotTimestamp: 1674325567,
SyncingPercent: 31,
BytesPerSecond: 446028.87,
BytesPerSnapshot: 559983.04,
LastSnapshotSyncSeconds: 9087,
LastSnapshotBytes: 4030,
},
},
}
for _, tcase := range cases {
t.Run("testCase", func(t *testing.T) {
s := SiteMirrorImageStatus{
Description: tcase.desc,
}
rs, err := s.DescriptionReplayStatus()
if tcase.ok {
assert.NoError(t, err)
assert.EqualValues(t, tcase.expected, *rs)
} else {
assert.Error(t, err)
}
})
}
}
// testDescriptionReplayStatus is a function that exists only to be compiled on
// ceph_preview builds so that we do not need to reimplement the bulk of the
// mirroring tests to check the functionality of our new preview funcs.
func testDescriptionReplayStatus(t *testing.T, smis SiteMirrorImageStatus) {
t.Log("testing DescriptionReplayStatus")
rsts, err := smis.DescriptionReplayStatus()
if assert.NoError(t, err) {
assert.Subset(t, []string{"idle", "syncing"}, []string{rsts.ReplayState})
// timestamp is approx. a year in the past so unless your
// clock is really messed up, this should pass
assert.Greater(t, rsts.RemoteSnapshotTimestamp, int64(1646593940))
}
}

14
rbd/mirror_stub_test.go Normal file
View File

@ -0,0 +1,14 @@
//go:build !nautilus && !ceph_preview
// +build !nautilus,!ceph_preview
package rbd
import (
"testing"
)
// testDescriptionReplayStatus is a stub function that exists only to be
// compiled as a near no-op on non ceph_preview builds.
func testDescriptionReplayStatus(t *testing.T, _ SiteMirrorImageStatus) {
t.Log("not testing DescriptionReplayStatus")
}

View File

@ -448,6 +448,7 @@ func TestGetGlobalMirrorStatusMirroredPool(t *testing.T) {
assert.Contains(t, ss2.Description, "replaying,")
assert.Greater(t, ss2.LastUpdate, int64(0))
assert.True(t, ss2.Up)
testDescriptionReplayStatus(t, ss2)
}
}()
@ -491,6 +492,7 @@ func TestGetGlobalMirrorStatusMirroredPool(t *testing.T) {
assert.Contains(t, ls.Description, "replaying,")
assert.Greater(t, ls.LastUpdate, int64(0))
assert.True(t, ls.Up)
testDescriptionReplayStatus(t, ls)
assert.Equal(t, ls, gms.SiteStatuses[0])