qemu-iotests: add testcases for mirroring on-source-error/on-target-error
The new options are tested with blkdebug on both the source and the target. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
		
							parent
							
								
									9eb80eadd4
								
							
						
					
					
						commit
						9dfa9f5930
					
				| @ -292,6 +292,259 @@ class TestMirrorNoBacking(ImageMirroringTestCase): | ||||
|         self.assertTrue(self.compare_images(test_img, target_img), | ||||
|                         'target image does not match source after mirroring') | ||||
| 
 | ||||
| class TestReadErrors(ImageMirroringTestCase): | ||||
|     image_len = 2 * 1024 * 1024 # MB | ||||
| 
 | ||||
|     # this should be a multiple of twice the default granularity | ||||
|     # so that we hit this offset first in state 1 | ||||
|     MIRROR_GRANULARITY = 1024 * 1024 | ||||
| 
 | ||||
|     def create_blkdebug_file(self, name, event, errno): | ||||
|         file = open(name, 'w') | ||||
|         file.write(''' | ||||
| [inject-error] | ||||
| state = "1" | ||||
| event = "%s" | ||||
| errno = "%d" | ||||
| immediately = "off" | ||||
| once = "on" | ||||
| sector = "%d" | ||||
| 
 | ||||
| [set-state] | ||||
| state = "1" | ||||
| event = "%s" | ||||
| new_state = "2" | ||||
| 
 | ||||
| [set-state] | ||||
| state = "2" | ||||
| event = "%s" | ||||
| new_state = "1" | ||||
| ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event)) | ||||
|         file.close() | ||||
| 
 | ||||
|     def setUp(self): | ||||
|         self.blkdebug_file = backing_img + ".blkdebug" | ||||
|         self.create_image(backing_img, TestReadErrors.image_len) | ||||
|         self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5) | ||||
|         qemu_img('create', '-f', iotests.imgfmt, | ||||
|                  '-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw' | ||||
|                        % (self.blkdebug_file, backing_img), | ||||
|                  test_img) | ||||
|         self.vm = iotests.VM().add_drive(test_img) | ||||
|         self.vm.launch() | ||||
| 
 | ||||
|     def tearDown(self): | ||||
|         self.vm.shutdown() | ||||
|         os.remove(test_img) | ||||
|         os.remove(backing_img) | ||||
|         os.remove(self.blkdebug_file) | ||||
| 
 | ||||
|     def test_report_read(self): | ||||
|         self.assert_no_active_mirrors() | ||||
| 
 | ||||
|         result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | ||||
|                              target=target_img) | ||||
|         self.assert_qmp(result, 'return', {}) | ||||
| 
 | ||||
|         completed = False | ||||
|         error = False | ||||
|         while not completed: | ||||
|             for event in self.vm.get_qmp_events(wait=True): | ||||
|                 if event['event'] == 'BLOCK_JOB_ERROR': | ||||
|                     self.assert_qmp(event, 'data/device', 'drive0') | ||||
|                     self.assert_qmp(event, 'data/operation', 'read') | ||||
|                     error = True | ||||
|                 elif event['event'] == 'BLOCK_JOB_READY': | ||||
|                     self.assertTrue(False, 'job completed unexpectedly') | ||||
|                 elif event['event'] == 'BLOCK_JOB_COMPLETED': | ||||
|                     self.assertTrue(error, 'job completed unexpectedly') | ||||
|                     self.assert_qmp(event, 'data/type', 'mirror') | ||||
|                     self.assert_qmp(event, 'data/device', 'drive0') | ||||
|                     self.assert_qmp(event, 'data/error', 'Input/output error') | ||||
|                     self.assert_qmp(event, 'data/len', self.image_len) | ||||
|                     completed = True | ||||
| 
 | ||||
|         self.assert_no_active_mirrors() | ||||
|         self.vm.shutdown() | ||||
| 
 | ||||
|     def test_ignore_read(self): | ||||
|         self.assert_no_active_mirrors() | ||||
| 
 | ||||
|         result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | ||||
|                              target=target_img, on_source_error='ignore') | ||||
|         self.assert_qmp(result, 'return', {}) | ||||
| 
 | ||||
|         event = self.vm.get_qmp_event(wait=True) | ||||
|         self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') | ||||
|         self.assert_qmp(event, 'data/device', 'drive0') | ||||
|         self.assert_qmp(event, 'data/operation', 'read') | ||||
|         result = self.vm.qmp('query-block-jobs') | ||||
|         self.assert_qmp(result, 'return[0]/paused', False) | ||||
|         self.complete_and_wait() | ||||
|         self.vm.shutdown() | ||||
| 
 | ||||
|     def test_stop_read(self): | ||||
|         self.assert_no_active_mirrors() | ||||
| 
 | ||||
|         result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | ||||
|                              target=target_img, on_source_error='stop') | ||||
|         self.assert_qmp(result, 'return', {}) | ||||
| 
 | ||||
|         error = False | ||||
|         ready = False | ||||
|         while not ready: | ||||
|             for event in self.vm.get_qmp_events(wait=True): | ||||
|                 if event['event'] == 'BLOCK_JOB_ERROR': | ||||
|                     self.assert_qmp(event, 'data/device', 'drive0') | ||||
|                     self.assert_qmp(event, 'data/operation', 'read') | ||||
| 
 | ||||
|                     result = self.vm.qmp('query-block-jobs') | ||||
|                     self.assert_qmp(result, 'return[0]/paused', True) | ||||
|                     self.assert_qmp(result, 'return[0]/io-status', 'failed') | ||||
| 
 | ||||
|                     result = self.vm.qmp('block-job-resume', device='drive0') | ||||
|                     self.assert_qmp(result, 'return', {}) | ||||
|                     error = True | ||||
|                 elif event['event'] == 'BLOCK_JOB_READY': | ||||
|                     self.assertTrue(error, 'job completed unexpectedly') | ||||
|                     self.assert_qmp(event, 'data/device', 'drive0') | ||||
|                     ready = True | ||||
| 
 | ||||
|         result = self.vm.qmp('query-block-jobs') | ||||
|         self.assert_qmp(result, 'return[0]/paused', False) | ||||
|         self.assert_qmp(result, 'return[0]/io-status', 'ok') | ||||
| 
 | ||||
|         self.complete_and_wait(wait_ready=False) | ||||
|         self.assert_no_active_mirrors() | ||||
|         self.vm.shutdown() | ||||
| 
 | ||||
| class TestWriteErrors(ImageMirroringTestCase): | ||||
|     image_len = 2 * 1024 * 1024 # MB | ||||
| 
 | ||||
|     # this should be a multiple of twice the default granularity | ||||
|     # so that we hit this offset first in state 1 | ||||
|     MIRROR_GRANULARITY = 1024 * 1024 | ||||
| 
 | ||||
|     def create_blkdebug_file(self, name, event, errno): | ||||
|         file = open(name, 'w') | ||||
|         file.write(''' | ||||
| [inject-error] | ||||
| state = "1" | ||||
| event = "%s" | ||||
| errno = "%d" | ||||
| immediately = "off" | ||||
| once = "on" | ||||
| sector = "%d" | ||||
| 
 | ||||
| [set-state] | ||||
| state = "1" | ||||
| event = "%s" | ||||
| new_state = "2" | ||||
| 
 | ||||
| [set-state] | ||||
| state = "2" | ||||
| event = "%s" | ||||
| new_state = "1" | ||||
| ''' % (event, errno, self.MIRROR_GRANULARITY / 512, event, event)) | ||||
|         file.close() | ||||
| 
 | ||||
|     def setUp(self): | ||||
|         self.blkdebug_file = target_img + ".blkdebug" | ||||
|         self.create_image(backing_img, TestWriteErrors.image_len) | ||||
|         self.create_blkdebug_file(self.blkdebug_file, "write_aio", 5) | ||||
|         qemu_img('create', '-f', iotests.imgfmt, '-obacking_file=%s' %(backing_img), test_img) | ||||
|         self.vm = iotests.VM().add_drive(test_img) | ||||
|         self.target_img = 'blkdebug:%s:%s' % (self.blkdebug_file, target_img) | ||||
|         qemu_img('create', '-f', iotests.imgfmt, '-osize=%d' %(TestWriteErrors.image_len), target_img) | ||||
|         self.vm.launch() | ||||
| 
 | ||||
|     def tearDown(self): | ||||
|         self.vm.shutdown() | ||||
|         os.remove(test_img) | ||||
|         os.remove(backing_img) | ||||
|         os.remove(self.blkdebug_file) | ||||
| 
 | ||||
|     def test_report_write(self): | ||||
|         self.assert_no_active_mirrors() | ||||
| 
 | ||||
|         result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | ||||
|                              mode='existing', target=self.target_img) | ||||
|         self.assert_qmp(result, 'return', {}) | ||||
| 
 | ||||
|         completed = False | ||||
|         error = False | ||||
|         while not completed: | ||||
|             for event in self.vm.get_qmp_events(wait=True): | ||||
|                 if event['event'] == 'BLOCK_JOB_ERROR': | ||||
|                     self.assert_qmp(event, 'data/device', 'drive0') | ||||
|                     self.assert_qmp(event, 'data/operation', 'write') | ||||
|                     error = True | ||||
|                 elif event['event'] == 'BLOCK_JOB_READY': | ||||
|                     self.assertTrue(False, 'job completed unexpectedly') | ||||
|                 elif event['event'] == 'BLOCK_JOB_COMPLETED': | ||||
|                     self.assertTrue(error, 'job completed unexpectedly') | ||||
|                     self.assert_qmp(event, 'data/type', 'mirror') | ||||
|                     self.assert_qmp(event, 'data/device', 'drive0') | ||||
|                     self.assert_qmp(event, 'data/error', 'Input/output error') | ||||
|                     self.assert_qmp(event, 'data/len', self.image_len) | ||||
|                     completed = True | ||||
| 
 | ||||
|         self.assert_no_active_mirrors() | ||||
|         self.vm.shutdown() | ||||
| 
 | ||||
|     def test_ignore_write(self): | ||||
|         self.assert_no_active_mirrors() | ||||
| 
 | ||||
|         result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | ||||
|                              mode='existing', target=self.target_img, | ||||
|                              on_target_error='ignore') | ||||
|         self.assert_qmp(result, 'return', {}) | ||||
| 
 | ||||
|         event = self.vm.get_qmp_event(wait=True) | ||||
|         self.assertEquals(event['event'], 'BLOCK_JOB_ERROR') | ||||
|         self.assert_qmp(event, 'data/device', 'drive0') | ||||
|         self.assert_qmp(event, 'data/operation', 'write') | ||||
|         result = self.vm.qmp('query-block-jobs') | ||||
|         self.assert_qmp(result, 'return[0]/paused', False) | ||||
|         self.complete_and_wait() | ||||
|         self.vm.shutdown() | ||||
| 
 | ||||
|     def test_stop_write(self): | ||||
|         self.assert_no_active_mirrors() | ||||
| 
 | ||||
|         result = self.vm.qmp('drive-mirror', device='drive0', sync='full', | ||||
|                              mode='existing', target=self.target_img, | ||||
|                              on_target_error='stop') | ||||
|         self.assert_qmp(result, 'return', {}) | ||||
| 
 | ||||
|         error = False | ||||
|         ready = False | ||||
|         while not ready: | ||||
|             for event in self.vm.get_qmp_events(wait=True): | ||||
|                 if event['event'] == 'BLOCK_JOB_ERROR': | ||||
|                     self.assert_qmp(event, 'data/device', 'drive0') | ||||
|                     self.assert_qmp(event, 'data/operation', 'write') | ||||
| 
 | ||||
|                     result = self.vm.qmp('query-block-jobs') | ||||
|                     self.assert_qmp(result, 'return[0]/paused', True) | ||||
|                     self.assert_qmp(result, 'return[0]/io-status', 'failed') | ||||
| 
 | ||||
|                     result = self.vm.qmp('block-job-resume', device='drive0') | ||||
|                     self.assert_qmp(result, 'return', {}) | ||||
| 
 | ||||
|                     result = self.vm.qmp('query-block-jobs') | ||||
|                     self.assert_qmp(result, 'return[0]/paused', False) | ||||
|                     self.assert_qmp(result, 'return[0]/io-status', 'ok') | ||||
|                     error = True | ||||
|                 elif event['event'] == 'BLOCK_JOB_READY': | ||||
|                     self.assertTrue(error, 'job completed unexpectedly') | ||||
|                     self.assert_qmp(event, 'data/device', 'drive0') | ||||
|                     ready = True | ||||
| 
 | ||||
|         self.complete_and_wait(wait_ready=False) | ||||
|         self.assert_no_active_mirrors() | ||||
|         self.vm.shutdown() | ||||
| 
 | ||||
| class TestSetSpeed(ImageMirroringTestCase): | ||||
|     image_len = 80 * 1024 * 1024 # MB | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| ............ | ||||
| .................. | ||||
| ---------------------------------------------------------------------- | ||||
| Ran 12 tests | ||||
| Ran 18 tests | ||||
| 
 | ||||
| OK | ||||
|  | ||||
| @ -106,6 +106,10 @@ class VM(object): | ||||
| 
 | ||||
|         return self._qmp.cmd(cmd, args=qmp_args) | ||||
| 
 | ||||
|     def get_qmp_event(self, wait=False): | ||||
|         '''Poll for one queued QMP events and return it''' | ||||
|         return self._qmp.pull_event(wait=wait) | ||||
| 
 | ||||
|     def get_qmp_events(self, wait=False): | ||||
|         '''Poll for queued QMP events and return a list of dicts''' | ||||
|         events = self._qmp.get_events(wait=wait) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Paolo Bonzini
						Paolo Bonzini