class TestImage(object): def setUp(self): self.rbd = RBD() create_image() self.image = Image(ioctx, image_name) def tearDown(self): self.image.close() remove_image() @require_new_format() @blacklist_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_update_features(self): features = self.image.features() self.image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, True) eq(features | RBD_FEATURE_EXCLUSIVE_LOCK, self.image.features()) @require_features([RBD_FEATURE_STRIPINGV2]) def test_create_with_params(self): global features image_name = get_temp_image_name() order = 20 stripe_unit = 1 << 20 stripe_count = 10 self.rbd.create(ioctx, image_name, IMG_SIZE, order, False, features, stripe_unit, stripe_count) image = Image(ioctx, image_name) info = image.stat() check_stat(info, IMG_SIZE, order) eq(image.features(), features) eq(image.stripe_unit(), stripe_unit) eq(image.stripe_count(), stripe_count) image.close() RBD().remove(ioctx, image_name) def test_invalidate_cache(self): self.image.write(b'abc', 0) eq(b'abc', self.image.read(0, 3)) self.image.invalidate_cache() eq(b'abc', self.image.read(0, 3)) def test_stat(self): info = self.image.stat() check_stat(info, IMG_SIZE, IMG_ORDER) def test_flags(self): flags = self.image.flags() eq(0, flags) def test_write(self): data = rand_data(256) self.image.write(data, 0) def test_write_with_fadvise_flags(self): data = rand_data(256) self.image.write(data, 0, LIBRADOS_OP_FLAG_FADVISE_DONTNEED) self.image.write(data, 0, LIBRADOS_OP_FLAG_FADVISE_NOCACHE) def test_read(self): data = self.image.read(0, 20) eq(data, b'\0' * 20) def test_read_with_fadvise_flags(self): data = self.image.read(0, 20, LIBRADOS_OP_FLAG_FADVISE_DONTNEED) eq(data, b'\0' * 20) data = self.image.read(0, 20, LIBRADOS_OP_FLAG_FADVISE_RANDOM) eq(data, b'\0' * 20) def test_large_write(self): data = rand_data(IMG_SIZE) self.image.write(data, 0) def test_large_read(self): data = self.image.read(0, IMG_SIZE) eq(data, b'\0' * IMG_SIZE) def test_write_read(self): data = rand_data(256) offset = 50 self.image.write(data, offset) read = self.image.read(offset, 256) eq(data, read) def test_read_bad_offset(self): assert_raises(InvalidArgument, self.image.read, IMG_SIZE + 1, IMG_SIZE) def test_resize(self): new_size = IMG_SIZE * 2 self.image.resize(new_size) info = self.image.stat() check_stat(info, new_size, IMG_ORDER) def test_size(self): eq(IMG_SIZE, self.image.size()) self.image.create_snap('snap1') new_size = IMG_SIZE * 2 self.image.resize(new_size) eq(new_size, self.image.size()) self.image.create_snap('snap2') self.image.set_snap('snap2') eq(new_size, self.image.size()) self.image.set_snap('snap1') eq(IMG_SIZE, self.image.size()) self.image.set_snap(None) eq(new_size, self.image.size()) self.image.remove_snap('snap1') self.image.remove_snap('snap2') def test_resize_down(self): new_size = IMG_SIZE // 2 data = rand_data(256) self.image.write(data, IMG_SIZE // 2) self.image.resize(new_size) self.image.resize(IMG_SIZE) read = self.image.read(IMG_SIZE // 2, 256) eq(b'\0' * 256, read) def test_resize_bytes(self): new_size = IMG_SIZE // 2 - 5 data = rand_data(256) self.image.write(data, IMG_SIZE // 2 - 10) self.image.resize(new_size) self.image.resize(IMG_SIZE) read = self.image.read(IMG_SIZE // 2 - 10, 5) eq(data[:5], read) read = self.image.read(IMG_SIZE // 2 - 5, 251) eq(b'\0' * 251, read) def _test_copy(self, features=None, order=None, stripe_unit=None, stripe_count=None): global ioctx data = rand_data(256) self.image.write(data, 256) image_name = get_temp_image_name() if features is None: self.image.copy(ioctx, image_name) elif order is None: self.image.copy(ioctx, image_name, features) elif stripe_unit is None: self.image.copy(ioctx, image_name, features, order) elif stripe_count is None: self.image.copy(ioctx, image_name, features, order, stripe_unit) else: self.image.copy(ioctx, image_name, features, order, stripe_unit, stripe_count) assert_raises(ImageExists, self.image.copy, ioctx, image_name) copy = Image(ioctx, image_name) copy_data = copy.read(256, 256) copy.close() self.rbd.remove(ioctx, image_name) eq(data, copy_data) def test_copy(self): self._test_copy() def test_copy2(self): self._test_copy(self.image.features(), self.image.stat()['order']) @require_features([RBD_FEATURE_STRIPINGV2]) def test_copy3(self): global features self._test_copy(features, self.image.stat()['order'], self.image.stripe_unit(), self.image.stripe_count()) def test_create_snap(self): global ioctx self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) at_snapshot = Image(ioctx, image_name, 'snap1') snap_data = at_snapshot.read(0, 256) at_snapshot.close() eq(snap_data, b'\0' * 256) self.image.remove_snap('snap1') def test_list_snaps(self): eq([], list(self.image.list_snaps())) self.image.create_snap('snap1') eq(['snap1'], [snap['name'] for snap in self.image.list_snaps()]) self.image.create_snap('snap2') eq(['snap1', 'snap2'], [snap['name'] for snap in self.image.list_snaps()]) self.image.remove_snap('snap1') self.image.remove_snap('snap2') def test_remove_snap(self): eq([], list(self.image.list_snaps())) self.image.create_snap('snap1') eq(['snap1'], [snap['name'] for snap in self.image.list_snaps()]) self.image.remove_snap('snap1') eq([], list(self.image.list_snaps())) def test_rename_snap(self): eq([], list(self.image.list_snaps())) self.image.create_snap('snap1') eq(['snap1'], [snap['name'] for snap in self.image.list_snaps()]) self.image.rename_snap("snap1", "snap1-rename") eq(['snap1-rename'], [snap['name'] for snap in self.image.list_snaps()]) self.image.remove_snap('snap1-rename') eq([], list(self.image.list_snaps())) @require_features([RBD_FEATURE_LAYERING]) def test_protect_snap(self): self.image.create_snap('snap1') assert (not self.image.is_protected_snap('snap1')) self.image.protect_snap('snap1') assert (self.image.is_protected_snap('snap1')) assert_raises(ImageBusy, self.image.remove_snap, 'snap1') self.image.unprotect_snap('snap1') assert (not self.image.is_protected_snap('snap1')) self.image.remove_snap('snap1') assert_raises(ImageNotFound, self.image.unprotect_snap, 'snap1') assert_raises(ImageNotFound, self.image.is_protected_snap, 'snap1') @require_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_remove_with_exclusive_lock(self): assert_raises(ImageBusy, remove_image) @blacklist_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_remove_with_snap(self): self.image.create_snap('snap1') assert_raises(ImageHasSnapshots, remove_image) self.image.remove_snap('snap1') @blacklist_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_remove_with_watcher(self): data = rand_data(256) self.image.write(data, 0) assert_raises(ImageBusy, remove_image) read = self.image.read(0, 256) eq(read, data) def test_rollback_to_snap(self): self.image.write(b'\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.rollback_to_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) self.image.remove_snap('snap1') def test_rollback_to_snap_sparse(self): self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.rollback_to_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) self.image.remove_snap('snap1') def test_rollback_with_resize(self): read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, data) new_size = IMG_SIZE * 2 self.image.resize(new_size) check_stat(self.image.stat(), new_size, IMG_ORDER) self.image.write(data, new_size - 256) self.image.create_snap('snap2') read = self.image.read(new_size - 256, 256) eq(read, data) self.image.rollback_to_snap('snap1') check_stat(self.image.stat(), IMG_SIZE, IMG_ORDER) assert_raises(InvalidArgument, self.image.read, new_size - 256, 256) self.image.rollback_to_snap('snap2') check_stat(self.image.stat(), new_size, IMG_ORDER) read = self.image.read(new_size - 256, 256) eq(read, data) self.image.remove_snap('snap1') self.image.remove_snap('snap2') def test_set_snap(self): self.image.write(b'\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) self.image.remove_snap('snap1') def test_set_no_snap(self): self.image.write(b'\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) self.image.set_snap(None) read = self.image.read(0, 256) eq(read, data) self.image.remove_snap('snap1') def test_set_snap_sparse(self): self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) self.image.remove_snap('snap1') def test_many_snaps(self): num_snaps = 200 for i in range(num_snaps): self.image.create_snap(str(i)) snaps = sorted(self.image.list_snaps(), key=lambda snap: int(snap['name'])) eq(len(snaps), num_snaps) for i, snap in enumerate(snaps): eq(snap['size'], IMG_SIZE) eq(snap['name'], str(i)) for i in range(num_snaps): self.image.remove_snap(str(i)) def test_set_snap_deleted(self): self.image.write(b'\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') self.image.remove_snap('snap1') assert_raises(ImageNotFound, self.image.read, 0, 256) self.image.set_snap(None) read = self.image.read(0, 256) eq(read, data) def test_set_snap_recreated(self): self.image.write(b'\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') self.image.remove_snap('snap1') self.image.create_snap('snap1') assert_raises(ImageNotFound, self.image.read, 0, 256) self.image.set_snap(None) read = self.image.read(0, 256) eq(read, data) self.image.remove_snap('snap1') def test_lock_unlock(self): assert_raises(ImageNotFound, self.image.unlock, '') self.image.lock_exclusive('') assert_raises(ImageExists, self.image.lock_exclusive, '') assert_raises(ImageBusy, self.image.lock_exclusive, 'test') assert_raises(ImageExists, self.image.lock_shared, '', '') assert_raises(ImageBusy, self.image.lock_shared, 'foo', '') self.image.unlock('') def test_list_lockers(self): eq([], self.image.list_lockers()) self.image.lock_exclusive('test') lockers = self.image.list_lockers() eq(1, len(lockers['lockers'])) _, cookie, _ = lockers['lockers'][0] eq(cookie, 'test') eq('', lockers['tag']) assert lockers['exclusive'] self.image.unlock('test') eq([], self.image.list_lockers()) num_shared = 10 for i in range(num_shared): self.image.lock_shared(str(i), 'tag') lockers = self.image.list_lockers() eq('tag', lockers['tag']) assert not lockers['exclusive'] eq(num_shared, len(lockers['lockers'])) cookies = sorted(map(lambda x: x[1], lockers['lockers'])) for i in range(num_shared): eq(str(i), cookies[i]) self.image.unlock(str(i)) eq([], self.image.list_lockers()) def test_diff_iterate(self): check_diff(self.image, 0, IMG_SIZE, None, []) self.image.write(b'a' * 256, 0) check_diff(self.image, 0, IMG_SIZE, None, [(0, 256, True)]) self.image.write(b'b' * 256, 256) check_diff(self.image, 0, IMG_SIZE, None, [(0, 512, True)]) self.image.discard(128, 256) check_diff(self.image, 0, IMG_SIZE, None, [(0, 512, True)]) self.image.create_snap('snap1') self.image.discard(0, 1 << IMG_ORDER) self.image.create_snap('snap2') self.image.set_snap('snap2') check_diff(self.image, 0, IMG_SIZE, 'snap1', [(0, 512, False)]) self.image.remove_snap('snap1') self.image.remove_snap('snap2')
class TestImage(object): def setUp(self): self.rbd = RBD() create_image() self.image = Image(ioctx, image_name) def tearDown(self): self.image.close() remove_image() @require_new_format() @blacklist_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_update_features(self): features = self.image.features() self.image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, True) eq(features | RBD_FEATURE_EXCLUSIVE_LOCK, self.image.features()) def test_invalidate_cache(self): self.image.write('abc', 0) eq('abc', self.image.read(0, 3)) self.image.invalidate_cache() eq('abc', self.image.read(0, 3)) def test_stat(self): info = self.image.stat() check_stat(info, IMG_SIZE, IMG_ORDER) def test_flags(self): flags = self.image.flags() eq(0, flags) def test_write(self): data = rand_data(256) self.image.write(data, 0) def test_write_with_fadvise_flags(self): data = rand_data(256) self.image.write(data, 0, LIBRADOS_OP_FLAG_FADVISE_DONTNEED) self.image.write(data, 0, LIBRADOS_OP_FLAG_FADVISE_NOCACHE) def test_read(self): data = self.image.read(0, 20) eq(data, '\0' * 20) def test_read_with_fadvise_flags(self): data = self.image.read(0, 20, LIBRADOS_OP_FLAG_FADVISE_DONTNEED) eq(data, '\0' * 20) data = self.image.read(0, 20, LIBRADOS_OP_FLAG_FADVISE_RANDOM) eq(data, '\0' * 20) def test_large_write(self): data = rand_data(IMG_SIZE) self.image.write(data, 0) def test_large_read(self): data = self.image.read(0, IMG_SIZE) eq(data, '\0' * IMG_SIZE) def test_write_read(self): data = rand_data(256) offset = 50 self.image.write(data, offset) read = self.image.read(offset, 256) eq(data, read) def test_read_bad_offset(self): assert_raises(InvalidArgument, self.image.read, IMG_SIZE + 1, IMG_SIZE) def test_resize(self): new_size = IMG_SIZE * 2 self.image.resize(new_size) info = self.image.stat() check_stat(info, new_size, IMG_ORDER) def test_size(self): eq(IMG_SIZE, self.image.size()) self.image.create_snap('snap1') new_size = IMG_SIZE * 2 self.image.resize(new_size) eq(new_size, self.image.size()) self.image.create_snap('snap2') self.image.set_snap('snap2') eq(new_size, self.image.size()) self.image.set_snap('snap1') eq(IMG_SIZE, self.image.size()) self.image.set_snap(None) eq(new_size, self.image.size()) self.image.remove_snap('snap1') self.image.remove_snap('snap2') def test_resize_down(self): new_size = IMG_SIZE / 2 data = rand_data(256) self.image.write(data, IMG_SIZE / 2); self.image.resize(new_size) self.image.resize(IMG_SIZE) read = self.image.read(IMG_SIZE / 2, 256) eq('\0' * 256, read) def test_resize_bytes(self): new_size = IMG_SIZE / 2 - 5 data = rand_data(256) self.image.write(data, IMG_SIZE / 2 - 10); self.image.resize(new_size) self.image.resize(IMG_SIZE) read = self.image.read(IMG_SIZE / 2 - 10, 5) eq(data[:5], read) read = self.image.read(IMG_SIZE / 2 - 5, 251) eq('\0' * 251, read) def test_copy(self): global ioctx data = rand_data(256) self.image.write(data, 256) image_name = get_temp_image_name() self.image.copy(ioctx, image_name) assert_raises(ImageExists, self.image.copy, ioctx, image_name) copy = Image(ioctx, image_name) copy_data = copy.read(256, 256) copy.close() self.rbd.remove(ioctx, image_name) eq(data, copy_data) def test_create_snap(self): global ioctx self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) at_snapshot = Image(ioctx, image_name, 'snap1') snap_data = at_snapshot.read(0, 256) at_snapshot.close() eq(snap_data, '\0' * 256) self.image.remove_snap('snap1') def test_list_snaps(self): eq([], list(self.image.list_snaps())) self.image.create_snap('snap1') eq(['snap1'], map(lambda snap: snap['name'], self.image.list_snaps())) self.image.create_snap('snap2') eq(['snap1', 'snap2'], map(lambda snap: snap['name'], self.image.list_snaps())) self.image.remove_snap('snap1') self.image.remove_snap('snap2') def test_remove_snap(self): eq([], list(self.image.list_snaps())) self.image.create_snap('snap1') eq(['snap1'], map(lambda snap: snap['name'], self.image.list_snaps())) self.image.remove_snap('snap1') eq([], list(self.image.list_snaps())) def test_rename_snap(self): eq([], list(self.image.list_snaps())) self.image.create_snap('snap1') eq(['snap1'], map(lambda snap: snap['name'], self.image.list_snaps())) self.image.rename_snap("snap1", "snap1-rename") eq(['snap1-rename'], map(lambda snap: snap['name'], self.image.list_snaps())) self.image.remove_snap('snap1-rename') eq([], list(self.image.list_snaps())) @require_features([RBD_FEATURE_LAYERING]) def test_protect_snap(self): self.image.create_snap('snap1') assert(not self.image.is_protected_snap('snap1')) self.image.protect_snap('snap1') assert(self.image.is_protected_snap('snap1')) assert_raises(ImageBusy, self.image.remove_snap, 'snap1') self.image.unprotect_snap('snap1') assert(not self.image.is_protected_snap('snap1')) self.image.remove_snap('snap1') assert_raises(ImageNotFound, self.image.unprotect_snap, 'snap1') assert_raises(ImageNotFound, self.image.is_protected_snap, 'snap1') @require_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_remove_with_exclusive_lock(self): assert_raises(ImageBusy, remove_image) @blacklist_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_remove_with_snap(self): self.image.create_snap('snap1') assert_raises(ImageHasSnapshots, remove_image) self.image.remove_snap('snap1') @blacklist_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_remove_with_watcher(self): data = rand_data(256) self.image.write(data, 0) assert_raises(ImageBusy, remove_image) read = self.image.read(0, 256) eq(read, data) def test_rollback_to_snap(self): self.image.write('\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.rollback_to_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) self.image.remove_snap('snap1') def test_rollback_to_snap_sparse(self): self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.rollback_to_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) self.image.remove_snap('snap1') def test_rollback_with_resize(self): read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, data) new_size = IMG_SIZE * 2 self.image.resize(new_size) check_stat(self.image.stat(), new_size, IMG_ORDER) self.image.write(data, new_size - 256) self.image.create_snap('snap2') read = self.image.read(new_size - 256, 256) eq(read, data) self.image.rollback_to_snap('snap1') check_stat(self.image.stat(), IMG_SIZE, IMG_ORDER) assert_raises(InvalidArgument, self.image.read, new_size - 256, 256) self.image.rollback_to_snap('snap2') check_stat(self.image.stat(), new_size, IMG_ORDER) read = self.image.read(new_size - 256, 256) eq(read, data) self.image.remove_snap('snap1') self.image.remove_snap('snap2') def test_set_snap(self): self.image.write('\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) self.image.remove_snap('snap1') def test_set_no_snap(self): self.image.write('\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) self.image.set_snap(None) read = self.image.read(0, 256) eq(read, data) self.image.remove_snap('snap1') def test_set_snap_sparse(self): self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) self.image.remove_snap('snap1') def test_many_snaps(self): num_snaps = 200 for i in xrange(num_snaps): self.image.create_snap(str(i)) snaps = sorted(self.image.list_snaps(), key=lambda snap: int(snap['name'])) eq(len(snaps), num_snaps) for i, snap in enumerate(snaps): eq(snap['size'], IMG_SIZE) eq(snap['name'], str(i)) for i in xrange(num_snaps): self.image.remove_snap(str(i)) def test_set_snap_deleted(self): self.image.write('\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') self.image.remove_snap('snap1') assert_raises(ImageNotFound, self.image.read, 0, 256) self.image.set_snap(None) read = self.image.read(0, 256) eq(read, data) def test_set_snap_recreated(self): self.image.write('\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') self.image.remove_snap('snap1') self.image.create_snap('snap1') assert_raises(ImageNotFound, self.image.read, 0, 256) self.image.set_snap(None) read = self.image.read(0, 256) eq(read, data) self.image.remove_snap('snap1') def test_lock_unlock(self): assert_raises(ImageNotFound, self.image.unlock, '') self.image.lock_exclusive('') assert_raises(ImageExists, self.image.lock_exclusive, '') assert_raises(ImageBusy, self.image.lock_exclusive, 'test') assert_raises(ImageExists, self.image.lock_shared, '', '') assert_raises(ImageBusy, self.image.lock_shared, 'foo', '') self.image.unlock('') def test_list_lockers(self): eq([], self.image.list_lockers()) self.image.lock_exclusive('test') lockers = self.image.list_lockers() eq(1, len(lockers['lockers'])) _, cookie, _ = lockers['lockers'][0] eq(cookie, 'test') eq('', lockers['tag']) assert lockers['exclusive'] self.image.unlock('test') eq([], self.image.list_lockers()) num_shared = 10 for i in xrange(num_shared): self.image.lock_shared(str(i), 'tag') lockers = self.image.list_lockers() eq('tag', lockers['tag']) assert not lockers['exclusive'] eq(num_shared, len(lockers['lockers'])) cookies = sorted(map(lambda x: x[1], lockers['lockers'])) for i in xrange(num_shared): eq(str(i), cookies[i]) self.image.unlock(str(i)) eq([], self.image.list_lockers()) def test_diff_iterate(self): check_diff(self.image, 0, IMG_SIZE, None, []) self.image.write('a' * 256, 0) check_diff(self.image, 0, IMG_SIZE, None, [(0, 256, True)]) self.image.write('b' * 256, 256) check_diff(self.image, 0, IMG_SIZE, None, [(0, 512, True)]) self.image.discard(128, 256) check_diff(self.image, 0, IMG_SIZE, None, [(0, 512, True)]) self.image.create_snap('snap1') self.image.discard(0, 1 << IMG_ORDER) self.image.create_snap('snap2') self.image.set_snap('snap2') check_diff(self.image, 0, IMG_SIZE, 'snap1', [(0, 512, False)]) self.image.remove_snap('snap1') self.image.remove_snap('snap2')
class TestImage(object): def setUp(self): self.rbd = RBD() create_image() self.image = Image(ioctx, image_name) def tearDown(self): self.image.close() remove_image() @require_new_format() @blacklist_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_update_features(self): features = self.image.features() self.image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, True) eq(features | RBD_FEATURE_EXCLUSIVE_LOCK, self.image.features()) @require_features([RBD_FEATURE_STRIPINGV2]) def test_create_with_params(self): global features image_name = get_temp_image_name() order = 20 stripe_unit = 1 << 20 stripe_count = 10 self.rbd.create(ioctx, image_name, IMG_SIZE, order, False, features, stripe_unit, stripe_count) image = Image(ioctx, image_name) info = image.stat() check_stat(info, IMG_SIZE, order) eq(image.features(), features) eq(image.stripe_unit(), stripe_unit) eq(image.stripe_count(), stripe_count) image.close() RBD().remove(ioctx, image_name) def test_invalidate_cache(self): self.image.write(b"abc", 0) eq(b"abc", self.image.read(0, 3)) self.image.invalidate_cache() eq(b"abc", self.image.read(0, 3)) def test_stat(self): info = self.image.stat() check_stat(info, IMG_SIZE, IMG_ORDER) def test_flags(self): flags = self.image.flags() eq(0, flags) def test_image_auto_close(self): image = Image(ioctx, image_name) def test_write(self): data = rand_data(256) self.image.write(data, 0) def test_write_with_fadvise_flags(self): data = rand_data(256) self.image.write(data, 0, LIBRADOS_OP_FLAG_FADVISE_DONTNEED) self.image.write(data, 0, LIBRADOS_OP_FLAG_FADVISE_NOCACHE) def test_read(self): data = self.image.read(0, 20) eq(data, b"\0" * 20) def test_read_with_fadvise_flags(self): data = self.image.read(0, 20, LIBRADOS_OP_FLAG_FADVISE_DONTNEED) eq(data, b"\0" * 20) data = self.image.read(0, 20, LIBRADOS_OP_FLAG_FADVISE_RANDOM) eq(data, b"\0" * 20) def test_large_write(self): data = rand_data(IMG_SIZE) self.image.write(data, 0) def test_large_read(self): data = self.image.read(0, IMG_SIZE) eq(data, b"\0" * IMG_SIZE) def test_write_read(self): data = rand_data(256) offset = 50 self.image.write(data, offset) read = self.image.read(offset, 256) eq(data, read) def test_read_bad_offset(self): assert_raises(InvalidArgument, self.image.read, IMG_SIZE + 1, IMG_SIZE) def test_resize(self): new_size = IMG_SIZE * 2 self.image.resize(new_size) info = self.image.stat() check_stat(info, new_size, IMG_ORDER) def test_size(self): eq(IMG_SIZE, self.image.size()) self.image.create_snap("snap1") new_size = IMG_SIZE * 2 self.image.resize(new_size) eq(new_size, self.image.size()) self.image.create_snap("snap2") self.image.set_snap("snap2") eq(new_size, self.image.size()) self.image.set_snap("snap1") eq(IMG_SIZE, self.image.size()) self.image.set_snap(None) eq(new_size, self.image.size()) self.image.remove_snap("snap1") self.image.remove_snap("snap2") def test_resize_down(self): new_size = IMG_SIZE // 2 data = rand_data(256) self.image.write(data, IMG_SIZE // 2) self.image.resize(new_size) self.image.resize(IMG_SIZE) read = self.image.read(IMG_SIZE // 2, 256) eq(b"\0" * 256, read) def test_resize_bytes(self): new_size = IMG_SIZE // 2 - 5 data = rand_data(256) self.image.write(data, IMG_SIZE // 2 - 10) self.image.resize(new_size) self.image.resize(IMG_SIZE) read = self.image.read(IMG_SIZE // 2 - 10, 5) eq(data[:5], read) read = self.image.read(IMG_SIZE // 2 - 5, 251) eq(b"\0" * 251, read) def _test_copy(self, features=None, order=None, stripe_unit=None, stripe_count=None): global ioctx data = rand_data(256) self.image.write(data, 256) image_name = get_temp_image_name() if features is None: self.image.copy(ioctx, image_name) elif order is None: self.image.copy(ioctx, image_name, features) elif stripe_unit is None: self.image.copy(ioctx, image_name, features, order) elif stripe_count is None: self.image.copy(ioctx, image_name, features, order, stripe_unit) else: self.image.copy(ioctx, image_name, features, order, stripe_unit, stripe_count) assert_raises(ImageExists, self.image.copy, ioctx, image_name) copy = Image(ioctx, image_name) copy_data = copy.read(256, 256) copy.close() self.rbd.remove(ioctx, image_name) eq(data, copy_data) def test_copy(self): self._test_copy() def test_copy2(self): self._test_copy(self.image.features(), self.image.stat()["order"]) @require_features([RBD_FEATURE_STRIPINGV2]) def test_copy3(self): global features self._test_copy(features, self.image.stat()["order"], self.image.stripe_unit(), self.image.stripe_count()) def test_create_snap(self): global ioctx self.image.create_snap("snap1") read = self.image.read(0, 256) eq(read, b"\0" * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) at_snapshot = Image(ioctx, image_name, "snap1") snap_data = at_snapshot.read(0, 256) at_snapshot.close() eq(snap_data, b"\0" * 256) self.image.remove_snap("snap1") def test_list_snaps(self): eq([], list(self.image.list_snaps())) self.image.create_snap("snap1") eq(["snap1"], [snap["name"] for snap in self.image.list_snaps()]) self.image.create_snap("snap2") eq(["snap1", "snap2"], [snap["name"] for snap in self.image.list_snaps()]) self.image.remove_snap("snap1") self.image.remove_snap("snap2") def test_list_snaps_iterator_auto_close(self): self.image.create_snap("snap1") self.image.list_snaps() self.image.remove_snap("snap1") def test_remove_snap(self): eq([], list(self.image.list_snaps())) self.image.create_snap("snap1") eq(["snap1"], [snap["name"] for snap in self.image.list_snaps()]) self.image.remove_snap("snap1") eq([], list(self.image.list_snaps())) def test_rename_snap(self): eq([], list(self.image.list_snaps())) self.image.create_snap("snap1") eq(["snap1"], [snap["name"] for snap in self.image.list_snaps()]) self.image.rename_snap("snap1", "snap1-rename") eq(["snap1-rename"], [snap["name"] for snap in self.image.list_snaps()]) self.image.remove_snap("snap1-rename") eq([], list(self.image.list_snaps())) @require_features([RBD_FEATURE_LAYERING]) def test_protect_snap(self): self.image.create_snap("snap1") assert not self.image.is_protected_snap("snap1") self.image.protect_snap("snap1") assert self.image.is_protected_snap("snap1") assert_raises(ImageBusy, self.image.remove_snap, "snap1") self.image.unprotect_snap("snap1") assert not self.image.is_protected_snap("snap1") self.image.remove_snap("snap1") assert_raises(ImageNotFound, self.image.unprotect_snap, "snap1") assert_raises(ImageNotFound, self.image.is_protected_snap, "snap1") @require_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_remove_with_exclusive_lock(self): assert_raises(ImageBusy, remove_image) @blacklist_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_remove_with_snap(self): self.image.create_snap("snap1") assert_raises(ImageHasSnapshots, remove_image) self.image.remove_snap("snap1") @blacklist_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_remove_with_watcher(self): data = rand_data(256) self.image.write(data, 0) assert_raises(ImageBusy, remove_image) read = self.image.read(0, 256) eq(read, data) def test_rollback_to_snap(self): self.image.write(b"\0" * 256, 0) self.image.create_snap("snap1") read = self.image.read(0, 256) eq(read, b"\0" * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.rollback_to_snap("snap1") read = self.image.read(0, 256) eq(read, b"\0" * 256) self.image.remove_snap("snap1") def test_rollback_to_snap_sparse(self): self.image.create_snap("snap1") read = self.image.read(0, 256) eq(read, b"\0" * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.rollback_to_snap("snap1") read = self.image.read(0, 256) eq(read, b"\0" * 256) self.image.remove_snap("snap1") def test_rollback_with_resize(self): read = self.image.read(0, 256) eq(read, b"\0" * 256) data = rand_data(256) self.image.write(data, 0) self.image.create_snap("snap1") read = self.image.read(0, 256) eq(read, data) new_size = IMG_SIZE * 2 self.image.resize(new_size) check_stat(self.image.stat(), new_size, IMG_ORDER) self.image.write(data, new_size - 256) self.image.create_snap("snap2") read = self.image.read(new_size - 256, 256) eq(read, data) self.image.rollback_to_snap("snap1") check_stat(self.image.stat(), IMG_SIZE, IMG_ORDER) assert_raises(InvalidArgument, self.image.read, new_size - 256, 256) self.image.rollback_to_snap("snap2") check_stat(self.image.stat(), new_size, IMG_ORDER) read = self.image.read(new_size - 256, 256) eq(read, data) self.image.remove_snap("snap1") self.image.remove_snap("snap2") def test_set_snap(self): self.image.write(b"\0" * 256, 0) self.image.create_snap("snap1") read = self.image.read(0, 256) eq(read, b"\0" * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap("snap1") read = self.image.read(0, 256) eq(read, b"\0" * 256) self.image.remove_snap("snap1") def test_set_no_snap(self): self.image.write(b"\0" * 256, 0) self.image.create_snap("snap1") read = self.image.read(0, 256) eq(read, b"\0" * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap("snap1") read = self.image.read(0, 256) eq(read, b"\0" * 256) self.image.set_snap(None) read = self.image.read(0, 256) eq(read, data) self.image.remove_snap("snap1") def test_set_snap_sparse(self): self.image.create_snap("snap1") read = self.image.read(0, 256) eq(read, b"\0" * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap("snap1") read = self.image.read(0, 256) eq(read, b"\0" * 256) self.image.remove_snap("snap1") def test_many_snaps(self): num_snaps = 200 for i in range(num_snaps): self.image.create_snap(str(i)) snaps = sorted(self.image.list_snaps(), key=lambda snap: int(snap["name"])) eq(len(snaps), num_snaps) for i, snap in enumerate(snaps): eq(snap["size"], IMG_SIZE) eq(snap["name"], str(i)) for i in range(num_snaps): self.image.remove_snap(str(i)) def test_set_snap_deleted(self): self.image.write(b"\0" * 256, 0) self.image.create_snap("snap1") read = self.image.read(0, 256) eq(read, b"\0" * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap("snap1") self.image.remove_snap("snap1") assert_raises(ImageNotFound, self.image.read, 0, 256) self.image.set_snap(None) read = self.image.read(0, 256) eq(read, data) def test_set_snap_recreated(self): self.image.write(b"\0" * 256, 0) self.image.create_snap("snap1") read = self.image.read(0, 256) eq(read, b"\0" * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap("snap1") self.image.remove_snap("snap1") self.image.create_snap("snap1") assert_raises(ImageNotFound, self.image.read, 0, 256) self.image.set_snap(None) read = self.image.read(0, 256) eq(read, data) self.image.remove_snap("snap1") def test_lock_unlock(self): assert_raises(ImageNotFound, self.image.unlock, "") self.image.lock_exclusive("") assert_raises(ImageExists, self.image.lock_exclusive, "") assert_raises(ImageBusy, self.image.lock_exclusive, "test") assert_raises(ImageExists, self.image.lock_shared, "", "") assert_raises(ImageBusy, self.image.lock_shared, "foo", "") self.image.unlock("") def test_list_lockers(self): eq([], self.image.list_lockers()) self.image.lock_exclusive("test") lockers = self.image.list_lockers() eq(1, len(lockers["lockers"])) _, cookie, _ = lockers["lockers"][0] eq(cookie, "test") eq("", lockers["tag"]) assert lockers["exclusive"] self.image.unlock("test") eq([], self.image.list_lockers()) num_shared = 10 for i in range(num_shared): self.image.lock_shared(str(i), "tag") lockers = self.image.list_lockers() eq("tag", lockers["tag"]) assert not lockers["exclusive"] eq(num_shared, len(lockers["lockers"])) cookies = sorted(map(lambda x: x[1], lockers["lockers"])) for i in range(num_shared): eq(str(i), cookies[i]) self.image.unlock(str(i)) eq([], self.image.list_lockers()) def test_diff_iterate(self): check_diff(self.image, 0, IMG_SIZE, None, []) self.image.write(b"a" * 256, 0) check_diff(self.image, 0, IMG_SIZE, None, [(0, 256, True)]) self.image.write(b"b" * 256, 256) check_diff(self.image, 0, IMG_SIZE, None, [(0, 512, True)]) self.image.discard(128, 256) check_diff(self.image, 0, IMG_SIZE, None, [(0, 512, True)]) self.image.create_snap("snap1") self.image.discard(0, 1 << IMG_ORDER) self.image.create_snap("snap2") self.image.set_snap("snap2") check_diff(self.image, 0, IMG_SIZE, "snap1", [(0, 512, False)]) self.image.remove_snap("snap1") self.image.remove_snap("snap2")
class TestImage(object): def setUp(self): self.rbd = RBD() create_image() self.image = Image(ioctx, image_name) def tearDown(self): self.image.close() remove_image() self.image = None @require_new_format() @blacklist_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_update_features(self): features = self.image.features() self.image.update_features(RBD_FEATURE_EXCLUSIVE_LOCK, True) eq(features | RBD_FEATURE_EXCLUSIVE_LOCK, self.image.features()) @require_features([RBD_FEATURE_STRIPINGV2]) def test_create_with_params(self): global features image_name = get_temp_image_name() order = 20 stripe_unit = 1 << 20 stripe_count = 10 self.rbd.create(ioctx, image_name, IMG_SIZE, order, False, features, stripe_unit, stripe_count) image = Image(ioctx, image_name) info = image.stat() check_stat(info, IMG_SIZE, order) eq(image.features(), features) eq(image.stripe_unit(), stripe_unit) eq(image.stripe_count(), stripe_count) image.close() RBD().remove(ioctx, image_name) @require_new_format() def test_id(self): assert_not_equal(b'', self.image.id()) def test_block_name_prefix(self): assert_not_equal(b'', self.image.block_name_prefix()) def test_invalidate_cache(self): self.image.write(b'abc', 0) eq(b'abc', self.image.read(0, 3)) self.image.invalidate_cache() eq(b'abc', self.image.read(0, 3)) def test_stat(self): info = self.image.stat() check_stat(info, IMG_SIZE, IMG_ORDER) def test_flags(self): flags = self.image.flags() eq(0, flags) def test_image_auto_close(self): image = Image(ioctx, image_name) def test_write(self): data = rand_data(256) self.image.write(data, 0) def test_write_with_fadvise_flags(self): data = rand_data(256) self.image.write(data, 0, LIBRADOS_OP_FLAG_FADVISE_DONTNEED) self.image.write(data, 0, LIBRADOS_OP_FLAG_FADVISE_NOCACHE) def test_read(self): data = self.image.read(0, 20) eq(data, b'\0' * 20) def test_read_with_fadvise_flags(self): data = self.image.read(0, 20, LIBRADOS_OP_FLAG_FADVISE_DONTNEED) eq(data, b'\0' * 20) data = self.image.read(0, 20, LIBRADOS_OP_FLAG_FADVISE_RANDOM) eq(data, b'\0' * 20) def test_large_write(self): data = rand_data(IMG_SIZE) self.image.write(data, 0) def test_large_read(self): data = self.image.read(0, IMG_SIZE) eq(data, b'\0' * IMG_SIZE) def test_write_read(self): data = rand_data(256) offset = 50 self.image.write(data, offset) read = self.image.read(offset, 256) eq(data, read) def test_read_bad_offset(self): assert_raises(InvalidArgument, self.image.read, IMG_SIZE + 1, IMG_SIZE) def test_resize(self): new_size = IMG_SIZE * 2 self.image.resize(new_size) info = self.image.stat() check_stat(info, new_size, IMG_ORDER) def test_size(self): eq(IMG_SIZE, self.image.size()) self.image.create_snap('snap1') new_size = IMG_SIZE * 2 self.image.resize(new_size) eq(new_size, self.image.size()) self.image.create_snap('snap2') self.image.set_snap('snap2') eq(new_size, self.image.size()) self.image.set_snap('snap1') eq(IMG_SIZE, self.image.size()) self.image.set_snap(None) eq(new_size, self.image.size()) self.image.remove_snap('snap1') self.image.remove_snap('snap2') def test_resize_down(self): new_size = IMG_SIZE // 2 data = rand_data(256) self.image.write(data, IMG_SIZE // 2); self.image.resize(new_size) self.image.resize(IMG_SIZE) read = self.image.read(IMG_SIZE // 2, 256) eq(b'\0' * 256, read) def test_resize_bytes(self): new_size = IMG_SIZE // 2 - 5 data = rand_data(256) self.image.write(data, IMG_SIZE // 2 - 10); self.image.resize(new_size) self.image.resize(IMG_SIZE) read = self.image.read(IMG_SIZE // 2 - 10, 5) eq(data[:5], read) read = self.image.read(IMG_SIZE // 2 - 5, 251) eq(b'\0' * 251, read) def _test_copy(self, features=None, order=None, stripe_unit=None, stripe_count=None): global ioctx data = rand_data(256) self.image.write(data, 256) image_name = get_temp_image_name() if features is None: self.image.copy(ioctx, image_name) elif order is None: self.image.copy(ioctx, image_name, features) elif stripe_unit is None: self.image.copy(ioctx, image_name, features, order) elif stripe_count is None: self.image.copy(ioctx, image_name, features, order, stripe_unit) else: self.image.copy(ioctx, image_name, features, order, stripe_unit, stripe_count) assert_raises(ImageExists, self.image.copy, ioctx, image_name) copy = Image(ioctx, image_name) copy_data = copy.read(256, 256) copy.close() self.rbd.remove(ioctx, image_name) eq(data, copy_data) def test_copy(self): self._test_copy() def test_copy2(self): self._test_copy(self.image.features(), self.image.stat()['order']) @require_features([RBD_FEATURE_STRIPINGV2]) def test_copy3(self): global features self._test_copy(features, self.image.stat()['order'], self.image.stripe_unit(), self.image.stripe_count()) def test_create_snap(self): global ioctx self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) at_snapshot = Image(ioctx, image_name, 'snap1') snap_data = at_snapshot.read(0, 256) at_snapshot.close() eq(snap_data, b'\0' * 256) self.image.remove_snap('snap1') def test_list_snaps(self): eq([], list(self.image.list_snaps())) self.image.create_snap('snap1') eq(['snap1'], [snap['name'] for snap in self.image.list_snaps()]) self.image.create_snap('snap2') eq(['snap1', 'snap2'], [snap['name'] for snap in self.image.list_snaps()]) self.image.remove_snap('snap1') self.image.remove_snap('snap2') def test_list_snaps_iterator_auto_close(self): self.image.create_snap('snap1') self.image.list_snaps() self.image.remove_snap('snap1') def test_remove_snap(self): eq([], list(self.image.list_snaps())) self.image.create_snap('snap1') eq(['snap1'], [snap['name'] for snap in self.image.list_snaps()]) self.image.remove_snap('snap1') eq([], list(self.image.list_snaps())) def test_rename_snap(self): eq([], list(self.image.list_snaps())) self.image.create_snap('snap1') eq(['snap1'], [snap['name'] for snap in self.image.list_snaps()]) self.image.rename_snap("snap1", "snap1-rename") eq(['snap1-rename'], [snap['name'] for snap in self.image.list_snaps()]) self.image.remove_snap('snap1-rename') eq([], list(self.image.list_snaps())) @require_features([RBD_FEATURE_LAYERING]) def test_protect_snap(self): self.image.create_snap('snap1') assert(not self.image.is_protected_snap('snap1')) self.image.protect_snap('snap1') assert(self.image.is_protected_snap('snap1')) assert_raises(ImageBusy, self.image.remove_snap, 'snap1') self.image.unprotect_snap('snap1') assert(not self.image.is_protected_snap('snap1')) self.image.remove_snap('snap1') assert_raises(ImageNotFound, self.image.unprotect_snap, 'snap1') assert_raises(ImageNotFound, self.image.is_protected_snap, 'snap1') def test_limit_snaps(self): self.image.set_snap_limit(2) eq(2, self.image.get_snap_limit()) self.image.create_snap('snap1') self.image.create_snap('snap2') assert_raises(DiskQuotaExceeded, self.image.create_snap, 'snap3') self.image.remove_snap_limit() self.image.create_snap('snap3') self.image.remove_snap('snap1') self.image.remove_snap('snap2') self.image.remove_snap('snap3') @require_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_remove_with_exclusive_lock(self): assert_raises(ImageBusy, remove_image) @blacklist_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_remove_with_snap(self): self.image.create_snap('snap1') assert_raises(ImageHasSnapshots, remove_image) self.image.remove_snap('snap1') @blacklist_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_remove_with_watcher(self): data = rand_data(256) self.image.write(data, 0) assert_raises(ImageBusy, remove_image) read = self.image.read(0, 256) eq(read, data) def test_rollback_to_snap(self): self.image.write(b'\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.rollback_to_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) self.image.remove_snap('snap1') def test_rollback_to_snap_sparse(self): self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.rollback_to_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) self.image.remove_snap('snap1') def test_rollback_with_resize(self): read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, data) new_size = IMG_SIZE * 2 self.image.resize(new_size) check_stat(self.image.stat(), new_size, IMG_ORDER) self.image.write(data, new_size - 256) self.image.create_snap('snap2') read = self.image.read(new_size - 256, 256) eq(read, data) self.image.rollback_to_snap('snap1') check_stat(self.image.stat(), IMG_SIZE, IMG_ORDER) assert_raises(InvalidArgument, self.image.read, new_size - 256, 256) self.image.rollback_to_snap('snap2') check_stat(self.image.stat(), new_size, IMG_ORDER) read = self.image.read(new_size - 256, 256) eq(read, data) self.image.remove_snap('snap1') self.image.remove_snap('snap2') def test_set_snap(self): self.image.write(b'\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) self.image.remove_snap('snap1') def test_set_no_snap(self): self.image.write(b'\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) self.image.set_snap(None) read = self.image.read(0, 256) eq(read, data) self.image.remove_snap('snap1') def test_set_snap_sparse(self): self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) self.image.remove_snap('snap1') def test_many_snaps(self): num_snaps = 200 for i in range(num_snaps): self.image.create_snap(str(i)) snaps = sorted(self.image.list_snaps(), key=lambda snap: int(snap['name'])) eq(len(snaps), num_snaps) for i, snap in enumerate(snaps): eq(snap['size'], IMG_SIZE) eq(snap['name'], str(i)) for i in range(num_snaps): self.image.remove_snap(str(i)) def test_set_snap_deleted(self): self.image.write(b'\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') self.image.remove_snap('snap1') assert_raises(ImageNotFound, self.image.read, 0, 256) self.image.set_snap(None) read = self.image.read(0, 256) eq(read, data) def test_set_snap_recreated(self): self.image.write(b'\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, b'\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') self.image.remove_snap('snap1') self.image.create_snap('snap1') assert_raises(ImageNotFound, self.image.read, 0, 256) self.image.set_snap(None) read = self.image.read(0, 256) eq(read, data) self.image.remove_snap('snap1') def test_lock_unlock(self): assert_raises(ImageNotFound, self.image.unlock, '') self.image.lock_exclusive('') assert_raises(ImageExists, self.image.lock_exclusive, '') assert_raises(ImageBusy, self.image.lock_exclusive, 'test') assert_raises(ImageExists, self.image.lock_shared, '', '') assert_raises(ImageBusy, self.image.lock_shared, 'foo', '') self.image.unlock('') def test_list_lockers(self): eq([], self.image.list_lockers()) self.image.lock_exclusive('test') lockers = self.image.list_lockers() eq(1, len(lockers['lockers'])) _, cookie, _ = lockers['lockers'][0] eq(cookie, 'test') eq('', lockers['tag']) assert lockers['exclusive'] self.image.unlock('test') eq([], self.image.list_lockers()) num_shared = 10 for i in range(num_shared): self.image.lock_shared(str(i), 'tag') lockers = self.image.list_lockers() eq('tag', lockers['tag']) assert not lockers['exclusive'] eq(num_shared, len(lockers['lockers'])) cookies = sorted(map(lambda x: x[1], lockers['lockers'])) for i in range(num_shared): eq(str(i), cookies[i]) self.image.unlock(str(i)) eq([], self.image.list_lockers()) def test_diff_iterate(self): check_diff(self.image, 0, IMG_SIZE, None, []) self.image.write(b'a' * 256, 0) check_diff(self.image, 0, IMG_SIZE, None, [(0, 256, True)]) self.image.write(b'b' * 256, 256) check_diff(self.image, 0, IMG_SIZE, None, [(0, 512, True)]) self.image.discard(128, 256) check_diff(self.image, 0, IMG_SIZE, None, [(0, 512, True)]) self.image.create_snap('snap1') self.image.discard(0, 1 << IMG_ORDER) self.image.create_snap('snap2') self.image.set_snap('snap2') check_diff(self.image, 0, IMG_SIZE, 'snap1', [(0, 512, False)]) self.image.remove_snap('snap1') self.image.remove_snap('snap2') def test_aio_read(self): # this is a list so that the local cb() can modify it retval = [None] def cb(_, buf): retval[0] = buf # test1: success case comp = self.image.aio_read(0, 20, cb) comp.wait_for_complete_and_cb() eq(retval[0], b'\0' * 20) eq(comp.get_return_value(), 20) eq(sys.getrefcount(comp), 2) # test2: error case retval[0] = 1 comp = self.image.aio_read(IMG_SIZE, 20, cb) comp.wait_for_complete_and_cb() eq(None, retval[0]) assert(comp.get_return_value() < 0) eq(sys.getrefcount(comp), 2) def test_aio_write(self): retval = [None] def cb(comp): retval[0] = comp.get_return_value() data = rand_data(256) comp = self.image.aio_write(data, 256, cb) comp.wait_for_complete_and_cb() eq(retval[0], 0) eq(comp.get_return_value(), 0) eq(sys.getrefcount(comp), 2) eq(self.image.read(256, 256), data) def test_aio_discard(self): retval = [None] def cb(comp): retval[0] = comp.get_return_value() data = rand_data(256) self.image.write(data, 0) comp = self.image.aio_discard(0, 256, cb) comp.wait_for_complete_and_cb() eq(retval[0], 0) eq(comp.get_return_value(), 0) eq(sys.getrefcount(comp), 2) eq(self.image.read(256, 256), b'\0' * 256) def test_aio_flush(self): retval = [None] def cb(comp): retval[0] = comp.get_return_value() comp = self.image.aio_flush(cb) comp.wait_for_complete_and_cb() eq(retval[0], 0) eq(sys.getrefcount(comp), 2)
class TestImage(object): def setUp(self): self.rbd = RBD() create_image() self.image = Image(ioctx, image_name) def tearDown(self): self.image.close() remove_image() def test_invalidate_cache(self): self.image.write('abc', 0) eq('abc', self.image.read(0, 3)) self.image.invalidate_cache() eq('abc', self.image.read(0, 3)) def test_stat(self): info = self.image.stat() check_stat(info, IMG_SIZE, IMG_ORDER) def test_flags(self): flags = self.image.flags() eq(0, flags) def test_write(self): data = rand_data(256) self.image.write(data, 0) def test_read(self): data = self.image.read(0, 20) eq(data, '\0' * 20) def test_large_write(self): data = rand_data(IMG_SIZE) self.image.write(data, 0) def test_large_read(self): data = self.image.read(0, IMG_SIZE) eq(data, '\0' * IMG_SIZE) def test_write_read(self): data = rand_data(256) offset = 50 self.image.write(data, offset) read = self.image.read(offset, 256) eq(data, read) def test_read_bad_offset(self): assert_raises(InvalidArgument, self.image.read, IMG_SIZE + 1, IMG_SIZE) def test_resize(self): new_size = IMG_SIZE * 2 self.image.resize(new_size) info = self.image.stat() check_stat(info, new_size, IMG_ORDER) def test_size(self): eq(IMG_SIZE, self.image.size()) self.image.create_snap('snap1') new_size = IMG_SIZE * 2 self.image.resize(new_size) eq(new_size, self.image.size()) self.image.create_snap('snap2') self.image.set_snap('snap2') eq(new_size, self.image.size()) self.image.set_snap('snap1') eq(IMG_SIZE, self.image.size()) self.image.set_snap(None) eq(new_size, self.image.size()) self.image.remove_snap('snap1') self.image.remove_snap('snap2') def test_resize_down(self): new_size = IMG_SIZE / 2 data = rand_data(256) self.image.write(data, IMG_SIZE / 2) self.image.resize(new_size) self.image.resize(IMG_SIZE) read = self.image.read(IMG_SIZE / 2, 256) eq('\0' * 256, read) def test_resize_bytes(self): new_size = IMG_SIZE / 2 - 5 data = rand_data(256) self.image.write(data, IMG_SIZE / 2 - 10) self.image.resize(new_size) self.image.resize(IMG_SIZE) read = self.image.read(IMG_SIZE / 2 - 10, 5) eq(data[:5], read) read = self.image.read(IMG_SIZE / 2 - 5, 251) eq('\0' * 251, read) def test_copy(self): global ioctx data = rand_data(256) self.image.write(data, 256) image_name = get_temp_image_name() self.image.copy(ioctx, image_name) assert_raises(ImageExists, self.image.copy, ioctx, image_name) copy = Image(ioctx, image_name) copy_data = copy.read(256, 256) copy.close() self.rbd.remove(ioctx, image_name) eq(data, copy_data) def test_create_snap(self): global ioctx self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) at_snapshot = Image(ioctx, image_name, 'snap1') snap_data = at_snapshot.read(0, 256) at_snapshot.close() eq(snap_data, '\0' * 256) self.image.remove_snap('snap1') def test_list_snaps(self): eq([], list(self.image.list_snaps())) self.image.create_snap('snap1') eq(['snap1'], map(lambda snap: snap['name'], self.image.list_snaps())) self.image.create_snap('snap2') eq(['snap1', 'snap2'], map(lambda snap: snap['name'], self.image.list_snaps())) self.image.remove_snap('snap1') self.image.remove_snap('snap2') def test_remove_snap(self): eq([], list(self.image.list_snaps())) self.image.create_snap('snap1') eq(['snap1'], map(lambda snap: snap['name'], self.image.list_snaps())) self.image.remove_snap('snap1') eq([], list(self.image.list_snaps())) @require_features([RBD_FEATURE_LAYERING]) def test_protect_snap(self): self.image.create_snap('snap1') assert (not self.image.is_protected_snap('snap1')) self.image.protect_snap('snap1') assert (self.image.is_protected_snap('snap1')) assert_raises(ImageBusy, self.image.remove_snap, 'snap1') self.image.unprotect_snap('snap1') assert (not self.image.is_protected_snap('snap1')) self.image.remove_snap('snap1') assert_raises(ImageNotFound, self.image.unprotect_snap, 'snap1') assert_raises(ImageNotFound, self.image.is_protected_snap, 'snap1') @require_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_remove_with_exclusive_lock(self): assert_raises(ImageBusy, remove_image) @blacklist_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_remove_with_snap(self): self.image.create_snap('snap1') assert_raises(ImageHasSnapshots, remove_image) self.image.remove_snap('snap1') @blacklist_features([RBD_FEATURE_EXCLUSIVE_LOCK]) def test_remove_with_watcher(self): data = rand_data(256) self.image.write(data, 0) assert_raises(ImageBusy, remove_image) read = self.image.read(0, 256) eq(read, data) def test_rollback_to_snap(self): self.image.write('\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.rollback_to_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) self.image.remove_snap('snap1') def test_rollback_to_snap_sparse(self): self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.rollback_to_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) self.image.remove_snap('snap1') def test_rollback_with_resize(self): read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, data) new_size = IMG_SIZE * 2 self.image.resize(new_size) check_stat(self.image.stat(), new_size, IMG_ORDER) self.image.write(data, new_size - 256) self.image.create_snap('snap2') read = self.image.read(new_size - 256, 256) eq(read, data) self.image.rollback_to_snap('snap1') check_stat(self.image.stat(), IMG_SIZE, IMG_ORDER) assert_raises(InvalidArgument, self.image.read, new_size - 256, 256) self.image.rollback_to_snap('snap2') check_stat(self.image.stat(), new_size, IMG_ORDER) read = self.image.read(new_size - 256, 256) eq(read, data) self.image.remove_snap('snap1') self.image.remove_snap('snap2') def test_set_snap(self): self.image.write('\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) self.image.remove_snap('snap1') def test_set_no_snap(self): self.image.write('\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) self.image.set_snap(None) read = self.image.read(0, 256) eq(read, data) self.image.remove_snap('snap1') def test_set_snap_sparse(self): self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) self.image.remove_snap('snap1') def test_many_snaps(self): num_snaps = 200 for i in xrange(num_snaps): self.image.create_snap(str(i)) snaps = sorted(self.image.list_snaps(), key=lambda snap: int(snap['name'])) eq(len(snaps), num_snaps) for i, snap in enumerate(snaps): eq(snap['size'], IMG_SIZE) eq(snap['name'], str(i)) for i in xrange(num_snaps): self.image.remove_snap(str(i)) def test_set_snap_deleted(self): self.image.write('\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') self.image.remove_snap('snap1') assert_raises(ImageNotFound, self.image.read, 0, 256) self.image.set_snap(None) read = self.image.read(0, 256) eq(read, data) def test_set_snap_recreated(self): self.image.write('\0' * 256, 0) self.image.create_snap('snap1') read = self.image.read(0, 256) eq(read, '\0' * 256) data = rand_data(256) self.image.write(data, 0) read = self.image.read(0, 256) eq(read, data) self.image.set_snap('snap1') self.image.remove_snap('snap1') self.image.create_snap('snap1') assert_raises(ImageNotFound, self.image.read, 0, 256) self.image.set_snap(None) read = self.image.read(0, 256) eq(read, data) self.image.remove_snap('snap1') def test_lock_unlock(self): assert_raises(ImageNotFound, self.image.unlock, '') self.image.lock_exclusive('') assert_raises(ImageExists, self.image.lock_exclusive, '') assert_raises(ImageBusy, self.image.lock_exclusive, 'test') assert_raises(ImageExists, self.image.lock_shared, '', '') assert_raises(ImageBusy, self.image.lock_shared, 'foo', '') self.image.unlock('') def test_list_lockers(self): eq([], self.image.list_lockers()) self.image.lock_exclusive('test') lockers = self.image.list_lockers() eq(1, len(lockers['lockers'])) _, cookie, _ = lockers['lockers'][0] eq(cookie, 'test') eq('', lockers['tag']) assert lockers['exclusive'] self.image.unlock('test') eq([], self.image.list_lockers()) num_shared = 10 for i in xrange(num_shared): self.image.lock_shared(str(i), 'tag') lockers = self.image.list_lockers() eq('tag', lockers['tag']) assert not lockers['exclusive'] eq(num_shared, len(lockers['lockers'])) cookies = sorted(map(lambda x: x[1], lockers['lockers'])) for i in xrange(num_shared): eq(str(i), cookies[i]) self.image.unlock(str(i)) eq([], self.image.list_lockers()) def test_diff_iterate(self): check_diff(self.image, 0, IMG_SIZE, None, []) self.image.write('a' * 256, 0) check_diff(self.image, 0, IMG_SIZE, None, [(0, 256, True)]) self.image.write('b' * 256, 256) check_diff(self.image, 0, IMG_SIZE, None, [(0, 512, True)]) self.image.discard(128, 256) check_diff(self.image, 0, IMG_SIZE, None, [(0, 512, True)]) self.image.create_snap('snap1') self.image.discard(0, 1 << IMG_ORDER) self.image.create_snap('snap2') self.image.set_snap('snap2') check_diff(self.image, 0, IMG_SIZE, 'snap1', [(0, 512, False)]) self.image.remove_snap('snap1') self.image.remove_snap('snap2')