@@ -28,9 +28,11 @@ from autopilot.platform import model
2828from autopilot.testcase import AutopilotTestCase
2929from autopilot.matchers import Eventually
3030from autopilot.input import Touch
31+from autopilot.introspection import get_proxy_object_for_existing_process
3132from autopilot.display import Display
3233import logging
3334import os.path
35+import subprocess
3436from testtools.matchers import Equals, NotEquals
3537
3638from unity8 import (
@@ -90,6 +92,10 @@ class UnityTestCase(AutopilotTestCase):
9092 self.touch = Touch.create()
9193 self._setup_display_details()
9294
95+ self._using_upstart = False
96+ if model() != "Desktop": # or check env
97+ self._using_upstart = True
98+
9399 def _reset_launcher(self):
94100 """Reset Unity launcher hide mode"""
95101 self._unityshell_schema.set_int(UNITYSHELL_LAUNCHER_KEY, self._launcher_hide_mode)
@@ -129,7 +135,7 @@ class UnityTestCase(AutopilotTestCase):
129135 self.grid_size = int(os.getenv('GRID_UNIT_PX'))
130136 else:
131137 self.grid_size = int(self.grid_unit_px / scale_divisor)
132− self.patch_environment("GRID_UNIT_PX", str(self.grid_size))
138+ self._patch_environment("GRID_UNIT_PX", str(self.grid_size))
133139
134140 def _geo_larger_than_display(self, width, height):
135141 should_scale = getattr(self, 'scale_geo', True)
@@ -147,6 +153,41 @@ class UnityTestCase(AutopilotTestCase):
147153 divisor = divisor * 2
148154 return divisor
149155
156+ def _patch_environment(self, key, value):
157+ """Wrapper for patching env for either upstart or non-upstart
158+ environments.
159+
160+ """
161+ if self._using_upstart:
162+ try:
163+ current_value = subprocess.check_output([
164+ "/sbin/initctl",
165+ "get-env",
166+ key
167+ ])
168+ except subprocess.CalledProcessError:
169+ current_value = None
170+
171+ subprocess.call([
172+ "/sbin/initctl",
173+ "set-env",
174+ "%s=%s" % (key, value)
175+ ])
176+ self.addCleanup(self._upstart_reset_env, key, current_value)
177+ else:
178+ self.patch_environment(key, value)
179+
180+ def _upstart_reset_env(self, key, value):
181+ logger.info("Resetting upstart env %s to %s", key, value)
182+ if value is None:
183+ subprocess.call(["/sbin/initctl", "unset-env", key])
184+ else:
185+ subprocess.call([
186+ "/sbin/initctl",
187+ "set-env",
188+ "%s=%s" % (key, value)
189+ ])
190+
150191 def launch_unity(self, **kwargs):
151192 """Launch the unity shell, return a proxy object for it."""
152193 binary_path = get_binary_path()
@@ -175,13 +216,17 @@ class UnityTestCase(AutopilotTestCase):
175216 except OSError:
176217 pass
177218
178− app_proxy = self.launch_test_application(
179− binary_path,
180− *self.unity_geometry_args,
181− app_type='qt',
182− emulator_base=UnityEmulatorBase,
183− **kwargs
184− )
219+ if self._using_upstart:
220+ app_proxy = self._launch_unity_with_upstart()
221+ else:
222+ app_proxy = self.launch_test_application(
223+ binary_path,
224+ *self.unity_geometry_args,
225+ app_type='qt',
226+ emulator_base=UnityEmulatorBase,
227+ **kwargs
228+ )
229+
185230 self._set_proxy(app_proxy)
186231
187232 # Ensure that the dash is visible before we return:
@@ -191,6 +236,54 @@ class UnityTestCase(AutopilotTestCase):
191236
192237 return app_proxy
193238
239+ def _launch_unity_with_upstart(self):
240+ subprocess.call(["/sbin/initctl", "set-env", "QT_LOAD_TESTABILITY=1"])
241+
242+ output = subprocess.check_output([
243+ "/sbin/initctl",
244+ "status",
245+ "unity8"
246+ ])
247+
248+ unity_already_started = False
249+ if "start/" in output:
250+ unity_already_started = True
251+ try:
252+ subprocess.check_call(["/sbin/initctl", "stop", "unity8"])
253+ except subprocess.CalledProcessError as e:
254+ logger.warning("Unable to stop unity8")
255+ e.args += ("Failed to stop existing unity8 process", )
256+ raise
257+
258+ output = subprocess.check_output(["/sbin/initctl", "start", "unity8"])
259+
260+ self.addCleanup(
261+ self._cleanup_launching_upstart_unity,
262+ unity_already_started
263+ )
264+
265+ pid = int(output.split()[-1])
266+
267+ return get_proxy_object_for_existing_process(
268+ pid=pid,
269+ emulator_base=UnityEmulatorBase,
270+ )
271+
272+ def _cleanup_launching_upstart_unity(self, restart_unity):
273+ logger.info("Cleaning up launching unity, unsetting env")
274+ subprocess.call(["/sbin/initctl", "unset-env", "QT_LOAD_TESTABILITY"])
275+
276+ try:
277+ logger.info("Stopping existing unity")
278+ subprocess.check_call(["/sbin/initctl", "stop", "unity8"])
279+ except subprocess.CalledProcessError:
280+ logger.warning("Appears unity was already stopped")
281+
282+ # Actually, the previous env stuff will be still here right?
283+ if restart_unity:
284+ logger.info("Starting unity again with original env")
285+ subprocess.check_call(["/sbin/initctl", "start", "unity8"])
286+
194287 def patch_lightdm_mock(self, mock_type='single'):
195288 self._lightdm_mock_type = mock_type
196289 logger.info("Setting up LightDM mock type '%s'", mock_type)
@@ -204,7 +297,7 @@ class UnityTestCase(AutopilotTestCase):
204297 new_ld_library_path = ':'.join(new_ld_library_path)
205298 logger.info("New library path: %s", new_ld_library_path)
206299
207− self.patch_environment('LD_LIBRARY_PATH', new_ld_library_path)
300+ self._patch_environment('LD_LIBRARY_PATH', new_ld_library_path)
208301
209302 def _get_lightdm_mock_path(self, mock_type):
210303 lib_path = get_mocks_library_path()
@@ -226,7 +319,7 @@ class UnityTestCase(AutopilotTestCase):
226319
227320 qml_import_path = ':'.join(qml_import_path)
228321 logger.info("New QML2 import path: %s", qml_import_path)
229− self.patch_environment('QML2_IMPORT_PATH', qml_import_path)
322+ self._patch_environment('QML2_IMPORT_PATH', qml_import_path)
230323
231324 def _set_proxy(self, proxy):
232325 """Keep a copy of the proxy object, so we can use it to get common