summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLucian Petrut <lpetrut@cloudbasesolutions.com>2019-01-28 12:56:49 +0000
committerLucian Petrut <lpetrut@cloudbasesolutions.com>2019-03-13 16:41:11 +0200
commit98b7ef195c18640b0a036e2ab0f03ec0cb29174d (patch)
tree4fea534a3f30c8103d3e25d2d1ba9f75aad3ebd1
parentf0dc2454dadeba04a17263d64574d786cdfcbc17 (diff)
Allow glance tests to run on Windows
In order to run the unit and functional Glance tests on Windows, we have to: * avoid monkey patching the os module on Windows (which causes Popen to fail) * update sqlite connection URL * avoid os.fork, not available on Windows. * we'll use subprocess.Popen when spinning up http servers. * for the really simple ones defined in the test helpers, we'll just use threads * do not attempt to connect to '0.0.0.0', use '127.0.0.1' instead * some tests aren't properly skipped (xattr ones), so we're covering that as well * skip log rotation test, we can't move in-use files. Log rotation can be performed by the log handler itself. * expect an exception when hitting connection timeouts * avoid installing unavailable test requirements (xattr, pysendfile) * pin the instance creation timestamp. some tests that deal with markers rely on ordering, which can be flipped if the timestamps are identical (can happen in case of resources created one after the other, not sure yet if this happens really fast or the clock isn't accurate enough). * add a few seconds to some timeouts (much needed when running the tests in VMs). blueprint windows-support Change-Id: Ife69f56a3f9f4d81e1e2e47fde4778efd490938f
Notes
Notes (review): Code-Review+2: Abhishek Kekane <akekane@redhat.com> Review-Priority+1: Abhishek Kekane <akekane@redhat.com> Code-Review+2: Erno Kuvaja <jokke@usr.fi> Workflow+1: Erno Kuvaja <jokke@usr.fi> Verified+2: Zuul Submitted-by: Zuul Submitted-at: Thu, 14 Mar 2019 15:30:41 +0000 Reviewed-on: https://review.openstack.org/634007 Project: openstack/glance Branch: refs/heads/master
-rw-r--r--glance/registry/client/v2/api.py1
-rw-r--r--glance/tests/__init__.py10
-rw-r--r--glance/tests/functional/__init__.py225
-rw-r--r--glance/tests/functional/db/base.py5
-rw-r--r--glance/tests/functional/serial/test_scrubber.py2
-rw-r--r--glance/tests/functional/test_cache_middleware.py26
-rw-r--r--glance/tests/functional/test_client_exceptions.py1
-rw-r--r--glance/tests/functional/test_logging.py6
-rw-r--r--glance/tests/functional/test_sqlite.py2
-rw-r--r--glance/tests/functional/test_wsgi.py8
-rw-r--r--glance/tests/functional/v2/test_images.py63
-rw-r--r--glance/tests/integration/v2/base.py7
-rw-r--r--glance/tests/unit/async_/flows/test_import.py4
-rw-r--r--glance/tests/unit/base.py6
-rw-r--r--glance/tests/unit/common/test_wsgi.py5
-rw-r--r--glance/tests/unit/test_image_cache.py7
-rw-r--r--glance/tests/unit/v2/test_images_resource.py28
-rw-r--r--glance/tests/unit/v2/test_registry_client.py2
-rw-r--r--glance/tests/utils.py35
19 files changed, 302 insertions, 141 deletions
diff --git a/glance/registry/client/v2/api.py b/glance/registry/client/v2/api.py
index 69a8016..0a2397e 100644
--- a/glance/registry/client/v2/api.py
+++ b/glance/registry/client/v2/api.py
@@ -32,7 +32,6 @@ CONF = cfg.CONF
32_registry_client = 'glance.registry.client' 32_registry_client = 'glance.registry.client'
33CONF.import_opt('registry_client_protocol', _registry_client) 33CONF.import_opt('registry_client_protocol', _registry_client)
34CONF.import_opt('registry_client_key_file', _registry_client) 34CONF.import_opt('registry_client_key_file', _registry_client)
35CONF.import_opt('registry_client_cert_file', _registry_client)
36CONF.import_opt('registry_client_ca_file', _registry_client) 35CONF.import_opt('registry_client_ca_file', _registry_client)
37CONF.import_opt('registry_client_insecure', _registry_client) 36CONF.import_opt('registry_client_insecure', _registry_client)
38CONF.import_opt('registry_client_timeout', _registry_client) 37CONF.import_opt('registry_client_timeout', _registry_client)
diff --git a/glance/tests/__init__.py b/glance/tests/__init__.py
index 724b7e9..eab8985 100644
--- a/glance/tests/__init__.py
+++ b/glance/tests/__init__.py
@@ -13,6 +13,8 @@
13# License for the specific language governing permissions and limitations 13# License for the specific language governing permissions and limitations
14# under the License. 14# under the License.
15 15
16import os
17
16import eventlet 18import eventlet
17# NOTE(jokke): As per the eventlet commit 19# NOTE(jokke): As per the eventlet commit
18# b756447bab51046dfc6f1e0e299cc997ab343701 there's circular import happening 20# b756447bab51046dfc6f1e0e299cc997ab343701 there's circular import happening
@@ -20,7 +22,13 @@ import eventlet
20# before calling monkey_patch(). This is solved in eventlet 0.22.0 but we 22# before calling monkey_patch(). This is solved in eventlet 0.22.0 but we
21# need to address it before that is widely used around. 23# need to address it before that is widely used around.
22eventlet.hubs.get_hub() 24eventlet.hubs.get_hub()
23eventlet.patcher.monkey_patch() 25
26if os.name == 'nt':
27 # eventlet monkey patching the os module causes subprocess.Popen to fail
28 # on Windows when using pipes due to missing non-blocking IO support.
29 eventlet.patcher.monkey_patch(os=False)
30else:
31 eventlet.patcher.monkey_patch()
24 32
25# See http://code.google.com/p/python-nose/issues/detail?id=373 33# See http://code.google.com/p/python-nose/issues/detail?id=373
26# The code below enables tests to work with i18n _() blocks 34# The code below enables tests to work with i18n _() blocks
diff --git a/glance/tests/functional/__init__.py b/glance/tests/functional/__init__.py
index ac42b1d..ff19b93 100644
--- a/glance/tests/functional/__init__.py
+++ b/glance/tests/functional/__init__.py
@@ -21,6 +21,7 @@ and Registry server, grabbing the logs of each, cleaning up pidfiles,
21and spinning down the servers. 21and spinning down the servers.
22""" 22"""
23 23
24import abc
24import atexit 25import atexit
25import datetime 26import datetime
26import errno 27import errno
@@ -28,12 +29,16 @@ import os
28import platform 29import platform
29import shutil 30import shutil
30import signal 31import signal
32import six
31import socket 33import socket
34import subprocess
32import sys 35import sys
33import tempfile 36import tempfile
34import time 37import time
35 38
36import fixtures 39import fixtures
40from os_win import utilsfactory as os_win_utilsfactory
41from oslo_config import cfg
37from oslo_serialization import jsonutils 42from oslo_serialization import jsonutils
38# NOTE(jokke): simplified transition to py3, behaves like py2 xrange 43# NOTE(jokke): simplified transition to py3, behaves like py2 xrange
39from six.moves import range 44from six.moves import range
@@ -48,8 +53,18 @@ from glance.tests import utils as test_utils
48execute, get_unused_port = test_utils.execute, test_utils.get_unused_port 53execute, get_unused_port = test_utils.execute, test_utils.get_unused_port
49tracecmd_osmap = {'Linux': 'strace', 'FreeBSD': 'truss'} 54tracecmd_osmap = {'Linux': 'strace', 'FreeBSD': 'truss'}
50 55
56if os.name == 'nt':
57 SQLITE_CONN_TEMPLATE = 'sqlite:///%s/tests.sqlite'
58else:
59 SQLITE_CONN_TEMPLATE = 'sqlite:////%s/tests.sqlite'
51 60
52class Server(object): 61
62CONF = cfg.CONF
63CONF.import_opt('registry_host', 'glance.registry')
64
65
66@six.add_metaclass(abc.ABCMeta)
67class BaseServer(object):
53 """ 68 """
54 Class used to easily manage starting and stopping 69 Class used to easily manage starting and stopping
55 a server during functional test runs. 70 a server during functional test runs.
@@ -131,6 +146,78 @@ class Server(object):
131 146
132 return self.conf_file_name, overridden 147 return self.conf_file_name, overridden
133 148
149 @abc.abstractmethod
150 def start(self, expect_exit=True, expected_exitcode=0, **kwargs):
151 pass
152
153 @abc.abstractmethod
154 def stop(self):
155 pass
156
157 def reload(self, expect_exit=True, expected_exitcode=0, **kwargs):
158 """
159 Start and stop the service to reload
160
161 Any kwargs passed to this method will override the configuration
162 value in the conf file used in starting the servers.
163 """
164 self.stop()
165 return self.start(expect_exit=expect_exit,
166 expected_exitcode=expected_exitcode, **kwargs)
167
168 def create_database(self):
169 """Create database if required for this server"""
170 if self.needs_database:
171 conf_dir = os.path.join(self.test_dir, 'etc')
172 utils.safe_mkdirs(conf_dir)
173 conf_filepath = os.path.join(conf_dir, 'glance-manage.conf')
174
175 with open(conf_filepath, 'w') as conf_file:
176 conf_file.write('[DEFAULT]\n')
177 conf_file.write('sql_connection = %s' % self.sql_connection)
178 conf_file.flush()
179
180 glance_db_env = 'GLANCE_DB_TEST_SQLITE_FILE'
181 if glance_db_env in os.environ:
182 # use the empty db created and cached as a tempfile
183 # instead of spending the time creating a new one
184 db_location = os.environ[glance_db_env]
185 shutil.copyfile(db_location, "%s/tests.sqlite" % self.test_dir)
186 else:
187 cmd = ('%s -m glance.cmd.manage --config-file %s db sync' %
188 (sys.executable, conf_filepath))
189 execute(cmd, no_venv=self.no_venv, exec_env=self.exec_env,
190 expect_exit=True)
191
192 # copy the clean db to a temp location so that it
193 # can be reused for future tests
194 (osf, db_location) = tempfile.mkstemp()
195 os.close(osf)
196 shutil.copyfile('%s/tests.sqlite' % self.test_dir, db_location)
197 os.environ[glance_db_env] = db_location
198
199 # cleanup the temp file when the test suite is
200 # complete
201 def _delete_cached_db():
202 try:
203 os.remove(os.environ[glance_db_env])
204 except Exception:
205 glance_tests.logger.exception(
206 "Error cleaning up the file %s" %
207 os.environ[glance_db_env])
208 atexit.register(_delete_cached_db)
209
210 def dump_log(self):
211 if not self.log_file:
212 return "log_file not set for {name}".format(name=self.server_name)
213 elif not os.path.exists(self.log_file):
214 return "{log_file} for {name} did not exist".format(
215 log_file=self.log_file, name=self.server_name)
216 with open(self.log_file, 'r') as fptr:
217 return fptr.read().strip()
218
219
220class PosixServer(BaseServer):
134 def start(self, expect_exit=True, expected_exitcode=0, **kwargs): 221 def start(self, expect_exit=True, expected_exitcode=0, **kwargs):
135 """ 222 """
136 Starts the server. 223 Starts the server.
@@ -190,81 +277,92 @@ class Server(object):
190 self.sock = None 277 self.sock = None
191 return (rc, '', '') 278 return (rc, '', '')
192 279
193 def reload(self, expect_exit=True, expected_exitcode=0, **kwargs): 280 def stop(self):
194 """ 281 """
195 Start and stop the service to reload 282 Spin down the server.
283 """
284 if not self.process_pid:
285 raise Exception('why is this being called? %s' % self.server_name)
286
287 if self.stop_kill:
288 os.kill(self.process_pid, signal.SIGTERM)
289 rc = test_utils.wait_for_fork(self.process_pid, raise_error=False)
290 return (rc, '', '')
291
292
293class Win32Server(BaseServer):
294 def __init__(self, *args, **kwargs):
295 super(Win32Server, self).__init__(*args, **kwargs)
296
297 self._processutils = os_win_utilsfactory.get_processutils()
298
299 def start(self, expect_exit=True, expected_exitcode=0, **kwargs):
300 """
301 Starts the server.
196 302
197 Any kwargs passed to this method will override the configuration 303 Any kwargs passed to this method will override the configuration
198 value in the conf file used in starting the servers. 304 value in the conf file used in starting the servers.
199 """ 305 """
200 self.stop()
201 return self.start(expect_exit=expect_exit,
202 expected_exitcode=expected_exitcode, **kwargs)
203 306
204 def create_database(self): 307 # Ensure the configuration file is written
205 """Create database if required for this server""" 308 self.write_conf(**kwargs)
206 if self.needs_database:
207 conf_dir = os.path.join(self.test_dir, 'etc')
208 utils.safe_mkdirs(conf_dir)
209 conf_filepath = os.path.join(conf_dir, 'glance-manage.conf')
210 309
211 with open(conf_filepath, 'w') as conf_file: 310 self.create_database()
212 conf_file.write('[DEFAULT]\n')
213 conf_file.write('sql_connection = %s' % self.sql_connection)
214 conf_file.flush()
215 311
216 glance_db_env = 'GLANCE_DB_TEST_SQLITE_FILE' 312 cmd = ("%(server_module)s --config-file %(conf_file_name)s"
217 if glance_db_env in os.environ: 313 % {"server_module": self.server_module,
218 # use the empty db created and cached as a tempfile 314 "conf_file_name": self.conf_file_name})
219 # instead of spending the time creating a new one 315 cmd = "%s -m %s" % (sys.executable, cmd)
220 db_location = os.environ[glance_db_env]
221 os.system('cp %s %s/tests.sqlite'
222 % (db_location, self.test_dir))
223 else:
224 cmd = ('%s -m glance.cmd.manage --config-file %s db sync' %
225 (sys.executable, conf_filepath))
226 execute(cmd, no_venv=self.no_venv, exec_env=self.exec_env,
227 expect_exit=True)
228 316
229 # copy the clean db to a temp location so that it 317 # Passing socket objects on Windows is a bit more cumbersome.
230 # can be reused for future tests 318 # We don't really have to do it.
231 (osf, db_location) = tempfile.mkstemp() 319 if self.sock:
232 os.close(osf) 320 self.sock.close()
233 os.system('cp %s/tests.sqlite %s' 321 self.sock = None
234 % (self.test_dir, db_location))
235 os.environ[glance_db_env] = db_location
236 322
237 # cleanup the temp file when the test suite is 323 self.process = subprocess.Popen(
238 # complete 324 cmd,
239 def _delete_cached_db(): 325 env=self.exec_env)
240 try: 326 self.process_pid = self.process.pid
241 os.remove(os.environ[glance_db_env]) 327
242 except Exception: 328 try:
243 glance_tests.logger.exception( 329 self.job_handle = self._processutils.kill_process_on_job_close(
244 "Error cleaning up the file %s" % 330 self.process_pid)
245 os.environ[glance_db_env]) 331 except Exception:
246 atexit.register(_delete_cached_db) 332 # Could not associate child process with a job, killing it.
333 self.process.kill()
334 raise
335
336 self.stop_kill = not expect_exit
337 if self.pid_file:
338 pf = open(self.pid_file, 'w')
339 pf.write('%d\n' % self.process_pid)
340 pf.close()
341
342 rc = 0
343 if expect_exit:
344 self.process.communicate()
345 rc = self.process.returncode
346
347 return (rc, '', '')
247 348
248 def stop(self): 349 def stop(self):
249 """ 350 """
250 Spin down the server. 351 Spin down the server.
251 """ 352 """
252 if not self.process_pid: 353 if not self.process_pid:
253 raise Exception('why is this being called? %s' % self.server_name) 354 raise Exception('Server "%s" process not running.'
355 % self.server_name)
254 356
255 if self.stop_kill: 357 if self.stop_kill:
256 os.kill(self.process_pid, signal.SIGTERM) 358 self.process.terminate()
257 rc = test_utils.wait_for_fork(self.process_pid, raise_error=False) 359 return (0, '', '')
258 return (rc, '', '')
259 360
260 def dump_log(self): 361
261 if not self.log_file: 362if os.name == 'nt':
262 return "log_file not set for {name}".format(name=self.server_name) 363 Server = Win32Server
263 elif not os.path.exists(self.log_file): 364else:
264 return "{log_file} for {name} did not exist".format( 365 Server = PosixServer
265 log_file=self.log_file, name=self.server_name)
266 with open(self.log_file, 'r') as fptr:
267 return fptr.read().strip()
268 366
269 367
270class ApiServer(Server): 368class ApiServer(Server):
@@ -305,7 +403,7 @@ class ApiServer(Server):
305 self.disable_path = None 403 self.disable_path = None
306 404
307 self.needs_database = True 405 self.needs_database = True
308 default_sql_connection = 'sqlite:////%s/tests.sqlite' % self.test_dir 406 default_sql_connection = SQLITE_CONN_TEMPLATE % self.test_dir
309 self.sql_connection = os.environ.get('GLANCE_TEST_SQL_CONNECTION', 407 self.sql_connection = os.environ.get('GLANCE_TEST_SQL_CONNECTION',
310 default_sql_connection) 408 default_sql_connection)
311 self.data_api = kwargs.get("data_api", 409 self.data_api = kwargs.get("data_api",
@@ -488,7 +586,7 @@ class ApiServerForMultipleBackend(Server):
488 self.disable_path = None 586 self.disable_path = None
489 587
490 self.needs_database = True 588 self.needs_database = True
491 default_sql_connection = 'sqlite:////%s/tests.sqlite' % self.test_dir 589 default_sql_connection = SQLITE_CONN_TEMPLATE % self.test_dir
492 self.sql_connection = os.environ.get('GLANCE_TEST_SQL_CONNECTION', 590 self.sql_connection = os.environ.get('GLANCE_TEST_SQL_CONNECTION',
493 default_sql_connection) 591 default_sql_connection)
494 self.data_api = kwargs.get("data_api", 592 self.data_api = kwargs.get("data_api",
@@ -646,7 +744,7 @@ class RegistryServer(Server):
646 self.server_module = 'glance.cmd.%s' % self.server_name 744 self.server_module = 'glance.cmd.%s' % self.server_name
647 745
648 self.needs_database = True 746 self.needs_database = True
649 default_sql_connection = 'sqlite:////%s/tests.sqlite' % self.test_dir 747 default_sql_connection = SQLITE_CONN_TEMPLATE % self.test_dir
650 self.sql_connection = os.environ.get('GLANCE_TEST_SQL_CONNECTION', 748 self.sql_connection = os.environ.get('GLANCE_TEST_SQL_CONNECTION',
651 default_sql_connection) 749 default_sql_connection)
652 750
@@ -732,7 +830,7 @@ class ScrubberDaemon(Server):
732 self.metadata_encryption_key = "012345678901234567890123456789ab" 830 self.metadata_encryption_key = "012345678901234567890123456789ab"
733 self.lock_path = self.test_dir 831 self.lock_path = self.test_dir
734 832
735 default_sql_connection = 'sqlite:////%s/tests.sqlite' % self.test_dir 833 default_sql_connection = SQLITE_CONN_TEMPLATE % self.test_dir
736 self.sql_connection = os.environ.get('GLANCE_TEST_SQL_CONNECTION', 834 self.sql_connection = os.environ.get('GLANCE_TEST_SQL_CONNECTION',
737 default_sql_connection) 835 default_sql_connection)
738 self.policy_file = policy_file 836 self.policy_file = policy_file
@@ -790,6 +888,11 @@ class FunctionalTest(test_utils.BaseTestCase):
790 # False in the test SetUps that do not require Scrubber to run. 888 # False in the test SetUps that do not require Scrubber to run.
791 self.include_scrubber = True 889 self.include_scrubber = True
792 890
891 # The clients will try to connect to this address. Let's make sure
892 # we're not using the default '0.0.0.0'
893 self.config(bind_host='127.0.0.1',
894 registry_host='127.0.0.1')
895
793 self.tracecmd = tracecmd_osmap.get(platform.system()) 896 self.tracecmd = tracecmd_osmap.get(platform.system())
794 897
795 conf_dir = os.path.join(self.test_dir, 'etc') 898 conf_dir = os.path.join(self.test_dir, 'etc')
diff --git a/glance/tests/functional/db/base.py b/glance/tests/functional/db/base.py
index 6d8a4dd..d74db9a 100644
--- a/glance/tests/functional/db/base.py
+++ b/glance/tests/functional/db/base.py
@@ -17,6 +17,7 @@
17 17
18import copy 18import copy
19import datetime 19import datetime
20import time
20import uuid 21import uuid
21 22
22import mock 23import mock
@@ -1340,6 +1341,10 @@ class DriverTests(object):
1340 'deleted': False} 1341 'deleted': False}
1341 self.assertEqual(expected, member) 1342 self.assertEqual(expected, member)
1342 1343
1344 # The clock may not be very accurate, for which reason we may
1345 # get identical timestamps.
1346 time.sleep(0.01)
1347
1343 member = self.db_api.image_member_update(self.context, 1348 member = self.db_api.image_member_update(self.context,
1344 member_id, 1349 member_id,
1345 {'status': 'accepted'}) 1350 {'status': 'accepted'})
diff --git a/glance/tests/functional/serial/test_scrubber.py b/glance/tests/functional/serial/test_scrubber.py
index f00504b..4f0a5ae 100644
--- a/glance/tests/functional/serial/test_scrubber.py
+++ b/glance/tests/functional/serial/test_scrubber.py
@@ -346,6 +346,8 @@ class TestScrubber(functional.FunctionalTest):
346 def test_scrubber_restore_image_with_daemon_running(self): 346 def test_scrubber_restore_image_with_daemon_running(self):
347 self.cleanup() 347 self.cleanup()
348 self.scrubber_daemon.start(daemon=True) 348 self.scrubber_daemon.start(daemon=True)
349 # Give the scrubber some time to start.
350 time.sleep(5)
349 351
350 exe_cmd = "%s -m glance.cmd.scrubber" % sys.executable 352 exe_cmd = "%s -m glance.cmd.scrubber" % sys.executable
351 cmd = ("%s --restore fake_image_id" % exe_cmd) 353 cmd = ("%s --restore fake_image_id" % exe_cmd)
diff --git a/glance/tests/functional/test_cache_middleware.py b/glance/tests/functional/test_cache_middleware.py
index 178115a..f6ef309 100644
--- a/glance/tests/functional/test_cache_middleware.py
+++ b/glance/tests/functional/test_cache_middleware.py
@@ -45,7 +45,7 @@ class BaseCacheMiddlewareTest(object):
45 self.start_servers(**self.__dict__.copy()) 45 self.start_servers(**self.__dict__.copy())
46 46
47 # Add an image and verify success 47 # Add an image and verify success
48 path = "http://%s:%d/v2/images" % ("0.0.0.0", self.api_port) 48 path = "http://%s:%d/v2/images" % ("127.0.0.1", self.api_port)
49 http = httplib2.Http() 49 http = httplib2.Http()
50 headers = {'content-type': 'application/json'} 50 headers = {'content-type': 'application/json'}
51 image_entity = { 51 image_entity = {
@@ -61,7 +61,7 @@ class BaseCacheMiddlewareTest(object):
61 data = jsonutils.loads(content) 61 data = jsonutils.loads(content)
62 image_id = data['id'] 62 image_id = data['id']
63 63
64 path = "http://%s:%d/v2/images/%s/file" % ("0.0.0.0", self.api_port, 64 path = "http://%s:%d/v2/images/%s/file" % ("127.0.0.1", self.api_port,
65 image_id) 65 image_id)
66 headers = {'content-type': 'application/octet-stream'} 66 headers = {'content-type': 'application/octet-stream'}
67 image_data = "*" * FIVE_KB 67 image_data = "*" * FIVE_KB
@@ -87,7 +87,7 @@ class BaseCacheMiddlewareTest(object):
87 87
88 # Now, we delete the image from the server and verify that 88 # Now, we delete the image from the server and verify that
89 # the image cache no longer contains the deleted image 89 # the image cache no longer contains the deleted image
90 path = "http://%s:%d/v2/images/%s" % ("0.0.0.0", self.api_port, 90 path = "http://%s:%d/v2/images/%s" % ("127.0.0.1", self.api_port,
91 image_id) 91 image_id)
92 http = httplib2.Http() 92 http = httplib2.Http()
93 response, content = http.request(path, 'DELETE') 93 response, content = http.request(path, 'DELETE')
@@ -107,7 +107,7 @@ class BaseCacheMiddlewareTest(object):
107 self.start_servers(**self.__dict__.copy()) 107 self.start_servers(**self.__dict__.copy())
108 108
109 # Add an image and verify success 109 # Add an image and verify success
110 path = "http://%s:%d/v2/images" % ("0.0.0.0", self.api_port) 110 path = "http://%s:%d/v2/images" % ("127.0.0.1", self.api_port)
111 http = httplib2.Http() 111 http = httplib2.Http()
112 headers = {'content-type': 'application/json'} 112 headers = {'content-type': 'application/json'}
113 image_entity = { 113 image_entity = {
@@ -123,7 +123,7 @@ class BaseCacheMiddlewareTest(object):
123 data = jsonutils.loads(content) 123 data = jsonutils.loads(content)
124 image_id = data['id'] 124 image_id = data['id']
125 125
126 path = "http://%s:%d/v2/images/%s/file" % ("0.0.0.0", self.api_port, 126 path = "http://%s:%d/v2/images/%s/file" % ("127.0.0.1", self.api_port,
127 image_id) 127 image_id)
128 headers = {'content-type': 'application/octet-stream'} 128 headers = {'content-type': 'application/octet-stream'}
129 image_data = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 129 image_data = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
@@ -187,7 +187,7 @@ class BaseCacheMiddlewareTest(object):
187 self.start_servers(**self.__dict__.copy()) 187 self.start_servers(**self.__dict__.copy())
188 188
189 # Add an image and verify success 189 # Add an image and verify success
190 path = "http://%s:%d/v2/images" % ("0.0.0.0", self.api_port) 190 path = "http://%s:%d/v2/images" % ("127.0.0.1", self.api_port)
191 http = httplib2.Http() 191 http = httplib2.Http()
192 headers = {'content-type': 'application/json'} 192 headers = {'content-type': 'application/json'}
193 image_entity = { 193 image_entity = {
@@ -203,7 +203,7 @@ class BaseCacheMiddlewareTest(object):
203 data = jsonutils.loads(content) 203 data = jsonutils.loads(content)
204 image_id = data['id'] 204 image_id = data['id']
205 205
206 path = "http://%s:%d/v2/images/%s/file" % ("0.0.0.0", self.api_port, 206 path = "http://%s:%d/v2/images/%s/file" % ("127.0.0.1", self.api_port,
207 image_id) 207 image_id)
208 headers = {'content-type': 'application/octet-stream'} 208 headers = {'content-type': 'application/octet-stream'}
209 image_data = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 209 image_data = b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
@@ -283,7 +283,7 @@ class BaseCacheMiddlewareTest(object):
283 self.start_servers(**self.__dict__.copy()) 283 self.start_servers(**self.__dict__.copy())
284 284
285 # Add an image and verify success 285 # Add an image and verify success
286 path = "http://%s:%d/v2/images" % ("0.0.0.0", self.api_port) 286 path = "http://%s:%d/v2/images" % ("127.0.0.1", self.api_port)
287 http = httplib2.Http() 287 http = httplib2.Http()
288 headers = {'content-type': 'application/json'} 288 headers = {'content-type': 'application/json'}
289 image_entity = { 289 image_entity = {
@@ -299,7 +299,7 @@ class BaseCacheMiddlewareTest(object):
299 data = jsonutils.loads(content) 299 data = jsonutils.loads(content)
300 image_id = data['id'] 300 image_id = data['id']
301 301
302 path = "http://%s:%d/v2/images/%s/file" % ("0.0.0.0", self.api_port, 302 path = "http://%s:%d/v2/images/%s/file" % ("127.0.0.1", self.api_port,
303 image_id) 303 image_id)
304 headers = {'content-type': 'application/octet-stream'} 304 headers = {'content-type': 'application/octet-stream'}
305 image_data = "*" * FIVE_KB 305 image_data = "*" * FIVE_KB
@@ -324,7 +324,7 @@ class BaseCacheMiddlewareTest(object):
324 324
325 # Now, we delete the image from the server and verify that 325 # Now, we delete the image from the server and verify that
326 # the image cache no longer contains the deleted image 326 # the image cache no longer contains the deleted image
327 path = "http://%s:%d/v2/images/%s" % ("0.0.0.0", self.api_port, 327 path = "http://%s:%d/v2/images/%s" % ("127.0.0.1", self.api_port,
328 image_id) 328 image_id)
329 http = httplib2.Http() 329 http = httplib2.Http()
330 response, content = http.request(path, 'DELETE') 330 response, content = http.request(path, 'DELETE')
@@ -347,7 +347,7 @@ class TestImageCacheXattr(functional.FunctionalTest,
347 filesystem) 347 filesystem)
348 """ 348 """
349 if getattr(self, 'disabled', False): 349 if getattr(self, 'disabled', False):
350 return 350 raise self.skipException('Test disabled.')
351 351
352 if not getattr(self, 'inited', False): 352 if not getattr(self, 'inited', False):
353 try: 353 try:
@@ -356,7 +356,7 @@ class TestImageCacheXattr(functional.FunctionalTest,
356 self.inited = True 356 self.inited = True
357 self.disabled = True 357 self.disabled = True
358 self.disabled_message = ("python-xattr not installed.") 358 self.disabled_message = ("python-xattr not installed.")
359 return 359 raise self.skipException(self.disabled_message)
360 360
361 self.inited = True 361 self.inited = True
362 self.disabled = False 362 self.disabled = False
@@ -370,7 +370,7 @@ class TestImageCacheXattr(functional.FunctionalTest,
370 self.inited = True 370 self.inited = True
371 self.disabled = True 371 self.disabled = True
372 self.disabled_message = ("filesystem does not support xattr") 372 self.disabled_message = ("filesystem does not support xattr")
373 return 373 raise self.skipException(self.disabled_message)
374 374
375 def tearDown(self): 375 def tearDown(self):
376 super(TestImageCacheXattr, self).tearDown() 376 super(TestImageCacheXattr, self).tearDown()
diff --git a/glance/tests/functional/test_client_exceptions.py b/glance/tests/functional/test_client_exceptions.py
index 72489b9..0b8b5ed 100644
--- a/glance/tests/functional/test_client_exceptions.py
+++ b/glance/tests/functional/test_client_exceptions.py
@@ -28,7 +28,6 @@ from glance.common import wsgi
28from glance.tests import functional 28from glance.tests import functional
29from glance.tests import utils 29from glance.tests import utils
30 30
31
32eventlet.patcher.monkey_patch(socket=True) 31eventlet.patcher.monkey_patch(socket=True)
33 32
34 33
diff --git a/glance/tests/functional/test_logging.py b/glance/tests/functional/test_logging.py
index 135d560..842b3a7 100644
--- a/glance/tests/functional/test_logging.py
+++ b/glance/tests/functional/test_logging.py
@@ -85,6 +85,12 @@ class TestLogging(functional.FunctionalTest):
85 """ 85 """
86 Test that we notice when our log file has been rotated 86 Test that we notice when our log file has been rotated
87 """ 87 """
88
89 # Moving in-use files is not supported on Windows.
90 # The log handler itself may be configured to rotate files.
91 if os.name == 'nt':
92 raise self.skipException("Unsupported platform.")
93
88 self.cleanup() 94 self.cleanup()
89 self.start_servers() 95 self.start_servers()
90 96
diff --git a/glance/tests/functional/test_sqlite.py b/glance/tests/functional/test_sqlite.py
index 8957573..524a142 100644
--- a/glance/tests/functional/test_sqlite.py
+++ b/glance/tests/functional/test_sqlite.py
@@ -32,7 +32,7 @@ class TestSqlite(functional.FunctionalTest):
32 self.cleanup() 32 self.cleanup()
33 self.start_servers(**self.__dict__.copy()) 33 self.start_servers(**self.__dict__.copy())
34 34
35 cmd = "sqlite3 tests.sqlite '.schema'" 35 cmd = 'sqlite3 tests.sqlite ".schema"'
36 exitcode, out, err = execute(cmd, raise_error=True) 36 exitcode, out, err = execute(cmd, raise_error=True)
37 37
38 self.assertNotIn('BIGINT', out) 38 self.assertNotIn('BIGINT', out)
diff --git a/glance/tests/functional/test_wsgi.py b/glance/tests/functional/test_wsgi.py
index e375e3b..6c6b887 100644
--- a/glance/tests/functional/test_wsgi.py
+++ b/glance/tests/functional/test_wsgi.py
@@ -15,6 +15,7 @@
15 15
16"""Tests for `glance.wsgi`.""" 16"""Tests for `glance.wsgi`."""
17 17
18import os
18import socket 19import socket
19import time 20import time
20 21
@@ -52,4 +53,9 @@ class TestWSGIServer(testtools.TestCase):
52 # Should succeed - no timeout 53 # Should succeed - no timeout
53 self.assertIn(greetings, get_request()) 54 self.assertIn(greetings, get_request())
54 # Should fail - connection timed out so we get nothing from the server 55 # Should fail - connection timed out so we get nothing from the server
55 self.assertFalse(get_request(delay=1.1)) 56 if os.name == 'nt':
57 self.assertRaises(ConnectionAbortedError,
58 get_request,
59 delay=1.1)
60 else:
61 self.assertFalse(get_request(delay=1.1))
diff --git a/glance/tests/functional/v2/test_images.py b/glance/tests/functional/v2/test_images.py
index 7d6d933..cb56692 100644
--- a/glance/tests/functional/v2/test_images.py
+++ b/glance/tests/functional/v2/test_images.py
@@ -14,8 +14,6 @@
14# under the License. 14# under the License.
15 15
16import hashlib 16import hashlib
17import os
18import signal
19import uuid 17import uuid
20 18
21from oslo_serialization import jsonutils 19from oslo_serialization import jsonutils
@@ -48,16 +46,17 @@ class TestImages(functional.FunctionalTest):
48 for i in range(3): 46 for i in range(3):
49 ret = test_utils.start_http_server("foo_image_id%d" % i, 47 ret = test_utils.start_http_server("foo_image_id%d" % i,
50 "foo_image%d" % i) 48 "foo_image%d" % i)
51 setattr(self, 'http_server%d_pid' % i, ret[0]) 49 setattr(self, 'http_server%d' % i, ret[1])
52 setattr(self, 'http_port%d' % i, ret[1]) 50 setattr(self, 'http_port%d' % i, ret[2])
53 self.api_server.use_user_token = True 51 self.api_server.use_user_token = True
54 self.api_server.send_identity_credentials = True 52 self.api_server.send_identity_credentials = True
55 53
56 def tearDown(self): 54 def tearDown(self):
57 for i in range(3): 55 for i in range(3):
58 pid = getattr(self, 'http_server%d_pid' % i, None) 56 httpd = getattr(self, 'http_server%d' % i, None)
59 if pid: 57 if httpd:
60 os.kill(pid, signal.SIGKILL) 58 httpd.shutdown()
59 httpd.server_close()
61 60
62 super(TestImages, self).tearDown() 61 super(TestImages, self).tearDown()
63 62
@@ -219,7 +218,7 @@ class TestImages(functional.FunctionalTest):
219 func_utils.wait_for_status(request_path=path, 218 func_utils.wait_for_status(request_path=path,
220 request_headers=self._headers(), 219 request_headers=self._headers(),
221 status='active', 220 status='active',
222 max_sec=2, 221 max_sec=10,
223 delay_sec=0.2) 222 delay_sec=0.2)
224 expect_c = six.text_type(hashlib.md5(image_data).hexdigest()) 223 expect_c = six.text_type(hashlib.md5(image_data).hexdigest())
225 expect_h = six.text_type(hashlib.sha512(image_data).hexdigest()) 224 expect_h = six.text_type(hashlib.sha512(image_data).hexdigest())
@@ -343,7 +342,7 @@ class TestImages(functional.FunctionalTest):
343 }) 342 })
344 343
345 # Start http server locally 344 # Start http server locally
346 pid, port = test_utils.start_standalone_http_server() 345 thread, httpd, port = test_utils.start_standalone_http_server()
347 346
348 image_data_uri = 'http://localhost:%s/' % port 347 image_data_uri = 'http://localhost:%s/' % port
349 data = jsonutils.dumps({'method': { 348 data = jsonutils.dumps({'method': {
@@ -373,7 +372,8 @@ class TestImages(functional.FunctionalTest):
373 status='active') 372 status='active')
374 373
375 # kill the local http server 374 # kill the local http server
376 os.kill(pid, signal.SIGKILL) 375 httpd.shutdown()
376 httpd.server_close()
377 377
378 # Deleting image should work 378 # Deleting image should work
379 path = self._url('/v2/images/%s' % image_id) 379 path = self._url('/v2/images/%s' % image_id)
@@ -1609,8 +1609,8 @@ class TestImages(functional.FunctionalTest):
1609 path = self._url('/v2/images/%s' % image_id) 1609 path = self._url('/v2/images/%s' % image_id)
1610 media_type = 'application/openstack-images-v2.1-json-patch' 1610 media_type = 'application/openstack-images-v2.1-json-patch'
1611 headers = self._headers({'content-type': media_type}) 1611 headers = self._headers({'content-type': media_type})
1612 http_server_pid, http_port = test_utils.start_http_server(image_id, 1612 thread, httpd, http_port = test_utils.start_http_server(image_id,
1613 "image-1") 1613 "image-1")
1614 values = [{'url': 'http://127.0.0.1:%s/image-1' % http_port, 1614 values = [{'url': 'http://127.0.0.1:%s/image-1' % http_port,
1615 'metadata': {'idx': '0'}}] 1615 'metadata': {'idx': '0'}}]
1616 doc = [{'op': 'replace', 1616 doc = [{'op': 'replace',
@@ -1627,7 +1627,8 @@ class TestImages(functional.FunctionalTest):
1627 self.assertEqual(http.OK, response.status_code) 1627 self.assertEqual(http.OK, response.status_code)
1628 1628
1629 # Stop http server used to update image location 1629 # Stop http server used to update image location
1630 os.kill(http_server_pid, signal.SIGKILL) 1630 httpd.shutdown()
1631 httpd.server_close()
1631 1632
1632 # Download an image should raise HTTPServiceUnavailable 1633 # Download an image should raise HTTPServiceUnavailable
1633 path = self._url('/v2/images/%s/file' % image_id) 1634 path = self._url('/v2/images/%s/file' % image_id)
@@ -3895,14 +3896,15 @@ class TestImageLocationSelectionStrategy(functional.FunctionalTest):
3895 for i in range(3): 3896 for i in range(3):
3896 ret = test_utils.start_http_server("foo_image_id%d" % i, 3897 ret = test_utils.start_http_server("foo_image_id%d" % i,
3897 "foo_image%d" % i) 3898 "foo_image%d" % i)
3898 setattr(self, 'http_server%d_pid' % i, ret[0]) 3899 setattr(self, 'http_server%d' % i, ret[1])
3899 setattr(self, 'http_port%d' % i, ret[1]) 3900 setattr(self, 'http_port%d' % i, ret[2])
3900 3901
3901 def tearDown(self): 3902 def tearDown(self):
3902 for i in range(3): 3903 for i in range(3):
3903 pid = getattr(self, 'http_server%d_pid' % i, None) 3904 httpd = getattr(self, 'http_server%d' % i, None)
3904 if pid: 3905 if httpd:
3905 os.kill(pid, signal.SIGKILL) 3906 httpd.shutdown()
3907 httpd.server_close()
3906 3908
3907 super(TestImageLocationSelectionStrategy, self).tearDown() 3909 super(TestImageLocationSelectionStrategy, self).tearDown()
3908 3910
@@ -4453,14 +4455,15 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
4453 for i in range(3): 4455 for i in range(3):
4454 ret = test_utils.start_http_server("foo_image_id%d" % i, 4456 ret = test_utils.start_http_server("foo_image_id%d" % i,
4455 "foo_image%d" % i) 4457 "foo_image%d" % i)
4456 setattr(self, 'http_server%d_pid' % i, ret[0]) 4458 setattr(self, 'http_server%d' % i, ret[1])
4457 setattr(self, 'http_port%d' % i, ret[1]) 4459 setattr(self, 'http_port%d' % i, ret[2])
4458 4460
4459 def tearDown(self): 4461 def tearDown(self):
4460 for i in range(3): 4462 for i in range(3):
4461 pid = getattr(self, 'http_server%d_pid' % i, None) 4463 httpd = getattr(self, 'http_server%d' % i, None)
4462 if pid: 4464 if httpd:
4463 os.kill(pid, signal.SIGKILL) 4465 httpd.shutdown()
4466 httpd.server_close()
4464 4467
4465 super(TestImagesMultipleBackend, self).tearDown() 4468 super(TestImagesMultipleBackend, self).tearDown()
4466 4469
@@ -4605,7 +4608,7 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
4605 func_utils.wait_for_status(request_path=path, 4608 func_utils.wait_for_status(request_path=path,
4606 request_headers=self._headers(), 4609 request_headers=self._headers(),
4607 status='active', 4610 status='active',
4608 max_sec=2, 4611 max_sec=15,
4609 delay_sec=0.2) 4612 delay_sec=0.2)
4610 expect_c = six.text_type(hashlib.md5(image_data).hexdigest()) 4613 expect_c = six.text_type(hashlib.md5(image_data).hexdigest())
4611 expect_h = six.text_type(hashlib.sha512(image_data).hexdigest()) 4614 expect_h = six.text_type(hashlib.sha512(image_data).hexdigest())
@@ -4766,7 +4769,7 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
4766 func_utils.wait_for_status(request_path=path, 4769 func_utils.wait_for_status(request_path=path,
4767 request_headers=self._headers(), 4770 request_headers=self._headers(),
4768 status='active', 4771 status='active',
4769 max_sec=2, 4772 max_sec=15,
4770 delay_sec=0.2) 4773 delay_sec=0.2)
4771 expect_c = six.text_type(hashlib.md5(image_data).hexdigest()) 4774 expect_c = six.text_type(hashlib.md5(image_data).hexdigest())
4772 expect_h = six.text_type(hashlib.sha512(image_data).hexdigest()) 4775 expect_h = six.text_type(hashlib.sha512(image_data).hexdigest())
@@ -4909,7 +4912,7 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
4909 }) 4912 })
4910 4913
4911 # Start http server locally 4914 # Start http server locally
4912 pid, port = test_utils.start_standalone_http_server() 4915 thread, httpd, port = test_utils.start_standalone_http_server()
4913 4916
4914 image_data_uri = 'http://localhost:%s/' % port 4917 image_data_uri = 'http://localhost:%s/' % port
4915 data = jsonutils.dumps({'method': { 4918 data = jsonutils.dumps({'method': {
@@ -4939,7 +4942,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
4939 status='active') 4942 status='active')
4940 4943
4941 # kill the local http server 4944 # kill the local http server
4942 os.kill(pid, signal.SIGKILL) 4945 httpd.shutdown()
4946 httpd.server_close()
4943 # Ensure image is created in default backend 4947 # Ensure image is created in default backend
4944 path = self._url('/v2/images/%s' % image_id) 4948 path = self._url('/v2/images/%s' % image_id)
4945 response = requests.get(path, headers=self._headers()) 4949 response = requests.get(path, headers=self._headers())
@@ -5069,7 +5073,7 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
5069 }) 5073 })
5070 5074
5071 # Start http server locally 5075 # Start http server locally
5072 pid, port = test_utils.start_standalone_http_server() 5076 thread, httpd, port = test_utils.start_standalone_http_server()
5073 5077
5074 image_data_uri = 'http://localhost:%s/' % port 5078 image_data_uri = 'http://localhost:%s/' % port
5075 data = jsonutils.dumps({'method': { 5079 data = jsonutils.dumps({'method': {
@@ -5099,7 +5103,8 @@ class TestImagesMultipleBackend(functional.MultipleBackendFunctionalTest):
5099 status='active') 5103 status='active')
5100 5104
5101 # kill the local http server 5105 # kill the local http server
5102 os.kill(pid, signal.SIGKILL) 5106 httpd.shutdown()
5107 httpd.server_close()
5103 5108
5104 # Ensure image is created in different backend 5109 # Ensure image is created in different backend
5105 path = self._url('/v2/images/%s' % image_id) 5110 path = self._url('/v2/images/%s' % image_id)
diff --git a/glance/tests/integration/v2/base.py b/glance/tests/integration/v2/base.py
index 2277102..6bcd0c8 100644
--- a/glance/tests/integration/v2/base.py
+++ b/glance/tests/integration/v2/base.py
@@ -15,6 +15,7 @@
15 15
16import atexit 16import atexit
17import os.path 17import os.path
18import shutil
18import tempfile 19import tempfile
19 20
20import fixtures 21import fixtures
@@ -163,8 +164,7 @@ class ApiTest(test_utils.BaseTestCase):
163 # use the empty db created and cached as a tempfile 164 # use the empty db created and cached as a tempfile
164 # instead of spending the time creating a new one 165 # instead of spending the time creating a new one
165 db_location = os.environ[glance_db_env] 166 db_location = os.environ[glance_db_env]
166 test_utils.execute('cp %s %s/tests.sqlite' 167 shutil.copyfile(db_location, "%s/tests.sqlite" % self.test_dir)
167 % (db_location, self.test_dir))
168 else: 168 else:
169 test_utils.db_sync() 169 test_utils.db_sync()
170 170
@@ -172,8 +172,7 @@ class ApiTest(test_utils.BaseTestCase):
172 # can be reused for future tests 172 # can be reused for future tests
173 (osf, db_location) = tempfile.mkstemp() 173 (osf, db_location) = tempfile.mkstemp()
174 os.close(osf) 174 os.close(osf)
175 test_utils.execute('cp %s/tests.sqlite %s' 175 shutil.copyfile('%s/tests.sqlite' % self.test_dir, db_location)
176 % (self.test_dir, db_location))
177 os.environ[glance_db_env] = db_location 176 os.environ[glance_db_env] = db_location
178 177
179 # cleanup the temp file when the test suite is 178 # cleanup the temp file when the test suite is
diff --git a/glance/tests/unit/async_/flows/test_import.py b/glance/tests/unit/async_/flows/test_import.py
index e3d1a4a..4998f6e 100644
--- a/glance/tests/unit/async_/flows/test_import.py
+++ b/glance/tests/unit/async_/flows/test_import.py
@@ -135,8 +135,8 @@ class TestImportTask(test_utils.BaseTestCase):
135 self.assertFalse(os.path.exists(tmp_image_path)) 135 self.assertFalse(os.path.exists(tmp_image_path))
136 self.assertTrue(os.path.exists(image_path)) 136 self.assertTrue(os.path.exists(image_path))
137 self.assertEqual(1, len(list(self.image.locations))) 137 self.assertEqual(1, len(list(self.image.locations)))
138 self.assertEqual("file://%s/%s" % (self.test_dir, 138 self.assertEqual("file://%s%s%s" % (self.test_dir, os.sep,
139 self.image.image_id), 139 self.image.image_id),
140 self.image.locations[0]['url']) 140 self.image.locations[0]['url'])
141 141
142 self._assert_qemu_process_limits(tmock) 142 self._assert_qemu_process_limits(tmock)
diff --git a/glance/tests/unit/base.py b/glance/tests/unit/base.py
index cc35342..de8a246 100644
--- a/glance/tests/unit/base.py
+++ b/glance/tests/unit/base.py
@@ -108,11 +108,9 @@ class IsolatedUnitTest(StoreClearingUnitTest):
108 DEFAULT_REGISTRY_PORT = 9191 108 DEFAULT_REGISTRY_PORT = 9191
109 DEFAULT_API_PORT = 9292 109 DEFAULT_API_PORT = 9292
110 110
111 if (client.port == DEFAULT_API_PORT and 111 if client.port == DEFAULT_API_PORT:
112 client.host == '0.0.0.0'):
113 return stubs.FakeGlanceConnection 112 return stubs.FakeGlanceConnection
114 elif (client.port == DEFAULT_REGISTRY_PORT and 113 elif client.port == DEFAULT_REGISTRY_PORT:
115 client.host == '0.0.0.0'):
116 return stubs.FakeRegistryConnection(registry=self.registry) 114 return stubs.FakeRegistryConnection(registry=self.registry)
117 115
118 self.patcher = mock.patch( 116 self.patcher = mock.patch(
diff --git a/glance/tests/unit/common/test_wsgi.py b/glance/tests/unit/common/test_wsgi.py
index 794873d..38ec612 100644
--- a/glance/tests/unit/common/test_wsgi.py
+++ b/glance/tests/unit/common/test_wsgi.py
@@ -588,8 +588,11 @@ class ServerTest(test_utils.BaseTestCase):
588 keepalive=False, 588 keepalive=False,
589 socket_timeout=900) 589 socket_timeout=900)
590 590
591 def test_number_of_workers(self): 591 def test_number_of_workers_posix(self):
592 """Ensure the number of workers matches num cpus limited to 8.""" 592 """Ensure the number of workers matches num cpus limited to 8."""
593 if os.name == 'nt':
594 raise self.skipException("Unsupported platform.")
595
593 def pid(): 596 def pid():
594 i = 1 597 i = 1
595 while True: 598 while True:
diff --git a/glance/tests/unit/test_image_cache.py b/glance/tests/unit/test_image_cache.py
index 8226d60..9890b52 100644
--- a/glance/tests/unit/test_image_cache.py
+++ b/glance/tests/unit/test_image_cache.py
@@ -281,6 +281,7 @@ class ImageCacheTestCase(object):
281 self.assertEqual(['0', '1', '2'], 281 self.assertEqual(['0', '1', '2'],
282 self.cache.get_queued_images()) 282 self.cache.get_queued_images())
283 283
284 @skip_if_disabled
284 def test_open_for_write_good(self): 285 def test_open_for_write_good(self):
285 """ 286 """
286 Test to see if open_for_write works in normal case 287 Test to see if open_for_write works in normal case
@@ -300,6 +301,7 @@ class ImageCacheTestCase(object):
300 self.assertFalse(os.path.exists(incomplete_file_path)) 301 self.assertFalse(os.path.exists(incomplete_file_path))
301 self.assertFalse(os.path.exists(invalid_file_path)) 302 self.assertFalse(os.path.exists(invalid_file_path))
302 303
304 @skip_if_disabled
303 def test_open_for_write_with_exception(self): 305 def test_open_for_write_with_exception(self):
304 """ 306 """
305 Test to see if open_for_write works in a failure case for each driver 307 Test to see if open_for_write works in a failure case for each driver
@@ -324,6 +326,7 @@ class ImageCacheTestCase(object):
324 self.assertFalse(os.path.exists(incomplete_file_path)) 326 self.assertFalse(os.path.exists(incomplete_file_path))
325 self.assertTrue(os.path.exists(invalid_file_path)) 327 self.assertTrue(os.path.exists(invalid_file_path))
326 328
329 @skip_if_disabled
327 def test_caching_iterator(self): 330 def test_caching_iterator(self):
328 """ 331 """
329 Test to see if the caching iterator interacts properly with the driver 332 Test to see if the caching iterator interacts properly with the driver
@@ -351,6 +354,7 @@ class ImageCacheTestCase(object):
351 self.assertFalse(os.path.exists(incomplete_file_path)) 354 self.assertFalse(os.path.exists(incomplete_file_path))
352 self.assertFalse(os.path.exists(invalid_file_path)) 355 self.assertFalse(os.path.exists(invalid_file_path))
353 356
357 @skip_if_disabled
354 def test_caching_iterator_handles_backend_failure(self): 358 def test_caching_iterator_handles_backend_failure(self):
355 """ 359 """
356 Test that when the backend fails, caching_iter does not continue trying 360 Test that when the backend fails, caching_iter does not continue trying
@@ -374,6 +378,7 @@ class ImageCacheTestCase(object):
374 # make sure bad image was not cached 378 # make sure bad image was not cached
375 self.assertFalse(self.cache.is_cached(image_id)) 379 self.assertFalse(self.cache.is_cached(image_id))
376 380
381 @skip_if_disabled
377 def test_caching_iterator_falloffend(self): 382 def test_caching_iterator_falloffend(self):
378 """ 383 """
379 Test to see if the caching iterator interacts properly with the driver 384 Test to see if the caching iterator interacts properly with the driver
@@ -402,6 +407,7 @@ class ImageCacheTestCase(object):
402 self.assertFalse(os.path.exists(incomplete_file_path)) 407 self.assertFalse(os.path.exists(incomplete_file_path))
403 self.assertTrue(os.path.exists(invalid_file_path)) 408 self.assertTrue(os.path.exists(invalid_file_path))
404 409
410 @skip_if_disabled
405 def test_gate_caching_iter_good_checksum(self): 411 def test_gate_caching_iter_good_checksum(self):
406 image = b"12345678990abcdefghijklmnop" 412 image = b"12345678990abcdefghijklmnop"
407 image_id = 123 413 image_id = 123
@@ -417,6 +423,7 @@ class ImageCacheTestCase(object):
417 # checksum is valid, fake image should be cached: 423 # checksum is valid, fake image should be cached:
418 self.assertTrue(cache.is_cached(image_id)) 424 self.assertTrue(cache.is_cached(image_id))
419 425
426 @skip_if_disabled
420 def test_gate_caching_iter_bad_checksum(self): 427 def test_gate_caching_iter_bad_checksum(self):
421 image = b"12345678990abcdefghijklmnop" 428 image = b"12345678990abcdefghijklmnop"
422 image_id = 123 429 image_id = 123
diff --git a/glance/tests/unit/v2/test_images_resource.py b/glance/tests/unit/v2/test_images_resource.py
index 45b7951..542c103 100644
--- a/glance/tests/unit/v2/test_images_resource.py
+++ b/glance/tests/unit/v2/test_images_resource.py
@@ -165,7 +165,9 @@ class TestImagesController(base.IsolatedUnitTest):
165 'metadata': {}, 'status': 'active'}], 165 'metadata': {}, 'status': 'active'}],
166 disk_format='raw', 166 disk_format='raw',
167 container_format='bare', 167 container_format='bare',
168 status='active'), 168 status='active',
169 created_at=DATETIME,
170 updated_at=DATETIME),
169 _db_fixture(UUID2, owner=TENANT1, checksum=CHKSUM1, 171 _db_fixture(UUID2, owner=TENANT1, checksum=CHKSUM1,
170 os_hash_algo=FAKEHASHALGO, os_hash_value=MULTIHASH2, 172 os_hash_algo=FAKEHASHALGO, os_hash_value=MULTIHASH2,
171 name='2', size=512, virtual_size=2048, 173 name='2', size=512, virtual_size=2048,
@@ -175,13 +177,19 @@ class TestImagesController(base.IsolatedUnitTest):
175 status='active', 177 status='active',
176 tags=['redhat', '64bit', 'power'], 178 tags=['redhat', '64bit', 'power'],
177 properties={'hypervisor_type': 'kvm', 'foo': 'bar', 179 properties={'hypervisor_type': 'kvm', 'foo': 'bar',
178 'bar': 'foo'}), 180 'bar': 'foo'},
181 created_at=DATETIME + datetime.timedelta(seconds=1),
182 updated_at=DATETIME + datetime.timedelta(seconds=1)),
179 _db_fixture(UUID3, owner=TENANT3, checksum=CHKSUM1, 183 _db_fixture(UUID3, owner=TENANT3, checksum=CHKSUM1,
180 os_hash_algo=FAKEHASHALGO, os_hash_value=MULTIHASH2, 184 os_hash_algo=FAKEHASHALGO, os_hash_value=MULTIHASH2,
181 name='3', size=512, virtual_size=2048, 185 name='3', size=512, virtual_size=2048,
182 visibility='public', tags=['windows', '64bit', 'x86']), 186 visibility='public', tags=['windows', '64bit', 'x86'],
187 created_at=DATETIME + datetime.timedelta(seconds=2),
188 updated_at=DATETIME + datetime.timedelta(seconds=2)),
183 _db_fixture(UUID4, owner=TENANT4, name='4', 189 _db_fixture(UUID4, owner=TENANT4, name='4',
184 size=1024, virtual_size=3072), 190 size=1024, virtual_size=3072,
191 created_at=DATETIME + datetime.timedelta(seconds=3),
192 updated_at=DATETIME + datetime.timedelta(seconds=3)),
185 ] 193 ]
186 [self.db.image_create(None, image) for image in self.images] 194 [self.db.image_create(None, image) for image in self.images]
187 195
@@ -4649,7 +4657,8 @@ class TestMultiImagesController(base.MultiIsolatedUnitTest):
4649 'metadata': {}, 'status': 'active'}], 4657 'metadata': {}, 'status': 'active'}],
4650 disk_format='raw', 4658 disk_format='raw',
4651 container_format='bare', 4659 container_format='bare',
4652 status='active'), 4660 status='active',
4661 created_at=DATETIME),
4653 _db_fixture(UUID2, owner=TENANT1, checksum=CHKSUM1, 4662 _db_fixture(UUID2, owner=TENANT1, checksum=CHKSUM1,
4654 name='2', size=512, virtual_size=2048, 4663 name='2', size=512, virtual_size=2048,
4655 visibility='public', 4664 visibility='public',
@@ -4658,12 +4667,15 @@ class TestMultiImagesController(base.MultiIsolatedUnitTest):
4658 status='active', 4667 status='active',
4659 tags=['redhat', '64bit', 'power'], 4668 tags=['redhat', '64bit', 'power'],
4660 properties={'hypervisor_type': 'kvm', 'foo': 'bar', 4669 properties={'hypervisor_type': 'kvm', 'foo': 'bar',
4661 'bar': 'foo'}), 4670 'bar': 'foo'},
4671 created_at=DATETIME + datetime.timedelta(seconds=1)),
4662 _db_fixture(UUID3, owner=TENANT3, checksum=CHKSUM1, 4672 _db_fixture(UUID3, owner=TENANT3, checksum=CHKSUM1,
4663 name='3', size=512, virtual_size=2048, 4673 name='3', size=512, virtual_size=2048,
4664 visibility='public', tags=['windows', '64bit', 'x86']), 4674 visibility='public', tags=['windows', '64bit', 'x86'],
4675 created_at=DATETIME + datetime.timedelta(seconds=2)),
4665 _db_fixture(UUID4, owner=TENANT4, name='4', 4676 _db_fixture(UUID4, owner=TENANT4, name='4',
4666 size=1024, virtual_size=3072), 4677 size=1024, virtual_size=3072,
4678 created_at=DATETIME + datetime.timedelta(seconds=3)),
4667 ] 4679 ]
4668 [self.db.image_create(None, image) for image in self.images] 4680 [self.db.image_create(None, image) for image in self.images]
4669 4681
diff --git a/glance/tests/unit/v2/test_registry_client.py b/glance/tests/unit/v2/test_registry_client.py
index 2401dd5..96d3380 100644
--- a/glance/tests/unit/v2/test_registry_client.py
+++ b/glance/tests/unit/v2/test_registry_client.py
@@ -79,7 +79,7 @@ class TestRegistryV2Client(base.IsolatedUnitTest,
79 created_at=uuid2_time)] 79 created_at=uuid2_time)]
80 self.destroy_fixtures() 80 self.destroy_fixtures()
81 self.create_fixtures() 81 self.create_fixtures()
82 self.client = rclient.RegistryClient("0.0.0.0") 82 self.client = rclient.RegistryClient("127.0.0.1")
83 83
84 def tearDown(self): 84 def tearDown(self):
85 """Clear the test environment""" 85 """Clear the test environment"""
diff --git a/glance/tests/utils.py b/glance/tests/utils.py
index 140a772..e8cff70 100644
--- a/glance/tests/utils.py
+++ b/glance/tests/utils.py
@@ -22,6 +22,7 @@ import shlex
22import shutil 22import shutil
23import socket 23import socket
24import subprocess 24import subprocess
25import threading
25 26
26from alembic import command as alembic_command 27from alembic import command as alembic_command
27import fixtures 28import fixtures
@@ -176,7 +177,11 @@ class depends_on_exe(object):
176 177
177 def __call__(self, func): 178 def __call__(self, func):
178 def _runner(*args, **kw): 179 def _runner(*args, **kw):
179 cmd = 'which %s' % self.exe 180 if os.name != 'nt':
181 cmd = 'which %s' % self.exe
182 else:
183 cmd = 'where.exe', '%s' % self.exe
184
180 exitcode, out, err = execute(cmd, raise_error=False) 185 exitcode, out, err = execute(cmd, raise_error=False)
181 if exitcode != 0: 186 if exitcode != 0:
182 args[0].disabled_message = 'test requires exe: %s' % self.exe 187 args[0].disabled_message = 'test requires exe: %s' % self.exe
@@ -325,7 +330,11 @@ def execute(cmd,
325 path_ext = [os.path.join(os.getcwd(), 'bin')] 330 path_ext = [os.path.join(os.getcwd(), 'bin')]
326 331
327 # Also jack in the path cmd comes from, if it's absolute 332 # Also jack in the path cmd comes from, if it's absolute
328 args = shlex.split(cmd) 333 if os.name != 'nt':
334 args = shlex.split(cmd)
335 else:
336 args = cmd
337
329 executable = args[0] 338 executable = args[0]
330 if os.path.isabs(executable): 339 if os.path.isabs(executable):
331 path_ext.append(os.path.dirname(executable)) 340 path_ext.append(os.path.dirname(executable))
@@ -484,7 +493,7 @@ def start_http_server(image_id, image_data):
484 self.send_response(http.OK) 493 self.send_response(http.OK)
485 self.send_header('Content-Length', str(len(fixture))) 494 self.send_header('Content-Length', str(len(fixture)))
486 self.end_headers() 495 self.end_headers()
487 self.wfile.write(fixture) 496 self.wfile.write(six.b(fixture))
488 return 497 return
489 498
490 def do_HEAD(self): 499 def do_HEAD(self):
@@ -510,11 +519,11 @@ def start_http_server(image_id, image_data):
510 httpd = BaseHTTPServer.HTTPServer(server_address, handler_class) 519 httpd = BaseHTTPServer.HTTPServer(server_address, handler_class)
511 port = httpd.socket.getsockname()[1] 520 port = httpd.socket.getsockname()[1]
512 521
513 pid = os.fork() 522 thread = threading.Thread(target=httpd.serve_forever)
514 if pid == 0: 523 thread.daemon = True
515 httpd.serve_forever() 524 thread.start()
516 else: 525
517 return pid, port 526 return thread, httpd, port
518 527
519 528
520class RegistryAPIMixIn(object): 529class RegistryAPIMixIn(object):
@@ -730,8 +739,8 @@ def start_standalone_http_server():
730 httpd = BaseHTTPServer.HTTPServer(server_address, handler_class) 739 httpd = BaseHTTPServer.HTTPServer(server_address, handler_class)
731 port = httpd.socket.getsockname()[1] 740 port = httpd.socket.getsockname()[1]
732 741
733 pid = os.fork() 742 thread = threading.Thread(target=httpd.serve_forever)
734 if pid == 0: 743 thread.daemon = True
735 httpd.serve_forever() 744 thread.start()
736 else: 745
737 return pid, port 746 return thread, httpd, port