|
|
1.1 root 1: #!/usr/bin/env python
2: #
3: # Tests for image streaming.
4: #
5: # Copyright (C) 2012 IBM Corp.
6: #
7: # This program is free software; you can redistribute it and/or modify
8: # it under the terms of the GNU General Public License as published by
9: # the Free Software Foundation; either version 2 of the License, or
10: # (at your option) any later version.
11: #
12: # This program is distributed in the hope that it will be useful,
13: # but WITHOUT ANY WARRANTY; without even the implied warranty of
14: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: # GNU General Public License for more details.
16: #
17: # You should have received a copy of the GNU General Public License
18: # along with this program. If not, see <http://www.gnu.org/licenses/>.
19: #
20:
21: import os
22: import iotests
23: from iotests import qemu_img, qemu_io
24:
25: backing_img = os.path.join(iotests.test_dir, 'backing.img')
26: mid_img = os.path.join(iotests.test_dir, 'mid.img')
27: test_img = os.path.join(iotests.test_dir, 'test.img')
28:
29: class ImageStreamingTestCase(iotests.QMPTestCase):
30: '''Abstract base class for image streaming test cases'''
31:
32: def assert_no_active_streams(self):
33: result = self.vm.qmp('query-block-jobs')
34: self.assert_qmp(result, 'return', [])
35:
36: def cancel_and_wait(self, drive='drive0'):
37: '''Cancel a block job and wait for it to finish'''
38: result = self.vm.qmp('block-job-cancel', device=drive)
39: self.assert_qmp(result, 'return', {})
40:
41: cancelled = False
42: while not cancelled:
43: for event in self.vm.get_qmp_events(wait=True):
44: if event['event'] == 'BLOCK_JOB_CANCELLED':
45: self.assert_qmp(event, 'data/type', 'stream')
46: self.assert_qmp(event, 'data/device', drive)
47: cancelled = True
48:
49: self.assert_no_active_streams()
50:
51: class TestSingleDrive(ImageStreamingTestCase):
52: image_len = 1 * 1024 * 1024 # MB
53:
54: def setUp(self):
55: qemu_img('create', backing_img, str(TestSingleDrive.image_len))
56: qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img)
57: qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
58: self.vm = iotests.VM().add_drive(test_img)
59: self.vm.launch()
60:
61: def tearDown(self):
62: self.vm.shutdown()
63: os.remove(test_img)
64: os.remove(mid_img)
65: os.remove(backing_img)
66:
67: def test_stream(self):
68: self.assert_no_active_streams()
69:
70: result = self.vm.qmp('block-stream', device='drive0')
71: self.assert_qmp(result, 'return', {})
72:
73: completed = False
74: while not completed:
75: for event in self.vm.get_qmp_events(wait=True):
76: if event['event'] == 'BLOCK_JOB_COMPLETED':
77: self.assert_qmp(event, 'data/type', 'stream')
78: self.assert_qmp(event, 'data/device', 'drive0')
79: self.assert_qmp(event, 'data/offset', self.image_len)
80: self.assert_qmp(event, 'data/len', self.image_len)
81: completed = True
82:
83: self.assert_no_active_streams()
84: self.vm.shutdown()
85:
86: self.assertEqual(qemu_io('-c', 'map', backing_img),
87: qemu_io('-c', 'map', test_img),
88: 'image file map does not match backing file after streaming')
89:
90: def test_stream_partial(self):
91: self.assert_no_active_streams()
92:
93: result = self.vm.qmp('block-stream', device='drive0', base=mid_img)
94: self.assert_qmp(result, 'return', {})
95:
96: completed = False
97: while not completed:
98: for event in self.vm.get_qmp_events(wait=True):
99: if event['event'] == 'BLOCK_JOB_COMPLETED':
100: self.assert_qmp(event, 'data/type', 'stream')
101: self.assert_qmp(event, 'data/device', 'drive0')
102: self.assert_qmp(event, 'data/offset', self.image_len)
103: self.assert_qmp(event, 'data/len', self.image_len)
104: completed = True
105:
106: self.assert_no_active_streams()
107: self.vm.shutdown()
108:
109: self.assertEqual(qemu_io('-c', 'map', mid_img),
110: qemu_io('-c', 'map', test_img),
111: 'image file map does not match backing file after streaming')
112:
113: def test_device_not_found(self):
114: result = self.vm.qmp('block-stream', device='nonexistent')
115: self.assert_qmp(result, 'error/class', 'DeviceNotFound')
116:
117: class TestStreamStop(ImageStreamingTestCase):
118: image_len = 8 * 1024 * 1024 * 1024 # GB
119:
120: def setUp(self):
121: qemu_img('create', backing_img, str(TestStreamStop.image_len))
122: qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
123: self.vm = iotests.VM().add_drive(test_img)
124: self.vm.launch()
125:
126: def tearDown(self):
127: self.vm.shutdown()
128: os.remove(test_img)
129: os.remove(backing_img)
130:
131: def test_stream_stop(self):
132: import time
133:
134: self.assert_no_active_streams()
135:
136: result = self.vm.qmp('block-stream', device='drive0')
137: self.assert_qmp(result, 'return', {})
138:
139: time.sleep(1)
140: events = self.vm.get_qmp_events(wait=False)
141: self.assertEqual(events, [], 'unexpected QMP event: %s' % events)
142:
143: self.cancel_and_wait()
144:
145: class TestSetSpeed(ImageStreamingTestCase):
146: image_len = 80 * 1024 * 1024 # MB
147:
148: def setUp(self):
149: qemu_img('create', backing_img, str(TestSetSpeed.image_len))
150: qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
151: self.vm = iotests.VM().add_drive(test_img)
152: self.vm.launch()
153:
154: def tearDown(self):
155: self.vm.shutdown()
156: os.remove(test_img)
157: os.remove(backing_img)
158:
159: # This is a short performance test which is not run by default.
160: # Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_throughput"
161: def perf_test_throughput(self):
162: self.assert_no_active_streams()
163:
164: result = self.vm.qmp('block-stream', device='drive0')
165: self.assert_qmp(result, 'return', {})
166:
167: result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
168: self.assert_qmp(result, 'return', {})
169:
170: completed = False
171: while not completed:
172: for event in self.vm.get_qmp_events(wait=True):
173: if event['event'] == 'BLOCK_JOB_COMPLETED':
174: self.assert_qmp(event, 'data/type', 'stream')
175: self.assert_qmp(event, 'data/device', 'drive0')
176: self.assert_qmp(event, 'data/offset', self.image_len)
177: self.assert_qmp(event, 'data/len', self.image_len)
178: completed = True
179:
180: self.assert_no_active_streams()
181:
182: def test_set_speed(self):
183: self.assert_no_active_streams()
184:
185: result = self.vm.qmp('block-stream', device='drive0')
186: self.assert_qmp(result, 'return', {})
187:
188: # Default speed is 0
189: result = self.vm.qmp('query-block-jobs')
190: self.assert_qmp(result, 'return[0]/device', 'drive0')
191: self.assert_qmp(result, 'return[0]/speed', 0)
192:
193: result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
194: self.assert_qmp(result, 'return', {})
195:
196: # Ensure the speed we set was accepted
197: result = self.vm.qmp('query-block-jobs')
198: self.assert_qmp(result, 'return[0]/device', 'drive0')
199: self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
200:
201: self.cancel_and_wait()
202:
203: # Check setting speed in block-stream works
204: result = self.vm.qmp('block-stream', device='drive0', speed=4 * 1024 * 1024)
205: self.assert_qmp(result, 'return', {})
206:
207: result = self.vm.qmp('query-block-jobs')
208: self.assert_qmp(result, 'return[0]/device', 'drive0')
209: self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
210:
211: self.cancel_and_wait()
212:
213: def test_set_speed_invalid(self):
214: self.assert_no_active_streams()
215:
216: result = self.vm.qmp('block-stream', device='drive0', speed=-1)
217: self.assert_qmp(result, 'error/class', 'InvalidParameter')
218: self.assert_qmp(result, 'error/data/name', 'speed')
219:
220: self.assert_no_active_streams()
221:
222: result = self.vm.qmp('block-stream', device='drive0')
223: self.assert_qmp(result, 'return', {})
224:
225: result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
226: self.assert_qmp(result, 'error/class', 'InvalidParameter')
227: self.assert_qmp(result, 'error/data/name', 'speed')
228:
229: self.cancel_and_wait()
230:
231: if __name__ == '__main__':
232: iotests.main(supported_fmts=['qcow2', 'qed'])
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.