1
# vim: tabstop=4 shiftwidth=4 softtabstop=4
3
# Copyright 2012 Red Hat, Inc
5
# Licensed under the Apache License, Version 2.0 (the "License"); you may
6
# not use this file except in compliance with the License. You may obtain
7
# a copy of the License at
9
# http://www.apache.org/licenses/LICENSE-2.0
11
# Unless required by applicable law or agreed to in writing, software
12
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
# License for the specific language governing permissions and limitations
17
"""Functional test case for the glance-control --respawn option """
26
from glance.tests import functional
27
from glance.tests.utils import skip_if_disabled
30
class TestRespawn(functional.FunctionalTest):
32
"""Functional test for glance-control --respawn """
34
def get_versions(self):
35
path = "http://%s:%d" % ("127.0.0.1", self.api_port)
36
http = httplib2.Http()
37
response, content = http.request(path, 'GET')
38
self.assertEqual(response.status, 300)
41
return int(open(self.api_server.pid_file).read().strip())
43
def kill_server(self):
45
os.killpg(pid, signal.SIGKILL)
48
def wait_for(self, predicate):
56
self.assertTrue(predicate())
58
def connection_unavailable(self, type):
61
self.fail('%s server should not be respawned' % type)
63
exc_value = sys.exc_info()[1]
64
self.assertTrue('Connection refused' in exc_value or
65
'ECONNREFUSED' in exc_value)
68
def test_respawn(self):
70
We test that the '--respawn' option causes the API server
71
to be respawned after death but not after a deliberate stop
74
self.api_server.server_control_options += ' --respawn'
76
# start API server, allowing glance-control to continue running
77
self.start_with_retry(self.api_server,
82
expect_confirmation=False,
83
**self.__dict__.copy())
85
# ensure the service pid has been cached
86
pid_cached = lambda: os.path.exists(self.api_server.pid_file)
87
self.wait_for(pid_cached)
89
# ensure glance-control has had a chance to waitpid on child
92
# verify server health with version negotiation
95
# server is killed ungracefully
96
old_pid = self.kill_server()
98
# ... but should be respawned
100
# wait for pid to cycle
101
pid_changed = lambda: old_pid != self.get_pid()
102
self.wait_for(pid_changed)
104
# ensure API service port is re-activated
105
launch_msg = self.wait_for_servers([self.api_server])
106
self.assertTrue(launch_msg is None, launch_msg)
108
# verify server health with version negotiation
111
# deliberately stop server, it should not be respawned
112
proc_file = '/proc/%d' % self.get_pid()
113
self.stop_server(self.api_server, 'API server')
115
# ensure last server process has gone away
116
process_died = lambda: not os.path.exists(proc_file)
117
self.wait_for(process_died)
119
# deliberately stopped server should not be respawned
120
launch_msg = self.wait_for_servers([self.api_server], False)
121
self.assertTrue(launch_msg is None, launch_msg)
123
# ensure the server has not been respawned
124
self.connection_unavailable('deliberately stopped')
127
def test_bouncing(self):
129
We test that the '--respawn' option doesn't cause bouncing
130
API server to be respawned
133
self.api_server.server_control_options += ' --respawn'
134
self.api_server.default_store = 'shouldnotexist'
136
# start API server, allowing glance-control to continue running
137
self.start_with_retry(self.api_server,
142
expect_confirmation=False,
143
**self.__dict__.copy())
145
# ensure the service pid has been cached
146
pid_cached = lambda: os.path.exists(self.api_server.pid_file)
147
self.wait_for(pid_cached)
149
# ensure glance-control has had a chance to waitpid on child
152
# bouncing server should not be respawned
153
launch_msg = self.wait_for_servers([self.api_server], False)
154
self.assertTrue(launch_msg is None, launch_msg)
156
# ensure server process has gone away
157
process_died = lambda: not os.path.exists('/proc/%d' % self.get_pid())
158
self.wait_for(process_died)
160
# ensure the server has not been respawned
161
self.connection_unavailable('bouncing')