Merge lp:~soren/nova/improve-smoketests into lp:~hudson-openstack/nova/trunk

Proposed by Soren Hansen
Status: Merged
Approved by: Soren Hansen
Approved revision: 825
Merged at revision: 835
Proposed branch: lp:~soren/nova/improve-smoketests
Merge into: lp:~hudson-openstack/nova/trunk
Diff against target: 641 lines (+362/-85)
9 files modified
nova/tests/api/openstack/test_servers.py (+0/-4)
run_tests.py (+2/-0)
smoketests/base.py (+16/-35)
smoketests/proxy.sh (+9/-2)
smoketests/public_network_smoketests.py (+0/-6)
smoketests/run_tests.py (+310/-0)
smoketests/test_admin.py (+0/-7)
smoketests/test_netadmin.py (+3/-14)
smoketests/test_sysadmin.py (+22/-17)
To merge this branch: bzr merge lp:~soren/nova/improve-smoketests
Reviewer Review Type Date Requested Status
Jesse Andrews (community) Approve
Vish Ishaya (community) Approve
Review via email: mp+53922@code.launchpad.net

Commit message

Make smoketests' exit code reveal whether they were succesful.

Adjust volume tests to check the exact size of the block device, instead of a rounded-off size of the resulting filesystem.

Make proxy.sh work with both variants of netcat.

Description of the change

With these couple of changes, my automated runs of both sysadmin_smoketests and netadmin_smoketests are now succesful.

To post a comment you must log in.
Revision history for this message
Vish Ishaya (vishvananda) wrote :

lgtm. Nice fixes

review: Approve
Revision history for this message
Jesse Andrews (anotherjesse) wrote :

lgtm!

I finally got hardware from RAX to run the smoketests on a real cluster after each deploy

review: Approve
Revision history for this message
OpenStack Infra (hudson-openstack) wrote :

Attempt to merge into lp:nova failed due to conflicts:

text conflict in smoketests/test_sysadmin.py

lp:~soren/nova/improve-smoketests updated
824. By Soren Hansen

Merge trunk

825. By Soren Hansen

pep8

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'nova/tests/api/openstack/test_servers.py'
2--- nova/tests/api/openstack/test_servers.py 2011-03-17 22:24:08 +0000
3+++ nova/tests/api/openstack/test_servers.py 2011-03-20 19:08:31 +0000
4@@ -1174,7 +1174,3 @@
5 server = dom.childNodes[0]
6 self.assertEquals(server.nodeName, 'server')
7 self.assertTrue(server.getAttribute('adminPass').startswith('fake'))
8-
9-
10-if __name__ == "__main__":
11- unittest.main()
12
13=== modified file 'run_tests.py'
14--- run_tests.py 2011-02-25 01:04:25 +0000
15+++ run_tests.py 2011-03-20 19:08:31 +0000
16@@ -60,6 +60,8 @@
17 import unittest
18 import sys
19
20+gettext.install('nova', unicode=1)
21+
22 from nose import config
23 from nose import core
24 from nose import result
25
26=== modified file 'smoketests/base.py'
27--- smoketests/base.py 2011-02-23 02:04:08 +0000
28+++ smoketests/base.py 2011-03-20 19:08:31 +0000
29@@ -31,17 +31,24 @@
30 SUITE_NAMES = '[image, instance, volume]'
31 FLAGS = flags.FLAGS
32 flags.DEFINE_string('suite', None, 'Specific test suite to run ' + SUITE_NAMES)
33+flags.DEFINE_integer('ssh_tries', 3, 'Numer of times to try ssh')
34 boto_v6 = None
35
36
37 class SmokeTestCase(unittest.TestCase):
38 def connect_ssh(self, ip, key_name):
39- # TODO(devcamcar): set a more reasonable connection timeout time
40 key = paramiko.RSAKey.from_private_key_file('/tmp/%s.pem' % key_name)
41- client = paramiko.SSHClient()
42- client.set_missing_host_key_policy(paramiko.WarningPolicy())
43- client.connect(ip, username='root', pkey=key)
44- return client
45+ tries = 0
46+ while(True):
47+ try:
48+ client = paramiko.SSHClient()
49+ client.set_missing_host_key_policy(paramiko.WarningPolicy())
50+ client.connect(ip, username='root', pkey=key, timeout=5)
51+ return client
52+ except (paramiko.AuthenticationException, paramiko.SSHException):
53+ tries += 1
54+ if tries == FLAGS.ssh_tries:
55+ raise
56
57 def can_ping(self, ip, command="ping"):
58 """Attempt to ping the specified IP, and give up after 1 second."""
59@@ -147,8 +154,8 @@
60 except:
61 pass
62
63- def bundle_image(self, image, kernel=False):
64- cmd = 'euca-bundle-image -i %s' % image
65+ def bundle_image(self, image, tempdir='/tmp', kernel=False):
66+ cmd = 'euca-bundle-image -i %s -d %s' % (image, tempdir)
67 if kernel:
68 cmd += ' --kernel true'
69 status, output = commands.getstatusoutput(cmd)
70@@ -157,9 +164,9 @@
71 raise Exception(output)
72 return True
73
74- def upload_image(self, bucket_name, image):
75+ def upload_image(self, bucket_name, image, tempdir='/tmp'):
76 cmd = 'euca-upload-bundle -b '
77- cmd += '%s -m /tmp/%s.manifest.xml' % (bucket_name, image)
78+ cmd += '%s -m %s/%s.manifest.xml' % (bucket_name, tempdir, image)
79 status, output = commands.getstatusoutput(cmd)
80 if status != 0:
81 print '%s -> \n %s' % (cmd, output)
82@@ -183,29 +190,3 @@
83 global TEST_DATA
84 self.conn = self.connection_for_env()
85 self.data = TEST_DATA
86-
87-
88-def run_tests(suites):
89- argv = FLAGS(sys.argv)
90- if FLAGS.use_ipv6:
91- global boto_v6
92- boto_v6 = __import__('boto_v6')
93-
94- if not os.getenv('EC2_ACCESS_KEY'):
95- print >> sys.stderr, 'Missing EC2 environment variables. Please ' \
96- 'source the appropriate novarc file before ' \
97- 'running this test.'
98- return 1
99-
100- if FLAGS.suite:
101- try:
102- suite = suites[FLAGS.suite]
103- except KeyError:
104- print >> sys.stderr, 'Available test suites:', \
105- ', '.join(suites.keys())
106- return 1
107-
108- unittest.TextTestRunner(verbosity=2).run(suite)
109- else:
110- for suite in suites.itervalues():
111- unittest.TextTestRunner(verbosity=2).run(suite)
112
113=== modified file 'smoketests/proxy.sh'
114--- smoketests/proxy.sh 2011-02-23 02:04:32 +0000
115+++ smoketests/proxy.sh 2011-03-20 19:08:31 +0000
116@@ -11,12 +11,19 @@
117 mkfifo backpipe1
118 mkfifo backpipe2
119
120+if nc -h 2>&1 | grep -i openbsd
121+then
122+ NC_LISTEN="nc -l"
123+else
124+ NC_LISTEN="nc -l -p"
125+fi
126+
127 # NOTE(vish): proxy metadata on port 80
128 while true; do
129- nc -l -p 80 0<backpipe1 | nc 169.254.169.254 80 1>backpipe1
130+ $NC_LISTEN 80 0<backpipe1 | nc 169.254.169.254 80 1>backpipe1
131 done &
132
133 # NOTE(vish): proxy google on port 8080
134 while true; do
135- nc -l -p 8080 0<backpipe2 | nc 74.125.19.99 80 1>backpipe2
136+ $NC_LISTEN 8080 0<backpipe2 | nc 74.125.19.99 80 1>backpipe2
137 done &
138
139=== modified file 'smoketests/public_network_smoketests.py'
140--- smoketests/public_network_smoketests.py 2011-02-23 02:04:08 +0000
141+++ smoketests/public_network_smoketests.py 2011-03-20 19:08:31 +0000
142@@ -19,10 +19,8 @@
143 import commands
144 import os
145 import random
146-import socket
147 import sys
148 import time
149-import unittest
150
151 # If ../nova/__init__.py exists, add ../ to Python search path, so that
152 # it will override what happens to be installed in /usr/(local/)lib/python...
153@@ -181,7 +179,3 @@
154 self.conn.delete_security_group(security_group_name)
155 if 'instance_id' in self.data:
156 self.conn.terminate_instances([self.data['instance_id']])
157-
158-if __name__ == "__main__":
159- suites = {'instance': unittest.makeSuite(InstanceTestsFromPublic)}
160- sys.exit(base.run_tests(suites))
161
162=== added file 'smoketests/run_tests.py'
163--- smoketests/run_tests.py 1970-01-01 00:00:00 +0000
164+++ smoketests/run_tests.py 2011-03-20 19:08:31 +0000
165@@ -0,0 +1,310 @@
166+#!/usr/bin/env python
167+# vim: tabstop=4 shiftwidth=4 softtabstop=4
168+
169+# Copyright 2010 United States Government as represented by the
170+# Administrator of the National Aeronautics and Space Administration.
171+# All Rights Reserved.
172+#
173+# Licensed under the Apache License, Version 2.0 (the "License");
174+# you may not use this file except in compliance with the License.
175+# You may obtain a copy of the License at
176+#
177+# http://www.apache.org/licenses/LICENSE-2.0
178+#
179+# Unless required by applicable law or agreed to in writing, software
180+# distributed under the License is distributed on an "AS IS" BASIS,
181+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
182+# See the License for the specific language governing permissions and
183+# limitations under the License.
184+
185+# Colorizer Code is borrowed from Twisted:
186+# Copyright (c) 2001-2010 Twisted Matrix Laboratories.
187+#
188+# Permission is hereby granted, free of charge, to any person obtaining
189+# a copy of this software and associated documentation files (the
190+# "Software"), to deal in the Software without restriction, including
191+# without limitation the rights to use, copy, modify, merge, publish,
192+# distribute, sublicense, and/or sell copies of the Software, and to
193+# permit persons to whom the Software is furnished to do so, subject to
194+# the following conditions:
195+#
196+# The above copyright notice and this permission notice shall be
197+# included in all copies or substantial portions of the Software.
198+#
199+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
200+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
201+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
202+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
203+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
204+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
205+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
206+"""Unittest runner for Nova.
207+
208+To run all tests
209+ python run_tests.py
210+
211+To run a single test:
212+ python run_tests.py test_compute:ComputeTestCase.test_run_terminate
213+
214+To run a single test module:
215+ python run_tests.py test_compute
216+
217+ or
218+
219+ python run_tests.py api.test_wsgi
220+
221+"""
222+
223+import gettext
224+import os
225+import unittest
226+import sys
227+
228+# If ../nova/__init__.py exists, add ../ to Python search path, so that
229+# it will override what happens to be installed in /usr/(local/)lib/python...
230+possible_topdir = os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]),
231+ os.pardir,
232+ os.pardir))
233+if os.path.exists(os.path.join(possible_topdir, 'nova', '__init__.py')):
234+ sys.path.insert(0, possible_topdir)
235+
236+
237+gettext.install('nova', unicode=1)
238+
239+from nose import config
240+from nose import core
241+from nose import result
242+
243+from smoketests import flags
244+FLAGS = flags.FLAGS
245+
246+
247+class _AnsiColorizer(object):
248+ """
249+ A colorizer is an object that loosely wraps around a stream, allowing
250+ callers to write text to the stream in a particular color.
251+
252+ Colorizer classes must implement C{supported()} and C{write(text, color)}.
253+ """
254+ _colors = dict(black=30, red=31, green=32, yellow=33,
255+ blue=34, magenta=35, cyan=36, white=37)
256+
257+ def __init__(self, stream):
258+ self.stream = stream
259+
260+ def supported(cls, stream=sys.stdout):
261+ """
262+ A class method that returns True if the current platform supports
263+ coloring terminal output using this method. Returns False otherwise.
264+ """
265+ if not stream.isatty():
266+ return False # auto color only on TTYs
267+ try:
268+ import curses
269+ except ImportError:
270+ return False
271+ else:
272+ try:
273+ try:
274+ return curses.tigetnum("colors") > 2
275+ except curses.error:
276+ curses.setupterm()
277+ return curses.tigetnum("colors") > 2
278+ except:
279+ raise
280+ # guess false in case of error
281+ return False
282+ supported = classmethod(supported)
283+
284+ def write(self, text, color):
285+ """
286+ Write the given text to the stream in the given color.
287+
288+ @param text: Text to be written to the stream.
289+
290+ @param color: A string label for a color. e.g. 'red', 'white'.
291+ """
292+ color = self._colors[color]
293+ self.stream.write('\x1b[%s;1m%s\x1b[0m' % (color, text))
294+
295+
296+class _Win32Colorizer(object):
297+ """
298+ See _AnsiColorizer docstring.
299+ """
300+ def __init__(self, stream):
301+ from win32console import GetStdHandle, STD_OUT_HANDLE, \
302+ FOREGROUND_RED, FOREGROUND_BLUE, FOREGROUND_GREEN, \
303+ FOREGROUND_INTENSITY
304+ red, green, blue, bold = (FOREGROUND_RED, FOREGROUND_GREEN,
305+ FOREGROUND_BLUE, FOREGROUND_INTENSITY)
306+ self.stream = stream
307+ self.screenBuffer = GetStdHandle(STD_OUT_HANDLE)
308+ self._colors = {
309+ 'normal': red | green | blue,
310+ 'red': red | bold,
311+ 'green': green | bold,
312+ 'blue': blue | bold,
313+ 'yellow': red | green | bold,
314+ 'magenta': red | blue | bold,
315+ 'cyan': green | blue | bold,
316+ 'white': red | green | blue | bold
317+ }
318+
319+ def supported(cls, stream=sys.stdout):
320+ try:
321+ import win32console
322+ screenBuffer = win32console.GetStdHandle(
323+ win32console.STD_OUT_HANDLE)
324+ except ImportError:
325+ return False
326+ import pywintypes
327+ try:
328+ screenBuffer.SetConsoleTextAttribute(
329+ win32console.FOREGROUND_RED |
330+ win32console.FOREGROUND_GREEN |
331+ win32console.FOREGROUND_BLUE)
332+ except pywintypes.error:
333+ return False
334+ else:
335+ return True
336+ supported = classmethod(supported)
337+
338+ def write(self, text, color):
339+ color = self._colors[color]
340+ self.screenBuffer.SetConsoleTextAttribute(color)
341+ self.stream.write(text)
342+ self.screenBuffer.SetConsoleTextAttribute(self._colors['normal'])
343+
344+
345+class _NullColorizer(object):
346+ """
347+ See _AnsiColorizer docstring.
348+ """
349+ def __init__(self, stream):
350+ self.stream = stream
351+
352+ def supported(cls, stream=sys.stdout):
353+ return True
354+ supported = classmethod(supported)
355+
356+ def write(self, text, color):
357+ self.stream.write(text)
358+
359+
360+class NovaTestResult(result.TextTestResult):
361+ def __init__(self, *args, **kw):
362+ result.TextTestResult.__init__(self, *args, **kw)
363+ self._last_case = None
364+ self.colorizer = None
365+ # NOTE(vish): reset stdout for the terminal check
366+ stdout = sys.stdout
367+ sys.stdout = sys.__stdout__
368+ for colorizer in [_Win32Colorizer, _AnsiColorizer, _NullColorizer]:
369+ if colorizer.supported():
370+ self.colorizer = colorizer(self.stream)
371+ break
372+ sys.stdout = stdout
373+
374+ def getDescription(self, test):
375+ return str(test)
376+
377+ # NOTE(vish): copied from unittest with edit to add color
378+ def addSuccess(self, test):
379+ unittest.TestResult.addSuccess(self, test)
380+ if self.showAll:
381+ self.colorizer.write("OK", 'green')
382+ self.stream.writeln()
383+ elif self.dots:
384+ self.stream.write('.')
385+ self.stream.flush()
386+
387+ # NOTE(vish): copied from unittest with edit to add color
388+ def addFailure(self, test, err):
389+ unittest.TestResult.addFailure(self, test, err)
390+ if self.showAll:
391+ self.colorizer.write("FAIL", 'red')
392+ self.stream.writeln()
393+ elif self.dots:
394+ self.stream.write('F')
395+ self.stream.flush()
396+
397+ # NOTE(vish): copied from nose with edit to add color
398+ def addError(self, test, err):
399+ """Overrides normal addError to add support for
400+ errorClasses. If the exception is a registered class, the
401+ error will be added to the list for that class, not errors.
402+ """
403+ stream = getattr(self, 'stream', None)
404+ ec, ev, tb = err
405+ try:
406+ exc_info = self._exc_info_to_string(err, test)
407+ except TypeError:
408+ # 2.3 compat
409+ exc_info = self._exc_info_to_string(err)
410+ for cls, (storage, label, isfail) in self.errorClasses.items():
411+ if result.isclass(ec) and issubclass(ec, cls):
412+ if isfail:
413+ test.passed = False
414+ storage.append((test, exc_info))
415+ # Might get patched into a streamless result
416+ if stream is not None:
417+ if self.showAll:
418+ message = [label]
419+ detail = result._exception_detail(err[1])
420+ if detail:
421+ message.append(detail)
422+ stream.writeln(": ".join(message))
423+ elif self.dots:
424+ stream.write(label[:1])
425+ return
426+ self.errors.append((test, exc_info))
427+ test.passed = False
428+ if stream is not None:
429+ if self.showAll:
430+ self.colorizer.write("ERROR", 'red')
431+ self.stream.writeln()
432+ elif self.dots:
433+ stream.write('E')
434+
435+ def startTest(self, test):
436+ unittest.TestResult.startTest(self, test)
437+ current_case = test.test.__class__.__name__
438+
439+ if self.showAll:
440+ if current_case != self._last_case:
441+ self.stream.writeln(current_case)
442+ self._last_case = current_case
443+
444+ self.stream.write(
445+ ' %s' % str(test.test._testMethodName).ljust(60))
446+ self.stream.flush()
447+
448+
449+class NovaTestRunner(core.TextTestRunner):
450+ def _makeResult(self):
451+ return NovaTestResult(self.stream,
452+ self.descriptions,
453+ self.verbosity,
454+ self.config)
455+
456+
457+if __name__ == '__main__':
458+ if not os.getenv('EC2_ACCESS_KEY'):
459+ print _('Missing EC2 environment variables. Please ' \
460+ 'source the appropriate novarc file before ' \
461+ 'running this test.')
462+ sys.exit(1)
463+
464+ argv = FLAGS(sys.argv)
465+ testdir = os.path.abspath("./")
466+ c = config.Config(stream=sys.stdout,
467+ env=os.environ,
468+ verbosity=3,
469+ workingDir=testdir,
470+ plugins=core.DefaultPluginManager())
471+
472+ runner = NovaTestRunner(stream=c.stream,
473+ verbosity=c.verbosity,
474+ config=c)
475+ sys.exit(not core.run(config=c, testRunner=runner, argv=argv))
476
477=== renamed file 'smoketests/admin_smoketests.py' => 'smoketests/test_admin.py'
478--- smoketests/admin_smoketests.py 2011-01-12 08:47:54 +0000
479+++ smoketests/test_admin.py 2011-03-20 19:08:31 +0000
480@@ -35,10 +35,7 @@
481 from smoketests import base
482
483
484-SUITE_NAMES = '[user]'
485-
486 FLAGS = flags.FLAGS
487-flags.DEFINE_string('suite', None, 'Specific test suite to run ' + SUITE_NAMES)
488
489 # TODO(devamcar): Use random tempfile
490 ZIP_FILENAME = '/tmp/nova-me-x509.zip'
491@@ -92,7 +89,3 @@
492 os.remove(ZIP_FILENAME)
493 except:
494 pass
495-
496-if __name__ == "__main__":
497- suites = {'user': unittest.makeSuite(UserTests)}
498- sys.exit(base.run_tests(suites))
499
500=== renamed file 'smoketests/netadmin_smoketests.py' => 'smoketests/test_netadmin.py'
501--- smoketests/netadmin_smoketests.py 2011-02-23 02:04:32 +0000
502+++ smoketests/test_netadmin.py 2011-03-20 19:08:31 +0000
503@@ -21,7 +21,6 @@
504 import random
505 import sys
506 import time
507-import unittest
508
509 # If ../nova/__init__.py exists, add ../ to Python search path, so that
510 # it will override what happens to be installed in /usr/(local/)lib/python...
511@@ -74,8 +73,10 @@
512 groups = self.conn.get_all_security_groups(['default'])
513 for rule in groups[0].rules:
514 if (rule.ip_protocol == 'tcp' and
515- rule.from_port <= 22 and rule.to_port >= 22):
516+ int(rule.from_port) <= 22 and
517+ int(rule.to_port) >= 22):
518 ssh_authorized = True
519+ break
520 if not ssh_authorized:
521 self.conn.authorize_security_group('default',
522 ip_protocol='tcp',
523@@ -137,11 +138,6 @@
524 if not self.wait_for_running(self.data['instance']):
525 self.fail('instance failed to start')
526 self.data['instance'].update()
527- if not self.wait_for_ping(self.data['instance'].private_dns_name):
528- self.fail('could not ping instance')
529- if not self.wait_for_ssh(self.data['instance'].private_dns_name,
530- TEST_KEY):
531- self.fail('could not ssh to instance')
532
533 def test_003_can_authorize_security_group_ingress(self):
534 self.assertTrue(self.conn.authorize_security_group(TEST_GROUP,
535@@ -185,10 +181,3 @@
536 self.assertFalse(TEST_GROUP in [group.name for group in groups])
537 self.conn.terminate_instances([self.data['instance'].id])
538 self.assertTrue(self.conn.release_address(self.data['public_ip']))
539-
540-
541-if __name__ == "__main__":
542- suites = {'address': unittest.makeSuite(AddressTests),
543- 'security_group': unittest.makeSuite(SecurityGroupTests)
544- }
545- sys.exit(base.run_tests(suites))
546
547=== renamed file 'smoketests/sysadmin_smoketests.py' => 'smoketests/test_sysadmin.py'
548--- smoketests/sysadmin_smoketests.py 2011-03-18 01:54:51 +0000
549+++ smoketests/test_sysadmin.py 2011-03-20 19:08:31 +0000
550@@ -16,12 +16,12 @@
551 # License for the specific language governing permissions and limitations
552 # under the License.
553
554-import commands
555 import os
556 import random
557 import sys
558 import time
559-import unittest
560+import tempfile
561+import shutil
562
563 # If ../nova/__init__.py exists, add ../ to Python search path, so that
564 # it will override what happens to be installed in /usr/(local/)lib/python...
565@@ -48,10 +48,18 @@
566
567 class ImageTests(base.UserSmokeTestCase):
568 def test_001_can_bundle_image(self):
569- self.assertTrue(self.bundle_image(FLAGS.bundle_image))
570+ self.data['tempdir'] = tempfile.mkdtemp()
571+ self.assertTrue(self.bundle_image(FLAGS.bundle_image,
572+ self.data['tempdir']))
573
574 def test_002_can_upload_image(self):
575- self.assertTrue(self.upload_image(TEST_BUCKET, FLAGS.bundle_image))
576+ try:
577+ self.assertTrue(self.upload_image(TEST_BUCKET,
578+ FLAGS.bundle_image,
579+ self.data['tempdir']))
580+ finally:
581+ if os.path.exists(self.data['tempdir']):
582+ shutil.rmtree(self.data['tempdir'])
583
584 def test_003_can_register_image(self):
585 image_id = self.conn.register_image('%s/%s.manifest.xml' %
586@@ -192,7 +200,7 @@
587 self.assertEqual(volume.size, 1)
588 self.data['volume'] = volume
589 # Give network time to find volume.
590- time.sleep(10)
591+ time.sleep(5)
592
593 def test_002_can_attach_volume(self):
594 volume = self.data['volume']
595@@ -205,6 +213,8 @@
596 else:
597 self.fail('cannot attach volume with state %s' % volume.status)
598
599+ # Give volume some time to be ready.
600+ time.sleep(5)
601 volume.attach(self.data['instance'].id, self.device)
602
603 # wait
604@@ -219,7 +229,7 @@
605 self.assertTrue(volume.status.startswith('in-use'))
606
607 # Give instance time to recognize volume.
608- time.sleep(10)
609+ time.sleep(5)
610
611 def test_003_can_mount_volume(self):
612 ip = self.data['instance'].private_dns_name
613@@ -256,12 +266,13 @@
614 ip = self.data['instance'].private_dns_name
615 conn = self.connect_ssh(ip, TEST_KEY)
616 stdin, stdout, stderr = conn.exec_command(
617- "df -h | grep %s | awk {'print $2'}" % self.device)
618- out = stdout.read()
619+ "blockdev --getsize64 %s" % self.device)
620+ out = stdout.read().strip()
621 conn.close()
622- if not out.strip() == '1007.9M':
623- self.fail('Volume is not the right size: %s %s' %
624- (out, stderr.read()))
625+ expected_size = 1024 * 1024 * 1024
626+ self.assertEquals('%s' % (expected_size,), out,
627+ 'Volume is not the right size: %s %s. Expected: %s' %
628+ (out, stderr.read(), expected_size))
629
630 def test_006_me_can_umount_volume(self):
631 ip = self.data['instance'].private_dns_name
632@@ -284,9 +295,3 @@
633 def test_999_tearDown(self):
634 self.conn.terminate_instances([self.data['instance'].id])
635 self.conn.delete_key_pair(TEST_KEY)
636-
637-if __name__ == "__main__":
638- suites = {'image': unittest.makeSuite(ImageTests),
639- 'instance': unittest.makeSuite(InstanceTests),
640- 'volume': unittest.makeSuite(VolumeTests)}
641- sys.exit(base.run_tests(suites))