From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57386) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Wvc5L-0006eY-Io for qemu-devel@nongnu.org; Fri, 13 Jun 2014 20:44:48 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Wvc5G-0008Rm-Dm for qemu-devel@nongnu.org; Fri, 13 Jun 2014 20:44:43 -0400 Received: from mx1.redhat.com ([209.132.183.28]:6122) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Wvc5G-0008RX-2h for qemu-devel@nongnu.org; Fri, 13 Jun 2014 20:44:38 -0400 Message-ID: <539B9AED.9060408@redhat.com> Date: Sat, 14 Jun 2014 02:44:29 +0200 From: Max Reitz MIME-Version: 1.0 References: <1402493053-13787-1-git-send-email-benoit.canet@irqsave.net> <1402493053-13787-5-git-send-email-benoit.canet@irqsave.net> In-Reply-To: <1402493053-13787-5-git-send-email-benoit.canet@irqsave.net> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: quoted-printable Subject: Re: [Qemu-devel] [PATCH v9 4/4] qemu-iotests: Add TestRepairQuorum to 041 to test drive-mirror node-name mode. List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: =?ISO-8859-1?Q?Beno=EEt_Canet?= , qemu-devel@nongnu.org Cc: kwolf@redhat.com, Benoit Canet , stefanha@redhat.com On 11.06.2014 15:24, Beno=EEt Canet wrote: > The to-replace-node-name is designed to allow repairing of broken Quoru= m file. "a broken Quorum file" or "broken Quorum files". > This patch introduce a new class TestRepairQuorum testing that the feat= ure *introduces > works. > Some further work will be done on QEMU to improve the robutness of the = tests. *robustness > Signed-off-by: Benoit Canet > --- > tests/qemu-iotests/041 | 196 ++++++++++++++++++++++++++++++++++++= ++++++++- > tests/qemu-iotests/041.out | 4 +- > 2 files changed, 194 insertions(+), 6 deletions(-) > > diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041 > index ec470b2..c0480e1 100755 > --- a/tests/qemu-iotests/041 > +++ b/tests/qemu-iotests/041 > @@ -28,6 +28,12 @@ target_backing_img =3D os.path.join(iotests.test_dir= , 'target-backing.img') > test_img =3D os.path.join(iotests.test_dir, 'test.img') > target_img =3D os.path.join(iotests.test_dir, 'target.img') > =20 > +quorum_img1 =3D os.path.join(iotests.test_dir, 'quorum1.img') > +quorum_img2 =3D os.path.join(iotests.test_dir, 'quorum2.img') > +quorum_img3 =3D os.path.join(iotests.test_dir, 'quorum3.img') > +quorum_repair_img =3D os.path.join(iotests.test_dir, 'quorum_repair.im= g') > +quorum_snapshot_file =3D os.path.join(iotests.test_dir, 'quorum_snapsh= ot.img') > + > class ImageMirroringTestCase(iotests.QMPTestCase): > '''Abstract base class for image mirroring test cases''' > =20 > @@ -42,8 +48,8 @@ class ImageMirroringTestCase(iotests.QMPTestCase): > ready =3D True > =20 > def wait_ready_and_cancel(self, drive=3D'drive0'): > - self.wait_ready(drive) > - event =3D self.cancel_and_wait() > + self.wait_ready(drive=3Ddrive) > + event =3D self.cancel_and_wait(drive=3Ddrive) My Python is very bad (if existent at all), but is this "drive=3Ddrive"=20 really necessary? Wouldn't simply "drive" suffice? > self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED') > self.assert_qmp(event, 'data/type', 'mirror') > self.assert_qmp(event, 'data/offset', self.image_len) > @@ -52,12 +58,12 @@ class ImageMirroringTestCase(iotests.QMPTestCase): > def complete_and_wait(self, drive=3D'drive0', wait_ready=3DTrue): > '''Complete a block job and wait for it to finish''' > if wait_ready: > - self.wait_ready() > + self.wait_ready(drive=3Ddrive) > =20 > result =3D self.vm.qmp('block-job-complete', device=3Ddrive) > self.assert_qmp(result, 'return', {}) > =20 > - event =3D self.wait_until_completed() > + event =3D self.wait_until_completed(drive=3Ddrive) > self.assert_qmp(event, 'data/type', 'mirror') > =20 > class TestSingleDrive(ImageMirroringTestCase): > @@ -718,5 +724,187 @@ class TestUnbackedSource(ImageMirroringTestCase): > self.complete_and_wait() > self.assert_no_active_block_jobs() > =20 > +class TestRepairQuorum(ImageMirroringTestCase): > + """ This class test quorum file repair using drive-mirror. > + It's mostly a fork of TestSingleDrive """ > + image_len =3D 1 * 1024 * 1024 # MB > + IMAGES =3D [ quorum_img1, quorum_img2, quorum_img3 ] > + > + def setUp(self): > + self.vm =3D iotests.VM() > + > + # Add each individual quorum images > + for i in self.IMAGES: > + qemu_img('create', '-f', iotests.imgfmt, i, > + str(TestSingleDrive.image_len)) > + # Assign a node name to each quorum image in order to mani= pulate > + # them > + opts =3D "node-name=3Dimg%i" % self.IMAGES.index(i) > + self.vm =3D self.vm.add_drive(i, opts) Just an idea: As you are constantly swapping out img1, why don't you=20 write some data to img2 and img3 and different data to img1 to test it=20 all how it's supposed to work? > + > + self.vm.launch() > + > + #assemble the quorum block device from the individual files > + args =3D { "options" : { "driver": "quorum", "id": "quorum0", > + "vote-threshold": 2, "children": [ "img0", "img1", "i= mg2" ] } } > + result =3D self.vm.qmp("blockdev-add", **args) > + self.assert_qmp(result, 'return', {}) > + > + > + def tearDown(self): > + self.vm.shutdown() > + for i in self.IMAGES + [ quorum_repair_img ]: > + # Do a try/except because the test may have deleted some i= mages > + try: > + os.remove(i) > + except OSError: > + pass > + > + def test_complete(self): > + self.assert_no_active_block_jobs() > + > + result =3D self.vm.qmp('drive-mirror', device=3D'quorum0', syn= c=3D'full', > + node_name=3D"repair0", > + replaces=3D"img1", > + target=3Dquorum_repair_img, format=3Diote= sts.imgfmt) > + self.assert_qmp(result, 'return', {}) > + > + self.complete_and_wait(drive=3D"quorum0") > + result =3D self.vm.qmp('query-named-block-nodes') > + self.assert_qmp(result, 'return[0]/file', quorum_repair_img) Hm, why do you know this is at index 0? > + # TODO: a better test requiring some QEMU infrastructure will = be added > + # to check that this file is really driven by quorum > + self.vm.shutdown() > + self.assertTrue(iotests.compare_images(quorum_img2, quorum_rep= air_img), > + 'target image does not match source after mirr= oring') > + > + def test_cancel(self): > + self.assert_no_active_block_jobs() > + > + result =3D self.vm.qmp('drive-mirror', device=3D'quorum0', syn= c=3D'full', > + node_name=3D"repair0", > + replaces=3D"img1", > + target=3Dquorum_repair_img, format=3Diote= sts.imgfmt) > + self.assert_qmp(result, 'return', {}) > + > + self.cancel_and_wait(drive=3D"quorum0", force=3DTrue) > + # here we check that the last registered quorum file has not b= een > + # swapped out and unref > + result =3D self.vm.qmp('query-named-block-nodes') > + self.assert_qmp(result, 'return[0]/file', quorum_img3) Why would img3 be affected at all? Aren't you trying to replace img1?=20 (Also, again, why index 0?) > + self.vm.shutdown() > + > + def test_cancel_after_ready(self): > + self.assert_no_active_block_jobs() > + > + result =3D self.vm.qmp('drive-mirror', device=3D'quorum0', syn= c=3D'full', > + node_name=3D"repair0", > + replaces=3D"img1", > + target=3Dquorum_repair_img, format=3Diote= sts.imgfmt) > + self.assert_qmp(result, 'return', {}) > + > + self.wait_ready_and_cancel(drive=3D"quorum0") > + result =3D self.vm.qmp('query-named-block-nodes') > + # here we check that the last registered quorum file has not b= een > + # swapped out and unref > + self.assert_qmp(result, 'return[0]/file', quorum_img3) Same here. > + self.vm.shutdown() > + self.assertTrue(iotests.compare_images(quorum_img2, quorum_rep= air_img), > + 'target image does not match source after mirr= oring') > + > + def test_pause(self): > + self.assert_no_active_block_jobs() > + > + result =3D self.vm.qmp('drive-mirror', device=3D'quorum0', syn= c=3D'full', > + node_name=3D"repair0", > + replaces=3D"img1", > + target=3Dquorum_repair_img, format=3Diote= sts.imgfmt) > + self.assert_qmp(result, 'return', {}) > + > + result =3D self.vm.qmp('block-job-pause', device=3D'quorum0') > + self.assert_qmp(result, 'return', {}) > + > + time.sleep(1) > + result =3D self.vm.qmp('query-block-jobs') > + offset =3D self.dictpath(result, 'return[0]/offset') > + > + time.sleep(1) > + result =3D self.vm.qmp('query-block-jobs') > + self.assert_qmp(result, 'return[0]/offset', offset) > + > + result =3D self.vm.qmp('block-job-resume', device=3D'quorum0') > + self.assert_qmp(result, 'return', {}) > + > + self.complete_and_wait(drive=3D"quorum0") > + self.vm.shutdown() > + self.assertTrue(iotests.compare_images(quorum_img2, quorum_rep= air_img), > + 'target image does not match source after mirr= oring') > + > + def test_medium_not_found(self): > + result =3D self.vm.qmp('drive-mirror', device=3D'ide1-cd0', sy= nc=3D'full', I don't know whether this device is supposed to exist forever, but if it=20 disappears from default configuration one day, TestSingleDrive will=20 break as well, so it's probably fine. Max > + node_name=3D'repair0', > + replaces=3D'img1', > + target=3Dquorum_repair_img, format=3Diote= sts.imgfmt) > + self.assert_qmp(result, 'error/class', 'GenericError') > + > + def test_image_not_found(self): > + result =3D self.vm.qmp('drive-mirror', device=3D'quorum0', syn= c=3D'full', > + node_name=3D'repair0', > + replaces=3D'img1', > + mode=3D'existing', > + target=3Dquorum_repair_img, format=3Diote= sts.imgfmt) > + self.assert_qmp(result, 'error/class', 'GenericError') > + > + def test_device_not_found(self): > + result =3D self.vm.qmp('drive-mirror', device=3D'nonexistent',= sync=3D'full', > + node_name=3D'repair0', > + replaces=3D'img1', > + target=3Dquorum_repair_img, format=3Diote= sts.imgfmt) > + self.assert_qmp(result, 'error/class', 'DeviceNotFound') > + > + def test_wrong_sync_mode(self): > + result =3D self.vm.qmp('drive-mirror', device=3D'quorum0', > + node_name=3D'repair0', > + replaces=3D'img1', > + target=3Dquorum_repair_img, format=3Diote= sts.imgfmt) > + self.assert_qmp(result, 'error/class', 'GenericError') > + > + def test_no_node_name(self): > + result =3D self.vm.qmp('drive-mirror', device=3D'quorum0', syn= c=3D'full', > + replaces=3D'img1', > + target=3Dquorum_repair_img, format=3Diote= sts.imgfmt) > + self.assert_qmp(result, 'error/class', 'GenericError') > + > + def test_unexistant_replaces(self): > + result =3D self.vm.qmp('drive-mirror', device=3D'quorum0', syn= c=3D'full', > + node_name=3D'repair0', > + replaces=3D'img77', > + target=3Dquorum_repair_img, format=3Diote= sts.imgfmt) > + self.assert_qmp(result, 'error/class', 'GenericError') > + > + def test_after_a_quorum_snapshot(self): > + result =3D self.vm.qmp('blockdev-snapshot-sync', node_name=3D'= img1', > + snapshot_file=3Dquorum_snapshot_file, > + snapshot_node_name=3D"snap1"); > + > + result =3D self.vm.qmp('drive-mirror', device=3D'quorum0', syn= c=3D'full', > + node_name=3D'repair0', > + replaces=3D"img1", > + target=3Dquorum_repair_img, format=3Diote= sts.imgfmt) > + self.assert_qmp(result, 'error/class', 'GenericError') > + > + result =3D self.vm.qmp('drive-mirror', device=3D'quorum0', syn= c=3D'full', > + node_name=3D'repair0', > + replaces=3D"snap1", > + target=3Dquorum_repair_img, format=3Diote= sts.imgfmt) > + self.assert_qmp(result, 'return', {}) > + > + self.complete_and_wait(drive=3D"quorum0") > + result =3D self.vm.qmp('query-named-block-nodes') > + self.assert_qmp(result, 'return[0]/file', quorum_repair_img) > + # TODO: a better test requiring some QEMU infrastructure will = be added > + # to check that this file is really driven by quorum > + self.vm.shutdown() > + > if __name__ =3D=3D '__main__': > iotests.main(supported_fmts=3D['qcow2', 'qed']) > diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out > index 6d9bee1..73e375a 100644 > --- a/tests/qemu-iotests/041.out > +++ b/tests/qemu-iotests/041.out > @@ -1,5 +1,5 @@ > -........................... > +...................................... > ---------------------------------------------------------------------= - > -Ran 27 tests > +Ran 38 tests > =20 > OK