32
37
from contextlib import ExitStack
33
38
from distutils.spawn import find_executable
34
39
from pkg_resources import resource_string as resource_bytes
35
40
from systemimage.helpers import temporary_directory
36
41
from systemimage.testing.helpers import (
37
data_path, find_dbus_process, reset_envar)
42
data_path, find_dbus_process, makedirs, reset_envar, wait_for_service)
43
from unittest.mock import patch
41
OVERRIDE = os.environ.get('SYSTEMIMAGE_DBUS_DAEMON_HUP_SLEEP_SECONDS')
42
HUP_SLEEP = (0 if OVERRIDE is None else int(OVERRIDE))
47
DLSERVICE = os.environ.get(
48
'SYSTEMIMAGE_DLSERVICE',
49
'/usr/bin/ubuntu-download-manager'
50
# For debugging the in-tree version of u-d-m.
51
#'/bin/sh $HOME/projects/phone/trunk/tools/runme.sh'
45
55
def start_system_image(controller):
46
bus = dbus.SystemBus()
47
service = bus.get_object('com.canonical.SystemImage', '/Service')
48
iface = dbus.Interface(service, 'com.canonical.SystemImage')
56
wait_for_service(reload=False)
50
57
process = find_dbus_process(controller.ini_path)
51
58
if process is None:
52
59
raise RuntimeError('Could not start system-image-dbus')
80
87
def start_downloader(controller):
81
bus = dbus.SystemBus()
82
service = bus.get_object('com.canonical.applications.Downloader', '/')
83
iface = dbus.Interface(
84
service, 'com.canonical.applications.DownloadManager')
88
service = dbus.SystemBus().get_object('org.freedesktop.DBus', '/')
89
iface = dbus.Interface(service, 'org.freedesktop.DBus')
92
reply = iface.StartServiceByName(
93
'com.canonical.applications.Downloader', 0)
85
95
# Something innocuous.
86
iface.defaultThrottle()
87
96
process = _find_udm_process()
88
97
if process is None:
89
98
raise RuntimeError('Could not start ubuntu-download-manager')
108
DLSERVICE = '/usr/bin/ubuntu-download-manager'
109
# For debugging the in-tree version of u-d-m.
110
#DLSERVICE = '/bin/sh /home/barry/projects/phone/runme'
114
118
('com.canonical.SystemImage',
115
'{python} -m {self.MODULE} -C {self.ini_path} --testing {self.mode}',
119
'{python} -m {self.MODULE} -C {self.ini_path} '
120
'{self.curl_cert} --testing {self.mode}',
116
121
start_system_image,
117
122
stop_system_image,
119
('com.canonical.applications.Downloader',
130
USING_PYCURL = int(os.environ.get('SYSTEMIMAGE_PYCURL', '0'))
134
('com.canonical.applications.Downloader',
121
' {self.certs} -disable-timeout -stoppable -log-dir {self.tmpdir}',
136
' {self.udm_certs} -disable-timeout -stoppable -log-dir {self.tmpdir}',
122
137
start_downloader,
128
143
class Controller:
131
146
MODULE = 'systemimage.testing.service'
133
148
def __init__(self, logfile=None, loglevel='info'):
149
self.loglevel = loglevel
135
151
self._stack = ExitStack()
136
152
self._stoppers = []
138
154
self.tmpdir = self._stack.enter_context(temporary_directory())
139
155
self.config_path = os.path.join(self.tmpdir, 'dbus-system.conf')
141
156
self.serverdir = self._stack.enter_context(temporary_directory())
142
157
self.daemon_pid = None
143
158
self.mode = 'live'
145
162
# Set up the dbus-daemon system configuration file.
146
163
path = data_path('dbus-system.conf.in')
147
164
with open(path, 'r', encoding='utf-8') as fp:
151
168
with open(self.config_path, 'w', encoding='utf-8') as fp:
153
170
# We need a client.ini file for the subprocess.
154
ini_tmpdir = self._stack.enter_context(temporary_directory())
155
ini_vardir = self._stack.enter_context(temporary_directory())
156
ini_logfile = (os.path.join(ini_tmpdir, 'client.log')
159
self.ini_path = os.path.join(self.tmpdir, 'client.ini')
171
self.ini_tmpdir = self._stack.enter_context(temporary_directory())
172
self.ini_vardir = self._stack.enter_context(temporary_directory())
173
self.ini_logfile = (os.path.join(self.ini_tmpdir, 'client.log')
176
self.ini_path = os.path.join(self.tmpdir, 'config.d')
177
makedirs(self.ini_path)
178
self._reset_configs()
180
def _reset_configs(self):
181
for filename in os.listdir(self.ini_path):
182
if filename.endswith('.ini'):
183
os.remove(os.path.join(self.ini_path, filename))
160
184
template = resource_bytes(
161
'systemimage.tests.data', 'config_03.ini').decode('utf-8')
162
with open(self.ini_path, 'w', encoding='utf-8') as fp:
163
print(template.format(tmpdir=ini_tmpdir,
185
'systemimage.tests.data', '01.ini').decode('utf-8')
186
defaults = os.path.join(self.ini_path, '00_defaults.ini')
187
with open(defaults, 'w', encoding='utf-8') as fp:
188
print(template.format(tmpdir=self.ini_tmpdir,
189
vardir=self.ini_vardir,
190
logfile=self.ini_logfile,
191
loglevel=self.loglevel),
169
194
def _configure_services(self):
184
209
self._stoppers.append(stopper)
185
210
# If the dbus-daemon is running, reload its configuration files.
186
211
if self.daemon_pid is not None:
187
service = dbus.SystemBus().get_object('org.freedesktop.DBus', '/')
188
iface = dbus.Interface(service, 'org.freedesktop.DBus')
190
time.sleep(HUP_SLEEP)
214
def _set_udm_certs(self, cert_pem, certificate_path):
216
'' if cert_pem is None
217
else '-self-signed-certs ' + certificate_path)
219
def _set_curl_certs(self, cert_pem, certificate_path):
220
# We have to set up the PyCURL downloader's self-signed certificate for
221
# the test in two ways. First, because we might be spawning the D-Bus
222
# service, we have to pass the path to the cert to that service...
224
'' if cert_pem is None
225
else '--self-signed-cert ' + certificate_path)
226
# ...but the controller is also used to set the mode for foreground
227
# tests, such as test_download.py. Here we don't spawn any D-Bus
228
# processes, but we still have to mock make_testable() in curl.py so
229
# that the PyCURL object accepts the self-signed cert.
230
if self.patcher is not None:
233
if cert_pem is not None:
235
c.setopt(pycurl.CAINFO, certificate_path)
236
self.patcher = patch('systemimage.curl.make_testable', self_sign)
192
239
def set_mode(self, *, cert_pem=None, service_mode=''):
193
240
self.mode = service_mode
195
'' if cert_pem is None
196
else '-self-signed-certs ' + data_path(cert_pem))
241
certificate_path = data_path(cert_pem)
243
self._set_curl_certs(cert_pem, certificate_path)
245
self._set_udm_certs(cert_pem, certificate_path)
246
self._reset_configs()
197
247
self._configure_services()
199
249
def _start(self):
214
264
#'/usr/lib/x86_64-linux-gnu/dbus-1.0/debug-build/bin/dbus-daemon',
216
'--config-file=' + self.config_path,
266
'--config-file=' + str(self.config_path),
217
267
# Return the address and pid on stdout.
218
268
'--print-address=1',