]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/trash/test_mock_MoveRequest.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / test / librbd / trash / test_mock_MoveRequest.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "test/librbd/test_mock_fixture.h"
5 #include "test/librbd/test_support.h"
6 #include "test/librbd/mock/MockExclusiveLock.h"
7 #include "test/librbd/mock/MockImageCtx.h"
8 #include "test/librbd/mock/MockImageState.h"
9 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
10 #include "test/librados_test_stub/MockTestMemRadosClient.h"
11 #include "include/rbd/librbd.hpp"
12 #include "librbd/Utils.h"
13 #include "librbd/trash/MoveRequest.h"
14
15 namespace librbd {
16 namespace {
17
18 struct MockTestImageCtx : public MockImageCtx {
19 static MockTestImageCtx *s_instance;
20 static MockTestImageCtx *create(const std::string &image_name,
21 const std::string &image_id,
22 const char *snap, librados::IoCtx& p,
23 bool read_only) {
24 ceph_assert(s_instance != nullptr);
25 s_instance->construct(image_name, image_id);
26 return s_instance;
27 }
28
29 MOCK_METHOD2(construct, void(const std::string&, const std::string&));
30
31 MockTestImageCtx(librbd::ImageCtx &image_ctx)
32 : librbd::MockImageCtx(image_ctx) {
33 s_instance = this;
34 }
35 };
36
37 MockTestImageCtx *MockTestImageCtx::s_instance = nullptr;
38
39 } // anonymous namespace
40 } // namespace librbd
41
42 #include "librbd/trash/MoveRequest.cc"
43
44 namespace librbd {
45 namespace trash {
46
47 using ::testing::_;
48 using ::testing::InSequence;
49 using ::testing::Invoke;
50 using ::testing::Return;
51 using ::testing::StrEq;
52 using ::testing::WithArg;
53
54 struct TestMockTrashMoveRequest : public TestMockFixture {
55 typedef MoveRequest<librbd::MockTestImageCtx> MockMoveRequest;
56
57 void expect_trash_add(MockTestImageCtx &mock_image_ctx,
58 const std::string& image_id,
59 cls::rbd::TrashImageSource trash_image_source,
60 const std::string& name,
61 const utime_t& end_time,
62 int r) {
63 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
64 exec(StrEq("rbd_trash"), _, StrEq("rbd"), StrEq("trash_add"),
65 _, _, _, _))
66 .WillOnce(WithArg<4>(Invoke([=](bufferlist& in_bl) {
67 std::string id;
68 cls::rbd::TrashImageSpec trash_image_spec;
69
70 auto bl_it = in_bl.cbegin();
71 decode(id, bl_it);
72 decode(trash_image_spec, bl_it);
73
74 EXPECT_EQ(id, image_id);
75 EXPECT_EQ(trash_image_spec.source,
76 trash_image_source);
77 EXPECT_EQ(trash_image_spec.name, name);
78 EXPECT_EQ(trash_image_spec.deferment_end_time,
79 end_time);
80 return r;
81 })));
82 }
83
84 void expect_aio_remove(MockTestImageCtx &mock_image_ctx,
85 const std::string& oid, int r) {
86 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), remove(oid, _))
87 .WillOnce(Return(r));
88 }
89
90 void expect_dir_remove(MockTestImageCtx& mock_image_ctx,
91 const std::string& name, const std::string& id,
92 int r) {
93 bufferlist in_bl;
94 encode(name, in_bl);
95 encode(id, in_bl);
96
97 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
98 exec(StrEq("rbd_directory"), _, StrEq("rbd"), StrEq("dir_remove_image"),
99 ContentsEqual(in_bl), _, _, _))
100 .WillOnce(Return(r));
101 }
102 };
103
104 TEST_F(TestMockTrashMoveRequest, Success) {
105 REQUIRE_FORMAT_V2();
106
107 librbd::ImageCtx *ictx;
108 ASSERT_EQ(0, open_image(m_image_name, &ictx));
109
110 MockTestImageCtx mock_image_ctx(*ictx);
111 MockExclusiveLock mock_exclusive_lock;
112 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
113 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
114 }
115
116 expect_op_work_queue(mock_image_ctx);
117
118 InSequence seq;
119 utime_t delete_time{ceph_clock_now()};
120 expect_trash_add(mock_image_ctx, "image id",
121 cls::rbd::TRASH_IMAGE_SOURCE_USER, "image name", delete_time,
122 0);
123 expect_aio_remove(mock_image_ctx, util::id_obj_name("image name"), 0);
124 expect_dir_remove(mock_image_ctx, "image name", "image id", 0);
125
126 C_SaferCond ctx;
127 cls::rbd::TrashImageSpec trash_image_spec{
128 cls::rbd::TRASH_IMAGE_SOURCE_USER, "image name", delete_time,
129 delete_time};
130 auto req = MockMoveRequest::create(mock_image_ctx.md_ctx, "image id",
131 trash_image_spec, &ctx);
132 req->send();
133 ASSERT_EQ(0, ctx.wait());
134 }
135
136 TEST_F(TestMockTrashMoveRequest, TrashAddError) {
137 REQUIRE_FORMAT_V2();
138
139 librbd::ImageCtx *ictx;
140 ASSERT_EQ(0, open_image(m_image_name, &ictx));
141
142 MockTestImageCtx mock_image_ctx(*ictx);
143 MockExclusiveLock mock_exclusive_lock;
144 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
145 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
146 }
147
148 expect_op_work_queue(mock_image_ctx);
149
150 InSequence seq;
151 utime_t delete_time{ceph_clock_now()};
152 expect_trash_add(mock_image_ctx, "image id",
153 cls::rbd::TRASH_IMAGE_SOURCE_USER, "image name", delete_time,
154 -EPERM);
155
156 C_SaferCond ctx;
157 cls::rbd::TrashImageSpec trash_image_spec{
158 cls::rbd::TRASH_IMAGE_SOURCE_USER, "image name", delete_time,
159 delete_time};
160 auto req = MockMoveRequest::create(mock_image_ctx.md_ctx, "image id",
161 trash_image_spec, &ctx);
162 req->send();
163 ASSERT_EQ(-EPERM, ctx.wait());
164 }
165
166 TEST_F(TestMockTrashMoveRequest, RemoveIdError) {
167 REQUIRE_FORMAT_V2();
168
169 librbd::ImageCtx *ictx;
170 ASSERT_EQ(0, open_image(m_image_name, &ictx));
171
172 MockTestImageCtx mock_image_ctx(*ictx);
173 MockExclusiveLock mock_exclusive_lock;
174 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
175 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
176 }
177
178 expect_op_work_queue(mock_image_ctx);
179
180 InSequence seq;
181 utime_t delete_time{ceph_clock_now()};
182 expect_trash_add(mock_image_ctx, "image id",
183 cls::rbd::TRASH_IMAGE_SOURCE_USER, "image name", delete_time,
184 0);
185 expect_aio_remove(mock_image_ctx, util::id_obj_name("image name"), -EPERM);
186
187 C_SaferCond ctx;
188 cls::rbd::TrashImageSpec trash_image_spec{
189 cls::rbd::TRASH_IMAGE_SOURCE_USER, "image name", delete_time,
190 delete_time};
191 auto req = MockMoveRequest::create(mock_image_ctx.md_ctx, "image id",
192 trash_image_spec, &ctx);
193 req->send();
194 ASSERT_EQ(-EPERM, ctx.wait());
195 }
196
197 TEST_F(TestMockTrashMoveRequest, DirectoryRemoveError) {
198 REQUIRE_FORMAT_V2();
199
200 librbd::ImageCtx *ictx;
201 ASSERT_EQ(0, open_image(m_image_name, &ictx));
202
203 MockTestImageCtx mock_image_ctx(*ictx);
204 MockExclusiveLock mock_exclusive_lock;
205 if (ictx->test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
206 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
207 }
208
209 expect_op_work_queue(mock_image_ctx);
210
211 InSequence seq;
212 utime_t delete_time{ceph_clock_now()};
213 expect_trash_add(mock_image_ctx, "image id",
214 cls::rbd::TRASH_IMAGE_SOURCE_USER, "image name", delete_time,
215 0);
216 expect_aio_remove(mock_image_ctx, util::id_obj_name("image name"), 0);
217 expect_dir_remove(mock_image_ctx, "image name", "image id", -EPERM);
218
219 C_SaferCond ctx;
220 cls::rbd::TrashImageSpec trash_image_spec{
221 cls::rbd::TRASH_IMAGE_SOURCE_USER, "image name", delete_time,
222 delete_time};
223 auto req = MockMoveRequest::create(mock_image_ctx.md_ctx, "image id",
224 trash_image_spec, &ctx);
225 req->send();
226 ASSERT_EQ(-EPERM, ctx.wait());
227 }
228
229 } // namespace trash
230 } // namespace librbd