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/errno.h"
11 #include "common/Mutex.h"
12 #include "common/RWLock.h"
13 #include "cls/lock/cls_lock_client.h"
14 #include "cls/lock/cls_lock_types.h"
15 #include "librbd/internal.h"
16 #include "librbd/ImageCtx.h"
17 #include "librbd/ImageWatcher.h"
18 #include "librbd/WatchNotifyTypes.h"
19 #include "librbd/io/AioCompletion.h"
20 #include "librbd/io/ImageRequestWQ.h"
21 #include "test/librados/test.h"
22 #include "gtest/gtest.h"
23 #include <boost/assign/std/set.hpp>
24 #include <boost/assign/std/map.hpp>
25 #include <boost/bind.hpp>
26 #include <boost/scope_exit.hpp>
27 #include <boost/thread/thread.hpp>
35 using namespace boost::assign
;
36 using namespace librbd::watch_notify
;
38 void register_test_image_watcher() {
41 class TestImageWatcher
: public TestFixture
{
44 TestImageWatcher() : m_watch_ctx(NULL
), m_callback_lock("m_callback_lock")
48 class WatchCtx
: public librados::WatchCtx2
{
50 explicit WatchCtx(TestImageWatcher
&parent
) : m_parent(parent
), m_handle(0) {}
52 int watch(const librbd::ImageCtx
&ictx
) {
53 m_header_oid
= ictx
.header_oid
;
54 return m_parent
.m_ioctx
.watch2(m_header_oid
, &m_handle
, this);
58 return m_parent
.m_ioctx
.unwatch2(m_handle
);
61 void handle_notify(uint64_t notify_id
,
64 bufferlist
& bl
) override
{
68 bufferlist::iterator iter
= bl
.begin();
69 DECODE_START(1, iter
);
71 iter
.copy_all(payload
);
74 NotifyOp notify_op
= static_cast<NotifyOp
>(op
);
76 std::cout << "NOTIFY: " << notify_op << ", " << notify_id
77 << ", " << cookie << ", " << notifier_id << std::endl;
80 Mutex::Locker
l(m_parent
.m_callback_lock
);
81 m_parent
.m_notify_payloads
[notify_op
] = payload
;
84 if (m_parent
.m_notify_acks
.count(notify_op
) > 0) {
85 reply
= m_parent
.m_notify_acks
[notify_op
];
86 m_parent
.m_notifies
+= notify_op
;
87 m_parent
.m_callback_cond
.Signal();
90 m_parent
.m_ioctx
.notify_ack(m_header_oid
, notify_id
, cookie
, reply
);
96 void handle_error(uint64_t cookie
, int err
) override
{
97 std::cerr
<< "ERROR: " << cookie
<< ", " << cpp_strerror(err
)
101 uint64_t get_handle() const {
106 TestImageWatcher
&m_parent
;
107 std::string m_header_oid
;
111 void TearDown() override
{
112 deregister_image_watch();
113 TestFixture::TearDown();
116 int deregister_image_watch() {
117 if (m_watch_ctx
!= NULL
) {
118 int r
= m_watch_ctx
->unwatch();
120 librados::Rados
rados(m_ioctx
);
130 int register_image_watch(librbd::ImageCtx
&ictx
) {
131 m_watch_ctx
= new WatchCtx(*this);
132 return m_watch_ctx
->watch(ictx
);
135 bool wait_for_notifies(librbd::ImageCtx
&ictx
) {
136 Mutex::Locker
l(m_callback_lock
);
137 while (m_notifies
.size() < m_notify_acks
.size()) {
138 int r
= m_callback_cond
.WaitInterval(m_callback_lock
,
144 return (m_notifies
.size() == m_notify_acks
.size());
147 bufferlist
create_response_message(int r
) {
149 ::encode(ResponseMessage(r
), bl
);
153 bool extract_async_request_id(NotifyOp op
, AsyncRequestId
*id
) {
154 if (m_notify_payloads
.count(op
) == 0) {
158 bufferlist payload
= m_notify_payloads
[op
];
159 bufferlist::iterator iter
= payload
.begin();
162 case NOTIFY_OP_FLATTEN
:
164 FlattenPayload payload
;
165 payload
.decode(2, iter
);
166 *id
= payload
.async_request_id
;
169 case NOTIFY_OP_RESIZE
:
171 ResizePayload payload
;
172 payload
.decode(2, iter
);
173 *id
= payload
.async_request_id
;
176 case NOTIFY_OP_REBUILD_OBJECT_MAP
:
178 RebuildObjectMapPayload payload
;
179 payload
.decode(2, iter
);
180 *id
= payload
.async_request_id
;
189 int notify_async_progress(librbd::ImageCtx
*ictx
, const AsyncRequestId
&id
,
190 uint64_t offset
, uint64_t total
) {
192 ::encode(NotifyMessage(AsyncProgressPayload(id
, offset
, total
)), bl
);
193 return m_ioctx
.notify2(ictx
->header_oid
, bl
, 5000, NULL
);
196 int notify_async_complete(librbd::ImageCtx
*ictx
, const AsyncRequestId
&id
,
199 ::encode(NotifyMessage(AsyncCompletePayload(id
, r
)), bl
);
200 return m_ioctx
.notify2(ictx
->header_oid
, bl
, 5000, NULL
);
203 typedef std::map
<NotifyOp
, bufferlist
> NotifyOpPayloads
;
204 typedef std::set
<NotifyOp
> NotifyOps
;
206 WatchCtx
*m_watch_ctx
;
208 NotifyOps m_notifies
;
209 NotifyOpPayloads m_notify_payloads
;
210 NotifyOpPayloads m_notify_acks
;
212 AsyncRequestId m_async_request_id
;
214 Mutex m_callback_lock
;
215 Cond m_callback_cond
;
219 struct ProgressContext
: public librbd::ProgressContext
{
226 ProgressContext() : mutex("ProgressContext::mutex"), received(false),
227 offset(0), total(0) {}
229 int update_progress(uint64_t offset_
, uint64_t total_
) override
{
230 Mutex::Locker
l(mutex
);
238 bool wait(librbd::ImageCtx
*ictx
, uint64_t offset_
, uint64_t total_
) {
239 Mutex::Locker
l(mutex
);
241 int r
= cond
.WaitInterval(mutex
, utime_t(10, 0));
246 return (received
&& offset
== offset_
&& total
== total_
);
251 librbd::ImageCtx
*ictx
;
252 ProgressContext
*progress_context
;
255 FlattenTask(librbd::ImageCtx
*ictx_
, ProgressContext
*ctx
)
256 : ictx(ictx_
), progress_context(ctx
), result(0) {}
259 RWLock::RLocker
l(ictx
->owner_lock
);
261 ictx
->image_watcher
->notify_flatten(0, *progress_context
, &ctx
);
267 librbd::ImageCtx
*ictx
;
268 ProgressContext
*progress_context
;
271 ResizeTask(librbd::ImageCtx
*ictx_
, ProgressContext
*ctx
)
272 : ictx(ictx_
), progress_context(ctx
), result(0) {}
275 RWLock::RLocker
l(ictx
->owner_lock
);
277 ictx
->image_watcher
->notify_resize(0, 0, true, *progress_context
, &ctx
);
282 struct RebuildObjectMapTask
{
283 librbd::ImageCtx
*ictx
;
284 ProgressContext
*progress_context
;
287 RebuildObjectMapTask(librbd::ImageCtx
*ictx_
, ProgressContext
*ctx
)
288 : ictx(ictx_
), progress_context(ctx
), result(0) {}
291 RWLock::RLocker
l(ictx
->owner_lock
);
293 ictx
->image_watcher
->notify_rebuild_object_map(0, *progress_context
, &ctx
);
298 TEST_F(TestImageWatcher
, NotifyHeaderUpdate
) {
299 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
301 librbd::ImageCtx
*ictx
;
302 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
304 ASSERT_EQ(0, register_image_watch(*ictx
));
306 m_notify_acks
= {{NOTIFY_OP_HEADER_UPDATE
, {}}};
307 ictx
->notify_update();
309 ASSERT_TRUE(wait_for_notifies(*ictx
));
311 NotifyOps expected_notify_ops
;
312 expected_notify_ops
+= NOTIFY_OP_HEADER_UPDATE
;
313 ASSERT_EQ(expected_notify_ops
, m_notifies
);
316 TEST_F(TestImageWatcher
, NotifyFlatten
) {
317 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
319 librbd::ImageCtx
*ictx
;
320 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
322 ASSERT_EQ(0, register_image_watch(*ictx
));
323 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
324 "auto " + stringify(m_watch_ctx
->get_handle())));
326 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, create_response_message(0)}};
328 ProgressContext progress_context
;
329 FlattenTask
flatten_task(ictx
, &progress_context
);
330 boost::thread
thread(boost::ref(flatten_task
));
332 ASSERT_TRUE(wait_for_notifies(*ictx
));
334 NotifyOps expected_notify_ops
;
335 expected_notify_ops
+= NOTIFY_OP_FLATTEN
;
336 ASSERT_EQ(expected_notify_ops
, m_notifies
);
338 AsyncRequestId async_request_id
;
339 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_FLATTEN
, &async_request_id
));
341 ASSERT_EQ(0, notify_async_progress(ictx
, async_request_id
, 10, 20));
342 ASSERT_TRUE(progress_context
.wait(ictx
, 10, 20));
344 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
346 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
347 ASSERT_EQ(0, flatten_task
.result
);
350 TEST_F(TestImageWatcher
, NotifyResize
) {
351 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
353 librbd::ImageCtx
*ictx
;
354 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
356 ASSERT_EQ(0, register_image_watch(*ictx
));
357 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
358 "auto " + stringify(m_watch_ctx
->get_handle())));
360 m_notify_acks
= {{NOTIFY_OP_RESIZE
, create_response_message(0)}};
362 ProgressContext progress_context
;
363 ResizeTask
resize_task(ictx
, &progress_context
);
364 boost::thread
thread(boost::ref(resize_task
));
366 ASSERT_TRUE(wait_for_notifies(*ictx
));
368 NotifyOps expected_notify_ops
;
369 expected_notify_ops
+= NOTIFY_OP_RESIZE
;
370 ASSERT_EQ(expected_notify_ops
, m_notifies
);
372 AsyncRequestId async_request_id
;
373 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_RESIZE
, &async_request_id
));
375 ASSERT_EQ(0, notify_async_progress(ictx
, async_request_id
, 10, 20));
376 ASSERT_TRUE(progress_context
.wait(ictx
, 10, 20));
378 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
380 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
381 ASSERT_EQ(0, resize_task
.result
);
384 TEST_F(TestImageWatcher
, NotifyRebuildObjectMap
) {
385 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
387 librbd::ImageCtx
*ictx
;
388 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
390 ASSERT_EQ(0, register_image_watch(*ictx
));
391 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
392 "auto " + stringify(m_watch_ctx
->get_handle())));
394 m_notify_acks
= {{NOTIFY_OP_REBUILD_OBJECT_MAP
, create_response_message(0)}};
396 ProgressContext progress_context
;
397 RebuildObjectMapTask
rebuild_task(ictx
, &progress_context
);
398 boost::thread
thread(boost::ref(rebuild_task
));
400 ASSERT_TRUE(wait_for_notifies(*ictx
));
402 NotifyOps expected_notify_ops
;
403 expected_notify_ops
+= NOTIFY_OP_REBUILD_OBJECT_MAP
;
404 ASSERT_EQ(expected_notify_ops
, m_notifies
);
406 AsyncRequestId async_request_id
;
407 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_REBUILD_OBJECT_MAP
,
410 ASSERT_EQ(0, notify_async_progress(ictx
, async_request_id
, 10, 20));
411 ASSERT_TRUE(progress_context
.wait(ictx
, 10, 20));
413 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, 0));
415 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
416 ASSERT_EQ(0, rebuild_task
.result
);
419 TEST_F(TestImageWatcher
, NotifySnapCreate
) {
420 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
422 librbd::ImageCtx
*ictx
;
423 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
425 ASSERT_EQ(0, register_image_watch(*ictx
));
426 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
427 "auto " + stringify(m_watch_ctx
->get_handle())));
429 m_notify_acks
= {{NOTIFY_OP_SNAP_CREATE
, create_response_message(0)}};
431 RWLock::RLocker
l(ictx
->owner_lock
);
432 C_SaferCond notify_ctx
;
433 ictx
->image_watcher
->notify_snap_create(cls::rbd::UserSnapshotNamespace(),
434 "snap", ¬ify_ctx
);
435 ASSERT_EQ(0, notify_ctx
.wait());
437 NotifyOps expected_notify_ops
;
438 expected_notify_ops
+= NOTIFY_OP_SNAP_CREATE
;
439 ASSERT_EQ(expected_notify_ops
, m_notifies
);
442 TEST_F(TestImageWatcher
, NotifySnapCreateError
) {
443 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
445 librbd::ImageCtx
*ictx
;
446 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
448 ASSERT_EQ(0, register_image_watch(*ictx
));
449 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
450 "auto " + stringify(m_watch_ctx
->get_handle())));
452 m_notify_acks
= {{NOTIFY_OP_SNAP_CREATE
, create_response_message(-EEXIST
)}};
454 RWLock::RLocker
l(ictx
->owner_lock
);
455 C_SaferCond notify_ctx
;
456 ictx
->image_watcher
->notify_snap_create(cls::rbd::UserSnapshotNamespace(),
457 "snap", ¬ify_ctx
);
458 ASSERT_EQ(-EEXIST
, notify_ctx
.wait());
460 NotifyOps expected_notify_ops
;
461 expected_notify_ops
+= NOTIFY_OP_SNAP_CREATE
;
462 ASSERT_EQ(expected_notify_ops
, m_notifies
);
465 TEST_F(TestImageWatcher
, NotifySnapRename
) {
466 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
468 librbd::ImageCtx
*ictx
;
469 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
471 ASSERT_EQ(0, register_image_watch(*ictx
));
472 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
473 "auto " + stringify(m_watch_ctx
->get_handle())));
475 m_notify_acks
= {{NOTIFY_OP_SNAP_RENAME
, create_response_message(0)}};
477 RWLock::RLocker
l(ictx
->owner_lock
);
478 C_SaferCond notify_ctx
;
479 ictx
->image_watcher
->notify_snap_rename(1, "snap-rename", ¬ify_ctx
);
480 ASSERT_EQ(0, notify_ctx
.wait());
482 NotifyOps expected_notify_ops
;
483 expected_notify_ops
+= NOTIFY_OP_SNAP_RENAME
;
484 ASSERT_EQ(expected_notify_ops
, m_notifies
);
487 TEST_F(TestImageWatcher
, NotifySnapRenameError
) {
488 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
490 librbd::ImageCtx
*ictx
;
491 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
493 ASSERT_EQ(0, register_image_watch(*ictx
));
494 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
495 "auto " + stringify(m_watch_ctx
->get_handle())));
497 m_notify_acks
= {{NOTIFY_OP_SNAP_RENAME
, create_response_message(-EEXIST
)}};
499 RWLock::RLocker
l(ictx
->owner_lock
);
500 C_SaferCond notify_ctx
;
501 ictx
->image_watcher
->notify_snap_rename(1, "snap-rename", ¬ify_ctx
);
502 ASSERT_EQ(-EEXIST
, notify_ctx
.wait());
504 NotifyOps expected_notify_ops
;
505 expected_notify_ops
+= NOTIFY_OP_SNAP_RENAME
;
506 ASSERT_EQ(expected_notify_ops
, m_notifies
);
509 TEST_F(TestImageWatcher
, NotifySnapRemove
) {
510 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
512 librbd::ImageCtx
*ictx
;
513 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
515 ASSERT_EQ(0, register_image_watch(*ictx
));
516 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
517 "auto " + stringify(m_watch_ctx
->get_handle())));
519 m_notify_acks
= {{NOTIFY_OP_SNAP_REMOVE
, create_response_message(0)}};
521 RWLock::RLocker
l(ictx
->owner_lock
);
522 C_SaferCond notify_ctx
;
523 ictx
->image_watcher
->notify_snap_remove(cls::rbd::UserSnapshotNamespace(),
526 ASSERT_EQ(0, notify_ctx
.wait());
528 NotifyOps expected_notify_ops
;
529 expected_notify_ops
+= NOTIFY_OP_SNAP_REMOVE
;
530 ASSERT_EQ(expected_notify_ops
, m_notifies
);
533 TEST_F(TestImageWatcher
, NotifySnapProtect
) {
534 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
536 librbd::ImageCtx
*ictx
;
537 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
539 ASSERT_EQ(0, register_image_watch(*ictx
));
540 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
541 "auto " + stringify(m_watch_ctx
->get_handle())));
543 m_notify_acks
= {{NOTIFY_OP_SNAP_PROTECT
, create_response_message(0)}};
545 RWLock::RLocker
l(ictx
->owner_lock
);
546 C_SaferCond notify_ctx
;
547 ictx
->image_watcher
->notify_snap_protect(cls::rbd::UserSnapshotNamespace(),
550 ASSERT_EQ(0, notify_ctx
.wait());
552 NotifyOps expected_notify_ops
;
553 expected_notify_ops
+= NOTIFY_OP_SNAP_PROTECT
;
554 ASSERT_EQ(expected_notify_ops
, m_notifies
);
557 TEST_F(TestImageWatcher
, NotifySnapUnprotect
) {
558 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
560 librbd::ImageCtx
*ictx
;
561 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
563 ASSERT_EQ(0, register_image_watch(*ictx
));
564 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
565 "auto " + stringify(m_watch_ctx
->get_handle())));
567 m_notify_acks
= {{NOTIFY_OP_SNAP_UNPROTECT
, create_response_message(0)}};
569 RWLock::RLocker
l(ictx
->owner_lock
);
570 C_SaferCond notify_ctx
;
571 ictx
->image_watcher
->notify_snap_unprotect(cls::rbd::UserSnapshotNamespace(),
574 ASSERT_EQ(0, notify_ctx
.wait());
576 NotifyOps expected_notify_ops
;
577 expected_notify_ops
+= NOTIFY_OP_SNAP_UNPROTECT
;
578 ASSERT_EQ(expected_notify_ops
, m_notifies
);
581 TEST_F(TestImageWatcher
, NotifyRename
) {
582 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
584 librbd::ImageCtx
*ictx
;
585 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
587 ASSERT_EQ(0, register_image_watch(*ictx
));
588 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
589 "auto " + stringify(m_watch_ctx
->get_handle())));
591 m_notify_acks
= {{NOTIFY_OP_RENAME
, create_response_message(0)}};
593 RWLock::RLocker
l(ictx
->owner_lock
);
594 C_SaferCond notify_ctx
;
595 ictx
->image_watcher
->notify_rename("new_name", ¬ify_ctx
);
596 ASSERT_EQ(0, notify_ctx
.wait());
598 NotifyOps expected_notify_ops
;
599 expected_notify_ops
+= NOTIFY_OP_RENAME
;
600 ASSERT_EQ(expected_notify_ops
, m_notifies
);
603 TEST_F(TestImageWatcher
, NotifyAsyncTimedOut
) {
604 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
606 librbd::ImageCtx
*ictx
;
607 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
609 ASSERT_EQ(0, register_image_watch(*ictx
));
610 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
611 "auto " + stringify(m_watch_ctx
->get_handle())));
613 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, {}}};
615 ProgressContext progress_context
;
616 FlattenTask
flatten_task(ictx
, &progress_context
);
617 boost::thread
thread(boost::ref(flatten_task
));
619 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
620 ASSERT_EQ(-ETIMEDOUT
, flatten_task
.result
);
623 TEST_F(TestImageWatcher
, NotifyAsyncError
) {
624 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
626 librbd::ImageCtx
*ictx
;
627 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
629 ASSERT_EQ(0, register_image_watch(*ictx
));
630 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
631 "auto " + stringify(m_watch_ctx
->get_handle())));
633 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, create_response_message(-EIO
)}};
635 ProgressContext progress_context
;
636 FlattenTask
flatten_task(ictx
, &progress_context
);
637 boost::thread
thread(boost::ref(flatten_task
));
639 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
640 ASSERT_EQ(-EIO
, flatten_task
.result
);
643 TEST_F(TestImageWatcher
, NotifyAsyncCompleteError
) {
644 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
646 librbd::ImageCtx
*ictx
;
647 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
649 ASSERT_EQ(0, register_image_watch(*ictx
));
650 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
651 "auto " + stringify(m_watch_ctx
->get_handle())));
653 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, create_response_message(0)}};
655 ProgressContext progress_context
;
656 FlattenTask
flatten_task(ictx
, &progress_context
);
657 boost::thread
thread(boost::ref(flatten_task
));
659 ASSERT_TRUE(wait_for_notifies(*ictx
));
661 NotifyOps expected_notify_ops
;
662 expected_notify_ops
+= NOTIFY_OP_FLATTEN
;
663 ASSERT_EQ(expected_notify_ops
, m_notifies
);
665 AsyncRequestId async_request_id
;
666 ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_FLATTEN
, &async_request_id
));
668 ASSERT_EQ(0, notify_async_complete(ictx
, async_request_id
, -ESHUTDOWN
));
670 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
671 ASSERT_EQ(-ESHUTDOWN
, flatten_task
.result
);
674 TEST_F(TestImageWatcher
, NotifyAsyncRequestTimedOut
) {
675 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK
);
677 librbd::ImageCtx
*ictx
;
678 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
680 ictx
->request_timed_out_seconds
= 0;
682 ASSERT_EQ(0, register_image_watch(*ictx
));
683 ASSERT_EQ(0, lock_image(*ictx
, LOCK_EXCLUSIVE
,
684 "auto " + stringify(m_watch_ctx
->get_handle())));
686 m_notify_acks
= {{NOTIFY_OP_FLATTEN
, create_response_message(0)}};
688 ProgressContext progress_context
;
689 FlattenTask
flatten_task(ictx
, &progress_context
);
690 boost::thread
thread(boost::ref(flatten_task
));
692 ASSERT_TRUE(wait_for_notifies(*ictx
));
694 ASSERT_TRUE(thread
.timed_join(boost::posix_time::seconds(10)));
695 ASSERT_EQ(-ETIMEDOUT
, flatten_task
.result
);