diff options
author | Ilya Dryomov <idryomov@gmail.com> | 2023-12-23 15:19:09 +0100 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2024-01-20 16:06:53 +0100 |
commit | 9931282bfd2260d654325970555cab8c617e8f14 (patch) | |
tree | f72584e1b68e692c95bd2fbd1bf46c94ab2c454f | |
parent | librbd/object_map: allow intermediate snaps to be skipped on diff-iterate (diff) | |
download | ceph-9931282bfd2260d654325970555cab8c617e8f14.tar.xz ceph-9931282bfd2260d654325970555cab8c617e8f14.zip |
test/librbd: expand TestMockObjectMapDiffRequest edge case coverage
For each covered edge case or error, run through the following
scenarios:
- where the edge case concerns snap_id_start
- where the edge case concerns snap_id_end
- where the edge case concerns intermediate snapshot and
snap_id_start == 0 (diff against the beginning of time)
- where the edge case concerns intermediate snapshot and
snap_id_start != 0 (diff from snapshot)
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
-rw-r--r-- | src/test/librbd/object_map/test_mock_DiffRequest.cc | 474 |
1 files changed, 438 insertions, 36 deletions
diff --git a/src/test/librbd/object_map/test_mock_DiffRequest.cc b/src/test/librbd/object_map/test_mock_DiffRequest.cc index 8646f09354b..9be4995e00a 100644 --- a/src/test/librbd/object_map/test_mock_DiffRequest.cc +++ b/src/test/librbd/object_map/test_mock_DiffRequest.cc @@ -271,28 +271,6 @@ TEST_P(TestMockObjectMapDiffRequest, FastDiffDisabled) { } } -TEST_P(TestMockObjectMapDiffRequest, StartFastDiffInvalid) { - REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); - - uint32_t object_count = 5; - m_image_ctx->size = object_count * (1 << m_image_ctx->order); - m_image_ctx->snap_info = { - {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, - {}, {}, {}}}, - {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, - {}, {}, {}}} - }; - - auto get_flags = [&](MockTestImageCtx& mock_image_ctx) { - expect_get_flags(mock_image_ctx, 1, RBD_FLAG_FAST_DIFF_INVALID, 0); - }; - if (is_diff_iterate()) { - ASSERT_EQ(-EINVAL, do_diff(get_flags, 1, 2, true)); - } else { - ASSERT_EQ(-EINVAL, do_diff(get_flags, 1, 2, false)); - } -} - TEST_P(TestMockObjectMapDiffRequest, FromBeginningToSnap) { REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); @@ -1296,9 +1274,9 @@ TEST_P(TestMockObjectMapDiffRequest, StartSnapDNE) { }; if (is_diff_iterate()) { - ASSERT_EQ(-ENOENT, do_diff(noop, 1, CEPH_NOSNAP, true)); + ASSERT_EQ(-ENOENT, do_diff(noop, 1, 2, true)); } else { - ASSERT_EQ(-ENOENT, do_diff(noop, 1, CEPH_NOSNAP, false)); + ASSERT_EQ(-ENOENT, do_diff(noop, 1, 2, false)); } } @@ -1315,18 +1293,18 @@ TEST_P(TestMockObjectMapDiffRequest, EndSnapDNE) { BitVector<2> object_map_1; object_map_1.resize(object_count); - auto load = [&](MockTestImageCtx& mock_image_ctx) { - expect_get_flags(mock_image_ctx, 1, 0, 0); - expect_load_map(mock_image_ctx, 1, object_map_1, 0); - }; if (is_diff_iterate()) { - ASSERT_EQ(-ENOENT, do_diff(load, 1, 2, true)); + ASSERT_EQ(-ENOENT, do_diff(noop, 0, 2, true)); } else { - ASSERT_EQ(-ENOENT, do_diff(load, 1, 2, false)); + auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 1, 0, 0); + expect_load_map(mock_image_ctx, 1, object_map_1, 0); + }; + ASSERT_EQ(-ENOENT, do_diff(load, 0, 2, false)); } } -TEST_P(TestMockObjectMapDiffRequest, IntermediateSnapDNE) { +TEST_P(TestMockObjectMapDiffRequest, IntermediateSnapDNEFromBeginning) { REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); uint32_t object_count = 5; @@ -1365,26 +1343,105 @@ TEST_P(TestMockObjectMapDiffRequest, IntermediateSnapDNE) { } } -TEST_P(TestMockObjectMapDiffRequest, LoadObjectMapDNE) { +TEST_P(TestMockObjectMapDiffRequest, IntermediateSnapDNEFromSnap) { REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); uint32_t object_count = 5; m_image_ctx->size = object_count * (1 << m_image_ctx->order); + m_image_ctx->snap_info = { + {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}}, + {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}} + }; + BitVector<2> object_map_1; + object_map_1.resize(object_count); BitVector<2> object_map_head; + object_map_head.resize(object_count); + object_map_head[1] = OBJECT_EXISTS_CLEAN; + BitVector<2> expected_diff_state; + expected_diff_state.resize(object_count); + expected_diff_state[1] = DIFF_STATE_DATA_UPDATED; auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 1, 0, 0); + expect_load_map(mock_image_ctx, 1, object_map_1, 0, + [&mock_image_ctx]() { mock_image_ctx.snap_info.erase(2); }); expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); - expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, -ENOENT); + expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); }; if (is_diff_iterate()) { - ASSERT_EQ(-ENOENT, do_diff(load, 0, CEPH_NOSNAP, true)); + test_diff_iterate(load, 1, CEPH_NOSNAP, expected_diff_state); } else { - ASSERT_EQ(-ENOENT, do_diff(load, 0, CEPH_NOSNAP, false)); + test_deep_copy(load, 1, CEPH_NOSNAP, expected_diff_state); } } -TEST_P(TestMockObjectMapDiffRequest, LoadIntermediateObjectMapDNE) { +TEST_P(TestMockObjectMapDiffRequest, StartObjectMapDNE) { + REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); + + uint32_t object_count = 5; + m_image_ctx->size = object_count * (1 << m_image_ctx->order); + m_image_ctx->snap_info = { + {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}}, + {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}} + }; + + BitVector<2> object_map_1; + + auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 1, 0, 0); + expect_load_map(mock_image_ctx, 1, object_map_1, -ENOENT); + }; + if (is_diff_iterate()) { + ASSERT_EQ(-ENOENT, do_diff(load, 1, 2, true)); + } else { + ASSERT_EQ(-ENOENT, do_diff(load, 1, 2, false)); + } +} + +TEST_P(TestMockObjectMapDiffRequest, EndObjectMapDNE) { + REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); + + uint32_t object_count = 5; + m_image_ctx->size = object_count * (1 << m_image_ctx->order); + m_image_ctx->snap_info = { + {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}}, + {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}} + }; + + BitVector<2> object_map_1; + object_map_1.resize(object_count); + BitVector<2> object_map_2; + object_map_2.resize(object_count); + object_map_2[1] = OBJECT_EXISTS_CLEAN; + BitVector<2> expected_diff_state; + expected_diff_state.resize(object_count); + expected_diff_state[1] = DIFF_STATE_DATA_UPDATED; + + if (is_diff_iterate()) { + auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 2, 0, 0); + expect_load_map(mock_image_ctx, 2, object_map_2, -ENOENT); + }; + ASSERT_EQ(-ENOENT, do_diff(load, 0, 2, true)); + } else { + auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 1, 0, 0); + expect_load_map(mock_image_ctx, 1, object_map_1, 0); + expect_get_flags(mock_image_ctx, 2, 0, 0); + expect_load_map(mock_image_ctx, 2, object_map_2, -ENOENT); + }; + ASSERT_EQ(-ENOENT, do_diff(load, 0, 2, false)); + } +} + +TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapDNEFromBeginning) { REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); uint32_t object_count = 5; @@ -1419,6 +1476,153 @@ TEST_P(TestMockObjectMapDiffRequest, LoadIntermediateObjectMapDNE) { } } +TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapDNEFromSnap) { + REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); + + uint32_t object_count = 5; + m_image_ctx->size = object_count * (1 << m_image_ctx->order); + m_image_ctx->snap_info = { + {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}}, + {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}} + }; + + BitVector<2> object_map_1; + object_map_1.resize(object_count); + BitVector<2> object_map_2; + BitVector<2> object_map_head; + object_map_head.resize(object_count); + object_map_head[1] = OBJECT_EXISTS_CLEAN; + BitVector<2> expected_diff_state; + expected_diff_state.resize(object_count); + expected_diff_state[1] = DIFF_STATE_DATA_UPDATED; + + auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 1, 0, 0); + expect_load_map(mock_image_ctx, 1, object_map_1, 0); + expect_get_flags(mock_image_ctx, 2, 0, 0); + expect_load_map(mock_image_ctx, 2, object_map_2, -ENOENT); + expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); + expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); + }; + if (is_diff_iterate()) { + test_diff_iterate(load, 1, CEPH_NOSNAP, expected_diff_state); + } else { + test_deep_copy(load, 1, CEPH_NOSNAP, expected_diff_state); + } +} + +TEST_P(TestMockObjectMapDiffRequest, StartFastDiffInvalid) { + REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); + + uint32_t object_count = 5; + m_image_ctx->size = object_count * (1 << m_image_ctx->order); + m_image_ctx->snap_info = { + {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}}, + {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}} + }; + + auto get_flags = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 1, RBD_FLAG_FAST_DIFF_INVALID, 0); + }; + if (is_diff_iterate()) { + ASSERT_EQ(-EINVAL, do_diff(get_flags, 1, 2, true)); + } else { + ASSERT_EQ(-EINVAL, do_diff(get_flags, 1, 2, false)); + } +} + +TEST_P(TestMockObjectMapDiffRequest, EndFastDiffInvalid) { + REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); + + uint32_t object_count = 5; + m_image_ctx->size = object_count * (1 << m_image_ctx->order); + m_image_ctx->snap_info = { + {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}}, + {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}} + }; + + BitVector<2> object_map_1; + object_map_1.resize(object_count); + + if (is_diff_iterate()) { + auto get_flags = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 2, RBD_FLAG_FAST_DIFF_INVALID, 0); + }; + ASSERT_EQ(-EINVAL, do_diff(get_flags, 0, 2, true)); + } else { + auto get_flags = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 1, 0, 0); + expect_load_map(mock_image_ctx, 1, object_map_1, 0); + expect_get_flags(mock_image_ctx, 2, RBD_FLAG_FAST_DIFF_INVALID, 0); + }; + ASSERT_EQ(-EINVAL, do_diff(get_flags, 0, 2, false)); + } +} + +TEST_P(TestMockObjectMapDiffRequest, IntermediateFastDiffInvalidFromBeginning) { + REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); + + uint32_t object_count = 5; + m_image_ctx->size = object_count * (1 << m_image_ctx->order); + m_image_ctx->snap_info = { + {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}} + }; + + BitVector<2> object_map_head; + object_map_head.resize(object_count); + object_map_head[1] = OBJECT_EXISTS_CLEAN; + BitVector<2> expected_diff_state; + expected_diff_state.resize(object_count); + expected_diff_state[1] = DIFF_STATE_DATA_UPDATED; + + if (is_diff_iterate()) { + auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); + expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); + }; + test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state); + } else { + auto get_flags = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 1, RBD_FLAG_FAST_DIFF_INVALID, 0); + }; + ASSERT_EQ(-EINVAL, do_diff(get_flags, 0, CEPH_NOSNAP, false)); + } +} + +TEST_P(TestMockObjectMapDiffRequest, IntermediateFastDiffInvalidFromSnap) { + REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); + + uint32_t object_count = 5; + m_image_ctx->size = object_count * (1 << m_image_ctx->order); + m_image_ctx->snap_info = { + {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}}, + {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}} + }; + + BitVector<2> object_map_1; + object_map_1.resize(object_count); + + auto get_flags = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 1, 0, 0); + expect_load_map(mock_image_ctx, 1, object_map_1, 0); + expect_get_flags(mock_image_ctx, 2, RBD_FLAG_FAST_DIFF_INVALID, 0); + }; + if (is_diff_iterate()) { + ASSERT_EQ(-EINVAL, do_diff(get_flags, 1, CEPH_NOSNAP, true)); + } else { + ASSERT_EQ(-EINVAL, do_diff(get_flags, 1, CEPH_NOSNAP, false)); + } +} + TEST_P(TestMockObjectMapDiffRequest, StartObjectMapLoadError) { REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); @@ -1444,6 +1648,106 @@ TEST_P(TestMockObjectMapDiffRequest, StartObjectMapLoadError) { } } +TEST_P(TestMockObjectMapDiffRequest, EndObjectMapLoadError) { + REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); + + uint32_t object_count = 5; + m_image_ctx->size = object_count * (1 << m_image_ctx->order); + m_image_ctx->snap_info = { + {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}}, + {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}} + }; + + BitVector<2> object_map_1; + object_map_1.resize(object_count); + BitVector<2> object_map_2; + object_map_2.resize(object_count); + object_map_2[1] = OBJECT_EXISTS_CLEAN; + BitVector<2> expected_diff_state; + expected_diff_state.resize(object_count); + expected_diff_state[1] = DIFF_STATE_DATA_UPDATED; + + if (is_diff_iterate()) { + auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 2, 0, 0); + expect_load_map(mock_image_ctx, 2, object_map_2, -EPERM); + }; + ASSERT_EQ(-EPERM, do_diff(load, 0, 2, true)); + } else { + auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 1, 0, 0); + expect_load_map(mock_image_ctx, 1, object_map_1, 0); + expect_get_flags(mock_image_ctx, 2, 0, 0); + expect_load_map(mock_image_ctx, 2, object_map_2, -EPERM); + }; + ASSERT_EQ(-EPERM, do_diff(load, 0, 2, false)); + } +} + +TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapLoadErrorFromBeginning) { + REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); + + uint32_t object_count = 5; + m_image_ctx->size = object_count * (1 << m_image_ctx->order); + m_image_ctx->snap_info = { + {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}} + }; + + BitVector<2> object_map_1; + BitVector<2> object_map_head; + object_map_head.resize(object_count); + object_map_head[1] = OBJECT_EXISTS_CLEAN; + BitVector<2> expected_diff_state; + expected_diff_state.resize(object_count); + expected_diff_state[1] = DIFF_STATE_DATA_UPDATED; + + if (is_diff_iterate()) { + auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); + expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); + }; + test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state); + } else { + auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 1, 0, 0); + expect_load_map(mock_image_ctx, 1, object_map_1, -EPERM); + }; + ASSERT_EQ(-EPERM, do_diff(load, 0, CEPH_NOSNAP, false)); + } +} + +TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapLoadErrorFromSnap) { + REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); + + uint32_t object_count = 5; + m_image_ctx->size = object_count * (1 << m_image_ctx->order); + m_image_ctx->snap_info = { + {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}}, + {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}} + }; + + BitVector<2> object_map_1; + object_map_1.resize(object_count); + BitVector<2> object_map_2; + + auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 1, 0, 0); + expect_load_map(mock_image_ctx, 1, object_map_1, 0); + expect_get_flags(mock_image_ctx, 2, 0, 0); + expect_load_map(mock_image_ctx, 2, object_map_2, -EPERM); + }; + if (is_diff_iterate()) { + ASSERT_EQ(-EPERM, do_diff(load, 1, CEPH_NOSNAP, true)); + } else { + ASSERT_EQ(-EPERM, do_diff(load, 1, CEPH_NOSNAP, false)); + } +} + TEST_P(TestMockObjectMapDiffRequest, StartObjectMapTooSmall) { REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); @@ -1470,6 +1774,104 @@ TEST_P(TestMockObjectMapDiffRequest, StartObjectMapTooSmall) { } } +TEST_P(TestMockObjectMapDiffRequest, EndObjectMapTooSmall) { + REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); + + uint32_t object_count = 5; + m_image_ctx->size = object_count * (1 << m_image_ctx->order); + m_image_ctx->snap_info = { + {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}}, + {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}} + }; + + BitVector<2> object_map_1; + object_map_1.resize(object_count); + BitVector<2> object_map_2; + object_map_2.resize(object_count - 1); + + if (is_diff_iterate()) { + auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 2, 0, 0); + expect_load_map(mock_image_ctx, 2, object_map_2, 0); + }; + ASSERT_EQ(-EINVAL, do_diff(load, 0, 2, true)); + } else { + auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 1, 0, 0); + expect_load_map(mock_image_ctx, 1, object_map_1, 0); + expect_get_flags(mock_image_ctx, 2, 0, 0); + expect_load_map(mock_image_ctx, 2, object_map_2, 0); + }; + ASSERT_EQ(-EINVAL, do_diff(load, 0, 2, false)); + } +} + +TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapTooSmallFromBeginning) { + REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); + + uint32_t object_count = 5; + m_image_ctx->size = object_count * (1 << m_image_ctx->order); + m_image_ctx->snap_info = { + {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}} + }; + + BitVector<2> object_map_1; + object_map_1.resize(object_count - 1); + BitVector<2> object_map_head; + object_map_head.resize(object_count); + object_map_head[1] = OBJECT_EXISTS_CLEAN; + BitVector<2> expected_diff_state; + expected_diff_state.resize(object_count); + expected_diff_state[1] = DIFF_STATE_DATA_UPDATED; + + if (is_diff_iterate()) { + auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, CEPH_NOSNAP, 0, 0); + expect_load_map(mock_image_ctx, CEPH_NOSNAP, object_map_head, 0); + }; + test_diff_iterate(load, 0, CEPH_NOSNAP, expected_diff_state); + } else { + auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 1, 0, 0); + expect_load_map(mock_image_ctx, 1, object_map_1, 0); + }; + ASSERT_EQ(-EINVAL, do_diff(load, 0, CEPH_NOSNAP, false)); + } +} + +TEST_P(TestMockObjectMapDiffRequest, IntermediateObjectMapTooSmallFromSnap) { + REQUIRE_FEATURE(RBD_FEATURE_FAST_DIFF); + + uint32_t object_count = 5; + m_image_ctx->size = object_count * (1 << m_image_ctx->order); + m_image_ctx->snap_info = { + {1U, {"snap1", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}}, + {2U, {"snap2", {cls::rbd::UserSnapshotNamespace{}}, m_image_ctx->size, {}, + {}, {}, {}}} + }; + + BitVector<2> object_map_1; + object_map_1.resize(object_count); + BitVector<2> object_map_2; + object_map_2.resize(object_count - 1); + + auto load = [&](MockTestImageCtx& mock_image_ctx) { + expect_get_flags(mock_image_ctx, 1, 0, 0); + expect_load_map(mock_image_ctx, 1, object_map_1, 0); + expect_get_flags(mock_image_ctx, 2, 0, 0); + expect_load_map(mock_image_ctx, 2, object_map_2, 0); + }; + if (is_diff_iterate()) { + ASSERT_EQ(-EINVAL, do_diff(load, 1, CEPH_NOSNAP, true)); + } else { + ASSERT_EQ(-EINVAL, do_diff(load, 1, CEPH_NOSNAP, false)); + } +} + INSTANTIATE_TEST_SUITE_P(MockObjectMapDiffRequestTests, TestMockObjectMapDiffRequest, ::testing::Bool()); |