1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 #include "test/librbd/test_fixture.h"
4 #include "test/librbd/test_support.h"
5 #include "include/int_types.h"
6 #include "include/stringify.h"
7 #include "include/rados/librados.h"
8 #include "include/rbd/librbd.hpp"
9 #include "common/Cond.h"
10 #include "common/ceph_mutex.h"
11 #include "common/errno.h"
12 #include "cls/lock/cls_lock_client.h"
13 #include "cls/lock/cls_lock_types.h"
14 #include "librbd/internal.h"
15 #include "librbd/ImageCtx.h"
16 #include "librbd/ImageWatcher.h"
17 #include "librbd/WatchNotifyTypes.h"
18 #include "librbd/io/AioCompletion.h"
19 #include "librbd/io/ImageRequestWQ.h"
20 #include "test/librados/test.h"
21 #include "gtest/gtest.h"
22 #include <boost/assign/std/set.hpp>
23 #include <boost/assign/std/map.hpp>
24 #include <boost/bind.hpp>
25 #include <boost/scope_exit.hpp>
26 #include <boost/thread/thread.hpp>
34 using namespace boost::assign
;
35 using namespace librbd::watch_notify
;
37 void register_test_image_watcher() {
40 class TestImageWatcher
: public TestFixture
{
43 TestImageWatcher() : m_watch_ctx(NULL
)
47 class WatchCtx
: public librados::WatchCtx2
{
49 explicit WatchCtx(TestImageWatcher
&parent
) : m_parent(parent
), m_handle(0) {}
51 int watch(const librbd::ImageCtx
&ictx
) {
52 m_header_oid
= ictx
.header_oid
;
53 return m_parent
.m_ioctx
.watch2(m_header_oid
, &m_handle
, this);
57 return m_parent
.m_ioctx
.unwatch2(m_handle
);
60 void handle_notify(uint64_t notify_id
,
63 bufferlist
& bl
) override
{
67 auto iter
= bl
.cbegin();
68 DECODE_START(1, iter
);
70 iter
.copy_all(payload
);
73 NotifyOp notify_op
= static_cast<NotifyOp
>(op
);
75 std::cout << "NOTIFY: " << notify_op << ", " << notify_id
76 << ", " << cookie << ", " << notifier_id << std::endl;
79 std::lock_guard l
{m_parent
.m_callback_lock
};
80 m_parent
.m_notify_payloads
[notify_op
] = payload
;
83 if (m_parent
.m_notify_acks
.count(notify_op
) > 0) {
84 reply
= m_parent
.m_notify_acks
[notify_op
];
85 m_parent
.m_notifies
+= notify_op
;
86 m_parent
.m_callback_cond
.notify_all();
89 m_parent
.m_ioctx
.notify_ack(m_header_oid
, notify_id
, cookie
, reply
);
95 void handle_error(uint64_t cookie
, int err
) override
{
96 std::cerr
<< "ERROR: " << cookie
<< ", " << cpp_strerror(err
)
100 uint64_t get_handle() const {
105 TestImageWatcher
&m_parent
;
106 std::string m_header_oid
;
110 void TearDown() override
{
111 deregister_image_watch();
112 TestFixture::TearDown();
115 int deregister_image_watch() {
116 if (m_watch_ctx
!= NULL
) {
117 int r
= m_watch_ctx
->unwatch();
119 librados::Rados
rados(m_ioctx
);
129 int register_image_watch(librbd::ImageCtx
&ictx
) {
130 m_watch_ctx
= new WatchCtx(*this);
131 return m_watch_ctx
->watch(ictx
);
134 bool wait_for_notifies(librbd::ImageCtx
&ictx
) {
135 std::unique_lock l
{m_callback_lock
};
136 while (m_notifies
.size() < m_notify_acks
.size()) {
137 if (m_callback_cond
.wait_for(l
, 10s
) == std::cv_status::timeout
) {
141 return (m_notifies
.size() == m_notify_acks
.size());
144 bufferlist
create_response_message(int r
) {
146 encode(ResponseMessage(r
), bl
);
150 bool extract_async_request_id(NotifyOp op
, AsyncRequestId
*id
) {
151 if (m_notify_payloads
.count(op
) == 0) {
155 bufferlist payload
= m_notify_payloads
[op
];
156 auto iter
= payload
.cbegin();
159 case NOTIFY_OP_FLATTEN
:
161 FlattenPayload payload
;
162 payload
.decode(2, iter
);
163 *id
= payload
.async_request_id
;
166 case NOTIFY_OP_RESIZE
:
168 ResizePayload payload
;
169 payload
.decode(2, iter
);
170 *id
= payload
.async_request_id
;
173 case NOTIFY_OP_REBUILD_OBJECT_MAP
:
175 RebuildObjectMapPayload payload
;
176 payload
.decode(2, iter
);
177 *id
= payload
.async_request_id
;
186 int notify_async_progress(librbd::ImageCtx
*ictx
, const AsyncRequestId
&id
,
187 uint64_t offset
, uint64_t total
) {
189 encode(NotifyMessage(AsyncProgressPayload(id
, offset
, total
)), bl
);
190 return m_ioctx
.notify2(ictx
->header_oid
, bl
, 5000, NULL
);
193 int notify_async_complete(librbd::ImageCtx
*ictx
, const AsyncRequestId
&id
,
196 encode(NotifyMessage(AsyncCompletePayload(id
, r
)), bl
);
197 return m_ioctx
.notify2(ictx
->header_oid
, bl
, 5000, NULL
);
200 typedef std::map
<NotifyOp
, bufferlist
> NotifyOpPayloads
;
201 typedef std::set
<NotifyOp
> NotifyOps
;
203 WatchCtx
*m_watch_ctx
;
205 NotifyOps m_notifies
;
206 NotifyOpPayloads m_notify_payloads
;
207 NotifyOpPayloads m_notify_acks
;
209 AsyncRequestId m_async_request_id
;
211 ceph::mutex m_callback_lock
= ceph::make_mutex("m_callback_lock");
212 ceph::condition_variable m_callback_cond
;
216 struct ProgressContext
: public librbd::ProgressContext
{
217 ceph::mutex mutex
= ceph::make_mutex("ProgressContext::mutex");
218 ceph::condition_variable cond
;
223 ProgressContext() : received(false),
224 offset(0), total(0) {}
226 int update_progress(uint64_t offset_
, uint64_t total_
) override
{
227 std::lock_guard l
{mutex
};
235 bool wait(librbd::ImageCtx
*ictx
, uint64_t offset_
, uint64_t total_
) {
236 std::unique_lock l
{mutex
};
238 if (cond
.wait_for(l
, 10s
) == std::cv_status::timeout
) {
242 return (received
&& offset
== offset_
&& total
== total_
);
247 librbd::ImageCtx
*ictx
;
248 ProgressContext
*progress_context
;
251 FlattenTask(librbd::ImageCtx
*ictx_
, ProgressContext
*ctx
)
252 : ictx(ictx_
), progress_context(ctx
), result(0) {}
255 std::shared_lock l
{ictx
->owner_lock
};
257 ictx
->image_watcher
->notify_flatten(0, *progress_context
, &ctx
);
263 librbd::ImageCtx
*ictx
;
264 ProgressContext
*progress_context
;
267 ResizeTask(librbd::ImageCtx
*ictx_
, ProgressContext
*ctx
)
268 : ictx(ictx_
), progress_context(ctx
), result(0) {}
271 std::shared_lock l
{ictx
->owner_lock
};
273 ictx
->image_watcher
->notify_resize(0, 0, true, *progress_context
, &ctx
);
278 struct RebuildObjectMapTask
{
279 librbd::ImageCtx
*ictx
;
280 ProgressContext
*progress_context
;
283 RebuildObjectMapTask(librbd::ImageCtx
*ictx_
, ProgressContext
*ctx
)
284 : ictx(ictx_
), progress_context(ctx
), result(0) {}
287 std::shared_lock l
{ictx
->owner_lock
};
289 ictx
->image_watcher
->notify_rebuild_object_map(0, *progress_context
, &ctx
);
294 TEST_F(TestImageWatcher
, NotifyHeaderUpdate
) {
295 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
297 librbd::ImageCtx
*ictx
;
298 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
300 ASSERT_EQ(0, register_image_watch(*ictx
));
302 m_notify_acks
= {{NOTIFY_OP_HEADER_UPDATE
, {}}};
303 ictx
->notify_update();
305 ASSERT_TRUE(wait_for_notifies(*ictx
));
307 NotifyOps expected_notify_ops
;
308 expected_notify_ops
+= NOTIFY_OP_HEADER_UPDATE
;
309 ASSERT_EQ(expected_notify_ops
, m_notifies
);
312 TEST_F(TestImageWatcher
, NotifyFlatten
) {
313 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
315 librbd::ImageCtx
*ictx
;
316 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
318 ASSERT_EQ(0, register_image_watch(*ictx
));
319 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
320 "auto " + stringify(m_watch_ctx
->get_handle())));
322 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, create_response_message(0)}};
324 ProgressContext progress_context
;
325 FlattenTask
flatten_task(ictx
, &progress_context
);
326 boost::thread
thread(boost::ref(flatten_task
));
328 ASSERT_TRUE(wait_for_notifies(*ictx
));
330 NotifyOps expected_notify_ops
;
331 expected_notify_ops
+= NOTIFY_OP_FLATTEN
;
332 ASSERT_EQ(expected_notify_ops
, m_notifies
);
334 AsyncRequestId async_request_id
;
335 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_FLATTEN
, &async_request_id
));
337 ASSERT_EQ(0, notify_async_progress(ictx
, async_request_id
, 10, 20));
338 ASSERT_TRUE(progress_context
.wait(ictx
, 10, 20));
340 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
342 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
343 ASSERT_EQ(0, flatten_task
.result
);
346 TEST_F(TestImageWatcher
, NotifyResize
) {
347 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
349 librbd::ImageCtx
*ictx
;
350 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
352 ASSERT_EQ(0, register_image_watch(*ictx
));
353 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
354 "auto " + stringify(m_watch_ctx
->get_handle())));
356 m_notify_acks
= {{NOTIFY_OP_RESIZE
, create_response_message(0)}};
358 ProgressContext progress_context
;
359 ResizeTask
resize_task(ictx
, &progress_context
);
360 boost::thread
thread(boost::ref(resize_task
));
362 ASSERT_TRUE(wait_for_notifies(*ictx
));
364 NotifyOps expected_notify_ops
;
365 expected_notify_ops
+= NOTIFY_OP_RESIZE
;
366 ASSERT_EQ(expected_notify_ops
, m_notifies
);
368 AsyncRequestId async_request_id
;
369 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_RESIZE
, &async_request_id
));
371 ASSERT_EQ(0, notify_async_progress(ictx
, async_request_id
, 10, 20));
372 ASSERT_TRUE(progress_context
.wait(ictx
, 10, 20));
374 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
376 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
377 ASSERT_EQ(0, resize_task
.result
);
380 TEST_F(TestImageWatcher
, NotifyRebuildObjectMap
) {
381 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
383 librbd::ImageCtx
*ictx
;
384 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
386 ASSERT_EQ(0, register_image_watch(*ictx
));
387 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
388 "auto " + stringify(m_watch_ctx
->get_handle())));
390 m_notify_acks
= {{NOTIFY_OP_REBUILD_OBJECT_MAP
, create_response_message(0)}};
392 ProgressContext progress_context
;
393 RebuildObjectMapTask
rebuild_task(ictx
, &progress_context
);
394 boost::thread
thread(boost::ref(rebuild_task
));
396 ASSERT_TRUE(wait_for_notifies(*ictx
));
398 NotifyOps expected_notify_ops
;
399 expected_notify_ops
+= NOTIFY_OP_REBUILD_OBJECT_MAP
;
400 ASSERT_EQ(expected_notify_ops
, m_notifies
);
402 AsyncRequestId async_request_id
;
403 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_REBUILD_OBJECT_MAP
,
406 ASSERT_EQ(0, notify_async_progress(ictx
, async_request_id
, 10, 20));
407 ASSERT_TRUE(progress_context
.wait(ictx
, 10, 20));
409 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
411 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
412 ASSERT_EQ(0, rebuild_task
.result
);
415 TEST_F(TestImageWatcher
, NotifySnapCreate
) {
416 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
418 librbd::ImageCtx
*ictx
;
419 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
421 ASSERT_EQ(0, register_image_watch(*ictx
));
422 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
423 "auto " + stringify(m_watch_ctx
->get_handle())));
425 m_notify_acks
= {{NOTIFY_OP_SNAP_CREATE
, create_response_message(0)}};
427 std::shared_lock l
{ictx
->owner_lock
};
428 C_SaferCond notify_ctx
;
429 ictx
->image_watcher
->notify_snap_create(cls::rbd::UserSnapshotNamespace(),
430 "snap", ¬ify_ctx
);
431 ASSERT_EQ(0, notify_ctx
.wait());
433 NotifyOps expected_notify_ops
;
434 expected_notify_ops
+= NOTIFY_OP_SNAP_CREATE
;
435 ASSERT_EQ(expected_notify_ops
, m_notifies
);
438 TEST_F(TestImageWatcher
, NotifySnapCreateError
) {
439 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
441 librbd::ImageCtx
*ictx
;
442 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
444 ASSERT_EQ(0, register_image_watch(*ictx
));
445 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
446 "auto " + stringify(m_watch_ctx
->get_handle())));
448 m_notify_acks
= {{NOTIFY_OP_SNAP_CREATE
, create_response_message(-EEXIST
)}};
450 std::shared_lock l
{ictx
->owner_lock
};
451 C_SaferCond notify_ctx
;
452 ictx
->image_watcher
->notify_snap_create(cls::rbd::UserSnapshotNamespace(),
453 "snap", ¬ify_ctx
);
454 ASSERT_EQ(-EEXIST
, notify_ctx
.wait());
456 NotifyOps expected_notify_ops
;
457 expected_notify_ops
+= NOTIFY_OP_SNAP_CREATE
;
458 ASSERT_EQ(expected_notify_ops
, m_notifies
);
461 TEST_F(TestImageWatcher
, NotifySnapRename
) {
462 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
464 librbd::ImageCtx
*ictx
;
465 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
467 ASSERT_EQ(0, register_image_watch(*ictx
));
468 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
469 "auto " + stringify(m_watch_ctx
->get_handle())));
471 m_notify_acks
= {{NOTIFY_OP_SNAP_RENAME
, create_response_message(0)}};
473 std::shared_lock l
{ictx
->owner_lock
};
474 C_SaferCond notify_ctx
;
475 ictx
->image_watcher
->notify_snap_rename(1, "snap-rename", ¬ify_ctx
);
476 ASSERT_EQ(0, notify_ctx
.wait());
478 NotifyOps expected_notify_ops
;
479 expected_notify_ops
+= NOTIFY_OP_SNAP_RENAME
;
480 ASSERT_EQ(expected_notify_ops
, m_notifies
);
483 TEST_F(TestImageWatcher
, NotifySnapRenameError
) {
484 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
486 librbd::ImageCtx
*ictx
;
487 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
489 ASSERT_EQ(0, register_image_watch(*ictx
));
490 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
491 "auto " + stringify(m_watch_ctx
->get_handle())));
493 m_notify_acks
= {{NOTIFY_OP_SNAP_RENAME
, create_response_message(-EEXIST
)}};
495 std::shared_lock l
{ictx
->owner_lock
};
496 C_SaferCond notify_ctx
;
497 ictx
->image_watcher
->notify_snap_rename(1, "snap-rename", ¬ify_ctx
);
498 ASSERT_EQ(-EEXIST
, notify_ctx
.wait());
500 NotifyOps expected_notify_ops
;
501 expected_notify_ops
+= NOTIFY_OP_SNAP_RENAME
;
502 ASSERT_EQ(expected_notify_ops
, m_notifies
);
505 TEST_F(TestImageWatcher
, NotifySnapRemove
) {
506 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
508 librbd::ImageCtx
*ictx
;
509 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
511 ASSERT_EQ(0, register_image_watch(*ictx
));
512 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
513 "auto " + stringify(m_watch_ctx
->get_handle())));
515 m_notify_acks
= {{NOTIFY_OP_SNAP_REMOVE
, create_response_message(0)}};
517 std::shared_lock l
{ictx
->owner_lock
};
518 C_SaferCond notify_ctx
;
519 ictx
->image_watcher
->notify_snap_remove(cls::rbd::UserSnapshotNamespace(),
522 ASSERT_EQ(0, notify_ctx
.wait());
524 NotifyOps expected_notify_ops
;
525 expected_notify_ops
+= NOTIFY_OP_SNAP_REMOVE
;
526 ASSERT_EQ(expected_notify_ops
, m_notifies
);
529 TEST_F(TestImageWatcher
, NotifySnapProtect
) {
530 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
532 librbd::ImageCtx
*ictx
;
533 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
535 ASSERT_EQ(0, register_image_watch(*ictx
));
536 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
537 "auto " + stringify(m_watch_ctx
->get_handle())));
539 m_notify_acks
= {{NOTIFY_OP_SNAP_PROTECT
, create_response_message(0)}};
541 std::shared_lock l
{ictx
->owner_lock
};
542 C_SaferCond notify_ctx
;
543 ictx
->image_watcher
->notify_snap_protect(cls::rbd::UserSnapshotNamespace(),
546 ASSERT_EQ(0, notify_ctx
.wait());
548 NotifyOps expected_notify_ops
;
549 expected_notify_ops
+= NOTIFY_OP_SNAP_PROTECT
;
550 ASSERT_EQ(expected_notify_ops
, m_notifies
);
553 TEST_F(TestImageWatcher
, NotifySnapUnprotect
) {
554 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
556 librbd::ImageCtx
*ictx
;
557 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
559 ASSERT_EQ(0, register_image_watch(*ictx
));
560 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
561 "auto " + stringify(m_watch_ctx
->get_handle())));
563 m_notify_acks
= {{NOTIFY_OP_SNAP_UNPROTECT
, create_response_message(0)}};
565 std::shared_lock l
{ictx
->owner_lock
};
566 C_SaferCond notify_ctx
;
567 ictx
->image_watcher
->notify_snap_unprotect(cls::rbd::UserSnapshotNamespace(),
570 ASSERT_EQ(0, notify_ctx
.wait());
572 NotifyOps expected_notify_ops
;
573 expected_notify_ops
+= NOTIFY_OP_SNAP_UNPROTECT
;
574 ASSERT_EQ(expected_notify_ops
, m_notifies
);
577 TEST_F(TestImageWatcher
, NotifyRename
) {
578 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
580 librbd::ImageCtx
*ictx
;
581 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
583 ASSERT_EQ(0, register_image_watch(*ictx
));
584 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
585 "auto " + stringify(m_watch_ctx
->get_handle())));
587 m_notify_acks
= {{NOTIFY_OP_RENAME
, create_response_message(0)}};
589 std::shared_lock l
{ictx
->owner_lock
};
590 C_SaferCond notify_ctx
;
591 ictx
->image_watcher
->notify_rename("new_name", ¬ify_ctx
);
592 ASSERT_EQ(0, notify_ctx
.wait());
594 NotifyOps expected_notify_ops
;
595 expected_notify_ops
+= NOTIFY_OP_RENAME
;
596 ASSERT_EQ(expected_notify_ops
, m_notifies
);
599 TEST_F(TestImageWatcher
, NotifyAsyncTimedOut
) {
600 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
602 librbd::ImageCtx
*ictx
;
603 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
605 ASSERT_EQ(0, register_image_watch(*ictx
));
606 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
607 "auto " + stringify(m_watch_ctx
->get_handle())));
609 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, {}}};
611 ProgressContext progress_context
;
612 FlattenTask
flatten_task(ictx
, &progress_context
);
613 boost::thread
thread(boost::ref(flatten_task
));
615 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
616 ASSERT_EQ(-ETIMEDOUT
, flatten_task
.result
);
619 TEST_F(TestImageWatcher
, NotifyAsyncError
) {
620 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
622 librbd::ImageCtx
*ictx
;
623 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
625 ASSERT_EQ(0, register_image_watch(*ictx
));
626 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
627 "auto " + stringify(m_watch_ctx
->get_handle())));
629 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, create_response_message(-EIO
)}};
631 ProgressContext progress_context
;
632 FlattenTask
flatten_task(ictx
, &progress_context
);
633 boost::thread
thread(boost::ref(flatten_task
));
635 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
636 ASSERT_EQ(-EIO
, flatten_task
.result
);
639 TEST_F(TestImageWatcher
, NotifyAsyncCompleteError
) {
640 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
642 librbd::ImageCtx
*ictx
;
643 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
645 ASSERT_EQ(0, register_image_watch(*ictx
));
646 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
647 "auto " + stringify(m_watch_ctx
->get_handle())));
649 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, create_response_message(0)}};
651 ProgressContext progress_context
;
652 FlattenTask
flatten_task(ictx
, &progress_context
);
653 boost::thread
thread(boost::ref(flatten_task
));
655 ASSERT_TRUE(wait_for_notifies(*ictx
));
657 NotifyOps expected_notify_ops
;
658 expected_notify_ops
+= NOTIFY_OP_FLATTEN
;
659 ASSERT_EQ(expected_notify_ops
, m_notifies
);
661 AsyncRequestId async_request_id
;
662 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_FLATTEN
, &async_request_id
));
664 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, -ESHUTDOWN
));
666 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
667 ASSERT_EQ(-ESHUTDOWN
, flatten_task
.result
);
670 TEST_F(TestImageWatcher
, NotifyAsyncRequestTimedOut
) {
671 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
673 librbd::ImageCtx
*ictx
;
674 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
676 ictx
->config
.set_val("rbd_request_timed_out_seconds", "0");
678 ASSERT_EQ(0, register_image_watch(*ictx
));
679 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
680 "auto " + stringify(m_watch_ctx
->get_handle())));
682 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, create_response_message(0)}};
684 ProgressContext progress_context
;
685 FlattenTask
flatten_task(ictx
, &progress_context
);
686 boost::thread
thread(boost::ref(flatten_task
));
688 ASSERT_TRUE(wait_for_notifies(*ictx
));
690 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
691 ASSERT_EQ(-ETIMEDOUT
, flatten_task
.result
);