Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / librbd / test_ImageWatcher.cc
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>
28 #include <iostream>
29 #include <map>
30 #include <set>
31 #include <sstream>
32 #include <vector>
33
34 using namespace ceph;
35 using namespace boost::assign;
36 using namespace librbd::watch_notify;
37
38 void register_test_image_watcher() {
39 }
40
41 class TestImageWatcher : public TestFixture {
42 public:
43
44   TestImageWatcher() : m_watch_ctx(NULL), m_callback_lock("m_callback_lock")
45   {
46   }
47
48   class WatchCtx : public librados::WatchCtx2 {
49   public:
50     explicit WatchCtx(TestImageWatcher &parent) : m_parent(parent), m_handle(0) {}
51
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);
55     }
56
57     int unwatch() {
58       return m_parent.m_ioctx.unwatch2(m_handle);
59     }
60
61     void handle_notify(uint64_t notify_id,
62                                uint64_t cookie,
63                                uint64_t notifier_id,
64                                bufferlist& bl) override {
65       try {
66         int op;
67         bufferlist payload;
68         bufferlist::iterator iter = bl.begin();
69         DECODE_START(1, iter);
70         ::decode(op, iter);
71         iter.copy_all(payload);
72         DECODE_FINISH(iter);
73
74         NotifyOp notify_op = static_cast<NotifyOp>(op);
75         /*
76         std::cout << "NOTIFY: " << notify_op << ", " << notify_id
77                   << ", " << cookie << ", " << notifier_id << std::endl;
78         */
79
80         Mutex::Locker l(m_parent.m_callback_lock);
81         m_parent.m_notify_payloads[notify_op] = payload;
82
83         bufferlist reply;
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();
88         }
89
90         m_parent.m_ioctx.notify_ack(m_header_oid, notify_id, cookie, reply);
91       } catch (...) {
92         FAIL();
93       }
94     }
95
96     void handle_error(uint64_t cookie, int err) override {
97       std::cerr << "ERROR: " << cookie << ", " << cpp_strerror(err)
98                 << std::endl; 
99     }
100
101     uint64_t get_handle() const {
102       return m_handle;
103     }
104
105   private:
106     TestImageWatcher &m_parent;
107     std::string m_header_oid;
108     uint64_t m_handle;
109   };
110
111   void TearDown() override {
112     deregister_image_watch();
113     TestFixture::TearDown();
114   }
115
116   int deregister_image_watch() {
117     if (m_watch_ctx != NULL) {
118       int r = m_watch_ctx->unwatch();
119
120       librados::Rados rados(m_ioctx);
121       rados.watch_flush();
122
123       delete m_watch_ctx;
124       m_watch_ctx = NULL;
125       return r;
126     }
127     return 0;
128   }
129
130   int register_image_watch(librbd::ImageCtx &ictx) {
131     m_watch_ctx = new WatchCtx(*this);
132     return m_watch_ctx->watch(ictx);
133   }
134
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,
139                                            utime_t(10, 0));
140       if (r != 0) {
141         break;
142       }
143     }
144     return (m_notifies.size() == m_notify_acks.size());
145   }
146
147   bufferlist create_response_message(int r) {
148     bufferlist bl;
149     ::encode(ResponseMessage(r), bl);
150     return bl;
151   }
152
153   bool extract_async_request_id(NotifyOp op, AsyncRequestId *id) {
154     if (m_notify_payloads.count(op) == 0) {
155       return false;
156     }
157
158     bufferlist payload = m_notify_payloads[op];
159     bufferlist::iterator iter = payload.begin();
160
161     switch (op) {
162     case NOTIFY_OP_FLATTEN:
163       {
164         FlattenPayload payload;
165         payload.decode(2, iter);
166         *id = payload.async_request_id;
167       }
168       return true;
169     case NOTIFY_OP_RESIZE:
170       {
171         ResizePayload payload;
172         payload.decode(2, iter);
173         *id = payload.async_request_id;
174       }
175       return true;
176     case NOTIFY_OP_REBUILD_OBJECT_MAP:
177       {
178         RebuildObjectMapPayload payload;
179         payload.decode(2, iter);
180         *id = payload.async_request_id;
181       }
182       return true;
183     default:
184       break;
185     }
186     return false;
187   }
188
189   int notify_async_progress(librbd::ImageCtx *ictx, const AsyncRequestId &id,
190                             uint64_t offset, uint64_t total) {
191     bufferlist bl;
192     ::encode(NotifyMessage(AsyncProgressPayload(id, offset, total)), bl);
193     return m_ioctx.notify2(ictx->header_oid, bl, 5000, NULL);
194   }
195
196   int notify_async_complete(librbd::ImageCtx *ictx, const AsyncRequestId &id,
197                             int r) {
198     bufferlist bl;
199     ::encode(NotifyMessage(AsyncCompletePayload(id, r)), bl);
200     return m_ioctx.notify2(ictx->header_oid, bl, 5000, NULL);
201   }
202
203   typedef std::map<NotifyOp, bufferlist> NotifyOpPayloads;
204   typedef std::set<NotifyOp> NotifyOps;
205
206   WatchCtx *m_watch_ctx;
207
208   NotifyOps m_notifies;
209   NotifyOpPayloads m_notify_payloads;
210   NotifyOpPayloads m_notify_acks;
211
212   AsyncRequestId m_async_request_id;
213
214   Mutex m_callback_lock;
215   Cond m_callback_cond;
216
217 };
218
219 struct ProgressContext : public librbd::ProgressContext {
220   Mutex mutex;
221   Cond cond;
222   bool received;
223   uint64_t offset;
224   uint64_t total;
225
226   ProgressContext() : mutex("ProgressContext::mutex"), received(false),
227                       offset(0), total(0) {}
228
229   int update_progress(uint64_t offset_, uint64_t total_) override {
230     Mutex::Locker l(mutex);
231     offset = offset_;
232     total = total_;
233     received = true;
234     cond.Signal();
235     return 0;
236   }
237
238   bool wait(librbd::ImageCtx *ictx, uint64_t offset_, uint64_t total_) {
239     Mutex::Locker l(mutex);
240     while (!received) {
241       int r = cond.WaitInterval(mutex, utime_t(10, 0));
242       if (r != 0) {
243         break;
244       }
245     }
246     return (received && offset == offset_ && total == total_);
247   }
248 };
249
250 struct FlattenTask {
251   librbd::ImageCtx *ictx;
252   ProgressContext *progress_context;
253   int result;
254
255   FlattenTask(librbd::ImageCtx *ictx_, ProgressContext *ctx)
256     : ictx(ictx_), progress_context(ctx), result(0) {}
257
258   void operator()() {
259     RWLock::RLocker l(ictx->owner_lock);
260     C_SaferCond ctx;
261     ictx->image_watcher->notify_flatten(0, *progress_context, &ctx);
262     result = ctx.wait();
263   }
264 };
265
266 struct ResizeTask {
267   librbd::ImageCtx *ictx;
268   ProgressContext *progress_context;
269   int result;
270
271   ResizeTask(librbd::ImageCtx *ictx_, ProgressContext *ctx)
272     : ictx(ictx_), progress_context(ctx), result(0) {}
273
274   void operator()() {
275     RWLock::RLocker l(ictx->owner_lock);
276     C_SaferCond ctx;
277     ictx->image_watcher->notify_resize(0, 0, true, *progress_context, &ctx);
278     result = ctx.wait();
279   }
280 };
281
282 struct RebuildObjectMapTask {
283   librbd::ImageCtx *ictx;
284   ProgressContext *progress_context;
285   int result;
286
287   RebuildObjectMapTask(librbd::ImageCtx *ictx_, ProgressContext *ctx)
288     : ictx(ictx_), progress_context(ctx), result(0) {}
289
290   void operator()() {
291     RWLock::RLocker l(ictx->owner_lock);
292     C_SaferCond ctx;
293     ictx->image_watcher->notify_rebuild_object_map(0, *progress_context, &ctx);
294     result = ctx.wait();
295   }
296 };
297
298 TEST_F(TestImageWatcher, NotifyHeaderUpdate) {
299   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
300
301   librbd::ImageCtx *ictx;
302   ASSERT_EQ(0, open_image(m_image_name, &ictx));
303
304   ASSERT_EQ(0, register_image_watch(*ictx));
305
306   m_notify_acks = {{NOTIFY_OP_HEADER_UPDATE, {}}};
307   ictx->notify_update();
308
309   ASSERT_TRUE(wait_for_notifies(*ictx));
310
311   NotifyOps expected_notify_ops;
312   expected_notify_ops += NOTIFY_OP_HEADER_UPDATE;
313   ASSERT_EQ(expected_notify_ops, m_notifies);
314 }
315
316 TEST_F(TestImageWatcher, NotifyFlatten) {
317   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
318
319   librbd::ImageCtx *ictx;
320   ASSERT_EQ(0, open_image(m_image_name, &ictx));
321
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())));
325
326   m_notify_acks = {{NOTIFY_OP_FLATTEN, create_response_message(0)}};
327
328   ProgressContext progress_context;
329   FlattenTask flatten_task(ictx, &progress_context);
330   boost::thread thread(boost::ref(flatten_task));
331
332   ASSERT_TRUE(wait_for_notifies(*ictx));
333
334   NotifyOps expected_notify_ops;
335   expected_notify_ops += NOTIFY_OP_FLATTEN;
336   ASSERT_EQ(expected_notify_ops, m_notifies);
337
338   AsyncRequestId async_request_id;
339   ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_FLATTEN, &async_request_id));
340
341   ASSERT_EQ(0, notify_async_progress(ictx, async_request_id, 10, 20));
342   ASSERT_TRUE(progress_context.wait(ictx, 10, 20));
343
344   ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0));
345
346   ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10)));
347   ASSERT_EQ(0, flatten_task.result);
348 }
349
350 TEST_F(TestImageWatcher, NotifyResize) {
351   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
352
353   librbd::ImageCtx *ictx;
354   ASSERT_EQ(0, open_image(m_image_name, &ictx));
355
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())));
359
360   m_notify_acks = {{NOTIFY_OP_RESIZE, create_response_message(0)}};
361
362   ProgressContext progress_context;
363   ResizeTask resize_task(ictx, &progress_context);
364   boost::thread thread(boost::ref(resize_task));
365
366   ASSERT_TRUE(wait_for_notifies(*ictx));
367
368   NotifyOps expected_notify_ops;
369   expected_notify_ops += NOTIFY_OP_RESIZE;
370   ASSERT_EQ(expected_notify_ops, m_notifies);
371
372   AsyncRequestId async_request_id;
373   ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_RESIZE, &async_request_id));
374
375   ASSERT_EQ(0, notify_async_progress(ictx, async_request_id, 10, 20));
376   ASSERT_TRUE(progress_context.wait(ictx, 10, 20));
377
378   ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0));
379
380   ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10)));
381   ASSERT_EQ(0, resize_task.result);
382 }
383
384 TEST_F(TestImageWatcher, NotifyRebuildObjectMap) {
385   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
386
387   librbd::ImageCtx *ictx;
388   ASSERT_EQ(0, open_image(m_image_name, &ictx));
389
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())));
393
394   m_notify_acks = {{NOTIFY_OP_REBUILD_OBJECT_MAP, create_response_message(0)}};
395
396   ProgressContext progress_context;
397   RebuildObjectMapTask rebuild_task(ictx, &progress_context);
398   boost::thread thread(boost::ref(rebuild_task));
399
400   ASSERT_TRUE(wait_for_notifies(*ictx));
401
402   NotifyOps expected_notify_ops;
403   expected_notify_ops += NOTIFY_OP_REBUILD_OBJECT_MAP;
404   ASSERT_EQ(expected_notify_ops, m_notifies);
405
406   AsyncRequestId async_request_id;
407   ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_REBUILD_OBJECT_MAP,
408                                        &async_request_id));
409
410   ASSERT_EQ(0, notify_async_progress(ictx, async_request_id, 10, 20));
411   ASSERT_TRUE(progress_context.wait(ictx, 10, 20));
412
413   ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, 0));
414
415   ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10)));
416   ASSERT_EQ(0, rebuild_task.result);
417 }
418
419 TEST_F(TestImageWatcher, NotifySnapCreate) {
420   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
421
422   librbd::ImageCtx *ictx;
423   ASSERT_EQ(0, open_image(m_image_name, &ictx));
424
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())));
428
429   m_notify_acks = {{NOTIFY_OP_SNAP_CREATE, create_response_message(0)}};
430
431   RWLock::RLocker l(ictx->owner_lock);
432   C_SaferCond notify_ctx;
433   ictx->image_watcher->notify_snap_create(cls::rbd::UserSnapshotNamespace(),
434         "snap", &notify_ctx);
435   ASSERT_EQ(0, notify_ctx.wait());
436
437   NotifyOps expected_notify_ops;
438   expected_notify_ops += NOTIFY_OP_SNAP_CREATE;
439   ASSERT_EQ(expected_notify_ops, m_notifies);
440 }
441
442 TEST_F(TestImageWatcher, NotifySnapCreateError) {
443   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
444
445   librbd::ImageCtx *ictx;
446   ASSERT_EQ(0, open_image(m_image_name, &ictx));
447
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())));
451
452   m_notify_acks = {{NOTIFY_OP_SNAP_CREATE, create_response_message(-EEXIST)}};
453
454   RWLock::RLocker l(ictx->owner_lock);
455   C_SaferCond notify_ctx;
456   ictx->image_watcher->notify_snap_create(cls::rbd::UserSnapshotNamespace(),
457        "snap", &notify_ctx);
458   ASSERT_EQ(-EEXIST, notify_ctx.wait());
459
460   NotifyOps expected_notify_ops;
461   expected_notify_ops += NOTIFY_OP_SNAP_CREATE;
462   ASSERT_EQ(expected_notify_ops, m_notifies);
463 }
464
465 TEST_F(TestImageWatcher, NotifySnapRename) {
466   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
467
468   librbd::ImageCtx *ictx;
469   ASSERT_EQ(0, open_image(m_image_name, &ictx));
470
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())));
474
475   m_notify_acks = {{NOTIFY_OP_SNAP_RENAME, create_response_message(0)}};
476
477   RWLock::RLocker l(ictx->owner_lock);
478   C_SaferCond notify_ctx;
479   ictx->image_watcher->notify_snap_rename(1, "snap-rename", &notify_ctx);
480   ASSERT_EQ(0, notify_ctx.wait());
481
482   NotifyOps expected_notify_ops;
483   expected_notify_ops += NOTIFY_OP_SNAP_RENAME;
484   ASSERT_EQ(expected_notify_ops, m_notifies);
485 }
486
487 TEST_F(TestImageWatcher, NotifySnapRenameError) {
488   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
489
490   librbd::ImageCtx *ictx;
491   ASSERT_EQ(0, open_image(m_image_name, &ictx));
492
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())));
496
497   m_notify_acks = {{NOTIFY_OP_SNAP_RENAME, create_response_message(-EEXIST)}};
498
499   RWLock::RLocker l(ictx->owner_lock);
500   C_SaferCond notify_ctx;
501   ictx->image_watcher->notify_snap_rename(1, "snap-rename", &notify_ctx);
502   ASSERT_EQ(-EEXIST, notify_ctx.wait());
503
504   NotifyOps expected_notify_ops;
505   expected_notify_ops += NOTIFY_OP_SNAP_RENAME;
506   ASSERT_EQ(expected_notify_ops, m_notifies);
507 }
508
509 TEST_F(TestImageWatcher, NotifySnapRemove) {
510   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
511
512   librbd::ImageCtx *ictx;
513   ASSERT_EQ(0, open_image(m_image_name, &ictx));
514
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())));
518
519   m_notify_acks = {{NOTIFY_OP_SNAP_REMOVE, create_response_message(0)}};
520
521   RWLock::RLocker l(ictx->owner_lock);
522   C_SaferCond notify_ctx;
523   ictx->image_watcher->notify_snap_remove(cls::rbd::UserSnapshotNamespace(),
524                                           "snap",
525                                           &notify_ctx);
526   ASSERT_EQ(0, notify_ctx.wait());
527
528   NotifyOps expected_notify_ops;
529   expected_notify_ops += NOTIFY_OP_SNAP_REMOVE;
530   ASSERT_EQ(expected_notify_ops, m_notifies);
531 }
532
533 TEST_F(TestImageWatcher, NotifySnapProtect) {
534   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
535
536   librbd::ImageCtx *ictx;
537   ASSERT_EQ(0, open_image(m_image_name, &ictx));
538
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())));
542
543   m_notify_acks = {{NOTIFY_OP_SNAP_PROTECT, create_response_message(0)}};
544
545   RWLock::RLocker l(ictx->owner_lock);
546   C_SaferCond notify_ctx;
547   ictx->image_watcher->notify_snap_protect(cls::rbd::UserSnapshotNamespace(),
548                                            "snap",
549                                            &notify_ctx);
550   ASSERT_EQ(0, notify_ctx.wait());
551
552   NotifyOps expected_notify_ops;
553   expected_notify_ops += NOTIFY_OP_SNAP_PROTECT;
554   ASSERT_EQ(expected_notify_ops, m_notifies);
555 }
556
557 TEST_F(TestImageWatcher, NotifySnapUnprotect) {
558   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
559
560   librbd::ImageCtx *ictx;
561   ASSERT_EQ(0, open_image(m_image_name, &ictx));
562
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())));
566
567   m_notify_acks = {{NOTIFY_OP_SNAP_UNPROTECT, create_response_message(0)}};
568
569   RWLock::RLocker l(ictx->owner_lock);
570   C_SaferCond notify_ctx;
571   ictx->image_watcher->notify_snap_unprotect(cls::rbd::UserSnapshotNamespace(),
572                                              "snap",
573                                              &notify_ctx);
574   ASSERT_EQ(0, notify_ctx.wait());
575
576   NotifyOps expected_notify_ops;
577   expected_notify_ops += NOTIFY_OP_SNAP_UNPROTECT;
578   ASSERT_EQ(expected_notify_ops, m_notifies);
579 }
580
581 TEST_F(TestImageWatcher, NotifyRename) {
582   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
583
584   librbd::ImageCtx *ictx;
585   ASSERT_EQ(0, open_image(m_image_name, &ictx));
586
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())));
590
591   m_notify_acks = {{NOTIFY_OP_RENAME, create_response_message(0)}};
592
593   RWLock::RLocker l(ictx->owner_lock);
594   C_SaferCond notify_ctx;
595   ictx->image_watcher->notify_rename("new_name", &notify_ctx);
596   ASSERT_EQ(0, notify_ctx.wait());
597
598   NotifyOps expected_notify_ops;
599   expected_notify_ops += NOTIFY_OP_RENAME;
600   ASSERT_EQ(expected_notify_ops, m_notifies);
601 }
602
603 TEST_F(TestImageWatcher, NotifyAsyncTimedOut) {
604   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
605
606   librbd::ImageCtx *ictx;
607   ASSERT_EQ(0, open_image(m_image_name, &ictx));
608
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())));
612
613   m_notify_acks = {{NOTIFY_OP_FLATTEN, {}}};
614
615   ProgressContext progress_context;
616   FlattenTask flatten_task(ictx, &progress_context);
617   boost::thread thread(boost::ref(flatten_task));
618
619   ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10)));
620   ASSERT_EQ(-ETIMEDOUT, flatten_task.result);
621 }
622
623 TEST_F(TestImageWatcher, NotifyAsyncError) {
624   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
625
626   librbd::ImageCtx *ictx;
627   ASSERT_EQ(0, open_image(m_image_name, &ictx));
628
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())));
632
633   m_notify_acks = {{NOTIFY_OP_FLATTEN, create_response_message(-EIO)}};
634
635   ProgressContext progress_context;
636   FlattenTask flatten_task(ictx, &progress_context);
637   boost::thread thread(boost::ref(flatten_task));
638
639   ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10)));
640   ASSERT_EQ(-EIO, flatten_task.result);
641 }
642
643 TEST_F(TestImageWatcher, NotifyAsyncCompleteError) {
644   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
645
646   librbd::ImageCtx *ictx;
647   ASSERT_EQ(0, open_image(m_image_name, &ictx));
648
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())));
652
653   m_notify_acks = {{NOTIFY_OP_FLATTEN, create_response_message(0)}};
654
655   ProgressContext progress_context;
656   FlattenTask flatten_task(ictx, &progress_context);
657   boost::thread thread(boost::ref(flatten_task));
658
659   ASSERT_TRUE(wait_for_notifies(*ictx));
660
661   NotifyOps expected_notify_ops;
662   expected_notify_ops += NOTIFY_OP_FLATTEN;
663   ASSERT_EQ(expected_notify_ops, m_notifies);
664
665   AsyncRequestId async_request_id;
666   ASSERT_TRUE(extract_async_request_id(NOTIFY_OP_FLATTEN, &async_request_id));
667
668   ASSERT_EQ(0, notify_async_complete(ictx, async_request_id, -ESHUTDOWN));
669
670   ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10)));
671   ASSERT_EQ(-ESHUTDOWN, flatten_task.result);
672 }
673
674 TEST_F(TestImageWatcher, NotifyAsyncRequestTimedOut) {
675   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
676
677   librbd::ImageCtx *ictx;
678   ASSERT_EQ(0, open_image(m_image_name, &ictx));
679
680   ictx->request_timed_out_seconds = 0;
681
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())));
685
686   m_notify_acks = {{NOTIFY_OP_FLATTEN, create_response_message(0)}};
687
688   ProgressContext progress_context;
689   FlattenTask flatten_task(ictx, &progress_context);
690   boost::thread thread(boost::ref(flatten_task));
691
692   ASSERT_TRUE(wait_for_notifies(*ictx));
693
694   ASSERT_TRUE(thread.timed_join(boost::posix_time::seconds(10)));
695   ASSERT_EQ(-ETIMEDOUT, flatten_task.result);
696 }
697