Merge lp:~ted/ubuntu-app-launch/jobs-tests into lp:ubuntu-app-launch/16.10
- jobs-tests
- Merge into trunk.16.10
Status: | Superseded |
---|---|
Proposed branch: | lp:~ted/ubuntu-app-launch/jobs-tests |
Merge into: | lp:ubuntu-app-launch/16.10 |
Prerequisite: | lp:~ted/ubuntu-app-launch/abstract-jobs |
Diff against target: |
1974 lines (+1052/-593) 11 files modified
data/com.canonical.UbuntuAppLaunch.xml (+8/-0) debian/control (+1/-0) libubuntu-app-launch/jobs-base.cpp (+201/-1) libubuntu-app-launch/jobs-base.h (+60/-1) libubuntu-app-launch/jobs-upstart.cpp (+332/-0) libubuntu-app-launch/jobs-upstart.h (+35/-0) libubuntu-app-launch/registry-impl.cpp (+0/-501) libubuntu-app-launch/registry-impl.h (+2/-68) libubuntu-app-launch/registry.cpp (+27/-7) tests/CMakeLists.txt (+22/-15) tests/jobs-base-test.cpp (+364/-0) |
To merge this branch: | bzr merge lp:~ted/ubuntu-app-launch/jobs-tests |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Unity API Team | Pending | ||
Review via email: mp+309407@code.launchpad.net |
This proposal has been superseded by a proposal from 2016-11-10.
Commit message
Jobs interface specific tests
Description of the change
- 265. By Ted Gould
-
Add dependency on google mock
- 266. By Ted Gould
-
Aligning with the signal instances branch
- 267. By Ted Gould
-
Pulling through updates
- 268. By Ted Gould
-
Pulling through trunk
- 269. By Ted Gould
-
Put the spew master into its own header
- 270. By Ted Gould
-
Get the static libs into the coverage game
- 271. By Ted Gould
-
Grab signal instances changes
- 272. By Ted Gould
-
Test fixes
- 273. By Ted Gould
-
Make the comparison values unsigned
- 274. By Ted Gould
-
Merge upstream changes
- 275. By Ted Gould
-
Backport the changes on the gmock-fix branch to here, where most of the problems were caused
- 276. By Ted Gould
-
Use a clearer definition of unsigned
- 277. By Ted Gould
-
Only or onto the transitional google-mock package
- 278. By Ted Gould
-
Alphabetize list
- 279. By Ted Gould
-
Make build on 32-bit architectures where gsize is a different size
- 280. By Ted Gould
-
Make it so that tests can run in parallel without running over each other
- 281. By Ted Gould
-
Remove -lgcov hack and add snapd-info-test to the list of tests
- 282. By Ted Gould
-
Uhg, wanted to delete not just comment out
- 283. By Ted Gould
-
Update to trunk
- 284. By Ted Gould
-
Switch to the local socket to avoid conflicts
- 285. By Ted Gould
-
Make required libraries required
- 286. By Ted Gould
-
Fix listing of targets
Unmerged revisions
- 286. By Ted Gould
-
Fix listing of targets
- 285. By Ted Gould
-
Make required libraries required
- 284. By Ted Gould
-
Switch to the local socket to avoid conflicts
- 283. By Ted Gould
-
Update to trunk
- 282. By Ted Gould
-
Uhg, wanted to delete not just comment out
- 281. By Ted Gould
-
Remove -lgcov hack and add snapd-info-test to the list of tests
- 280. By Ted Gould
-
Make it so that tests can run in parallel without running over each other
- 279. By Ted Gould
-
Make build on 32-bit architectures where gsize is a different size
- 278. By Ted Gould
-
Alphabetize list
- 277. By Ted Gould
-
Only or onto the transitional google-mock package
Preview Diff
1 | === modified file 'data/com.canonical.UbuntuAppLaunch.xml' |
2 | --- data/com.canonical.UbuntuAppLaunch.xml 2015-03-04 14:26:35 +0000 |
3 | +++ data/com.canonical.UbuntuAppLaunch.xml 2016-11-10 21:58:53 +0000 |
4 | @@ -3,29 +3,37 @@ |
5 | <interface name="com.canonical.UpstartAppLaunch"> |
6 | <signal name="UnityResumeRequest"> |
7 | <arg type="s" name="appid" /> |
8 | + <arg type="s" name="instance" /> |
9 | </signal> |
10 | <signal name="UnityResumeResponse"> |
11 | <arg type="s" name="appid" /> |
12 | + <arg type="s" name="instance" /> |
13 | </signal> |
14 | <signal name="UnityFocusRequest"> |
15 | <arg type="s" name="appid" /> |
16 | + <arg type="s" name="instance" /> |
17 | </signal> |
18 | <signal name="UnityStartingBroadcast"> |
19 | <arg type="s" name="appid" /> |
20 | + <arg type="s" name="instance" /> |
21 | </signal> |
22 | <signal name="UnityStartingSignal"> |
23 | <arg type="s" name="appid" /> |
24 | + <arg type="s" name="instance" /> |
25 | </signal> |
26 | <signal name="ApplicationFailed"> |
27 | <arg type="s" name="appid" /> |
28 | + <arg type="s" name="instance" /> |
29 | <arg type="s" name="stage" /> |
30 | </signal> |
31 | <signal name="ApplicationPaused"> |
32 | <arg type="s" name="appid" /> |
33 | + <arg type="s" name="instance" /> |
34 | <arg type="at" name="pids" /> |
35 | </signal> |
36 | <signal name="ApplicationResumed"> |
37 | <arg type="s" name="appid" /> |
38 | + <arg type="s" name="instance" /> |
39 | <arg type="at" name="pids" /> |
40 | </signal> |
41 | </interface> |
42 | |
43 | === modified file 'debian/control' |
44 | --- debian/control 2016-08-23 15:04:08 +0000 |
45 | +++ debian/control 2016-11-10 21:58:53 +0000 |
46 | @@ -9,6 +9,7 @@ |
47 | dbus-x11, |
48 | dbus-test-runner, |
49 | debhelper (>= 9), |
50 | + google-mock, |
51 | libcgmanager-dev, |
52 | libclick-0.4-dev, |
53 | libcurl4-dev | libcurl4-gnutls-dev, |
54 | |
55 | === modified file 'libubuntu-app-launch/jobs-base.cpp' |
56 | --- libubuntu-app-launch/jobs-base.cpp 2016-11-10 21:58:53 +0000 |
57 | +++ libubuntu-app-launch/jobs-base.cpp 2016-11-10 21:58:53 +0000 |
58 | @@ -37,7 +37,23 @@ |
59 | |
60 | Base::Base(const std::shared_ptr<Registry>& registry) |
61 | : registry_(registry) |
62 | -{ |
63 | + , dbus_(registry->impl->_dbus) |
64 | +{ |
65 | +} |
66 | + |
67 | +Base::~Base() |
68 | +{ |
69 | + auto dohandle = [&](guint& handle) { |
70 | + if (handle != 0) |
71 | + { |
72 | + g_dbus_connection_signal_unsubscribe(dbus_.get(), handle); |
73 | + handle = 0; |
74 | + } |
75 | + }; |
76 | + |
77 | + dohandle(handle_managerSignalFocus); |
78 | + dohandle(handle_managerSignalResume); |
79 | + dohandle(handle_managerSignalStarting); |
80 | } |
81 | |
82 | std::shared_ptr<Base> Base::determineFactory(std::shared_ptr<Registry> registry) |
83 | @@ -45,6 +61,190 @@ |
84 | return std::make_shared<jobs::manager::Upstart>(registry); |
85 | } |
86 | |
87 | +/** Take the GVariant of parameters and turn them into an application and |
88 | + and instance. Easier to read in the smaller function */ |
89 | +std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> Base::managerParams( |
90 | + const std::shared_ptr<GVariant>& params, const std::shared_ptr<Registry>& reg) |
91 | +{ |
92 | + std::shared_ptr<Application> app; |
93 | + std::shared_ptr<Application::Instance> instance; |
94 | + |
95 | + const gchar* cappid = nullptr; |
96 | + g_variant_get(params.get(), "(&s)", &cappid); |
97 | + |
98 | + auto appid = ubuntu::app_launch::AppID::find(reg, cappid); |
99 | + app = ubuntu::app_launch::Application::create(appid, reg); |
100 | + |
101 | + return std::make_tuple(app, instance); |
102 | +} |
103 | + |
104 | +/** Used to store data for manager based signal handlers. Has a link to the |
105 | + registry and the callback to use in a C++ style. */ |
106 | +struct managerEventData |
107 | +{ |
108 | + /* Keeping a weak pointer because the handle is held by |
109 | + the registry implementation. */ |
110 | + std::weak_ptr<Registry> weakReg; |
111 | + std::function<void(const std::shared_ptr<Registry>& reg, |
112 | + const std::shared_ptr<Application>& app, |
113 | + const std::shared_ptr<Application::Instance>& instance, |
114 | + const std::shared_ptr<GDBusConnection>&, |
115 | + const std::string&, |
116 | + const std::shared_ptr<GVariant>&)> |
117 | + func; |
118 | +}; |
119 | + |
120 | +/** Register for a signal for the manager. All of the signals needed this same |
121 | + code so it got pulled out into a function. Takes the same of the signal, the registry |
122 | + that we're using and a function to call after we've messaged all the parameters |
123 | + into being something C++-ish. */ |
124 | +guint Base::managerSignalHelper(const std::shared_ptr<Registry>& reg, |
125 | + const std::string& signalname, |
126 | + std::function<void(const std::shared_ptr<Registry>& reg, |
127 | + const std::shared_ptr<Application>& app, |
128 | + const std::shared_ptr<Application::Instance>& instance, |
129 | + const std::shared_ptr<GDBusConnection>&, |
130 | + const std::string&, |
131 | + const std::shared_ptr<GVariant>&)> responsefunc) |
132 | +{ |
133 | + managerEventData* focusdata = new managerEventData{reg, responsefunc}; |
134 | + |
135 | + return g_dbus_connection_signal_subscribe( |
136 | + reg->impl->_dbus.get(), /* bus */ |
137 | + nullptr, /* sender */ |
138 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
139 | + signalname.c_str(), /* signal */ |
140 | + "/", /* path */ |
141 | + nullptr, /* arg0 */ |
142 | + G_DBUS_SIGNAL_FLAGS_NONE, |
143 | + [](GDBusConnection* cconn, const gchar* csender, const gchar*, const gchar*, const gchar*, GVariant* params, |
144 | + gpointer user_data) -> void { |
145 | + auto data = reinterpret_cast<managerEventData*>(user_data); |
146 | + auto reg = data->weakReg.lock(); |
147 | + |
148 | + /* If we're still conneted and the manager has been cleared |
149 | + we'll just be a no-op */ |
150 | + auto ljobs = std::dynamic_pointer_cast<Base>(reg->impl->jobs); |
151 | + if (!ljobs->manager_) |
152 | + { |
153 | + return; |
154 | + } |
155 | + |
156 | + auto vparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
157 | + auto conn = std::shared_ptr<GDBusConnection>(reinterpret_cast<GDBusConnection*>(g_object_ref(cconn)), |
158 | + [](GDBusConnection* con) { g_clear_object(&con); }); |
159 | + std::string sender = csender; |
160 | + std::shared_ptr<Application> app; |
161 | + std::shared_ptr<Application::Instance> instance; |
162 | + |
163 | + std::tie(app, instance) = managerParams(vparams, reg); |
164 | + |
165 | + data->func(reg, app, instance, conn, sender, vparams); |
166 | + }, |
167 | + focusdata, |
168 | + [](gpointer user_data) { |
169 | + auto data = reinterpret_cast<managerEventData*>(user_data); |
170 | + delete data; |
171 | + }); /* user data destroy */ |
172 | +} |
173 | + |
174 | +/** Set the manager for the registry. This includes tracking the pointer |
175 | + as well as setting up the signals to call back into the manager. The |
176 | + signals are only setup once per registry even if the manager is cleared |
177 | + and changed again. They will just be no-op's in those cases. |
178 | +*/ |
179 | +void Base::setManager(std::shared_ptr<Registry::Manager> manager) |
180 | +{ |
181 | + if (manager_) |
182 | + { |
183 | + throw std::runtime_error("Already have a manager and trying to set another"); |
184 | + } |
185 | + |
186 | + g_debug("Setting a new manager"); |
187 | + manager_ = manager; |
188 | + |
189 | + std::call_once(flag_managerSignals, [this]() { |
190 | + auto reg = registry_.lock(); |
191 | + |
192 | + if (!reg->impl->thread.executeOnThread<bool>([this, reg]() { |
193 | + handle_managerSignalFocus = managerSignalHelper( |
194 | + reg, "UnityFocusRequest", |
195 | + [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app, |
196 | + const std::shared_ptr<Application::Instance>& instance, |
197 | + const std::shared_ptr<GDBusConnection>& conn, const std::string& sender, |
198 | + const std::shared_ptr<GVariant>& params) { |
199 | + /* Nothing to do today */ |
200 | + std::dynamic_pointer_cast<Base>(reg->impl->jobs) |
201 | + ->manager_->focusRequest(app, instance, [](bool response) { |
202 | + /* NOTE: We have no clue what thread this is gonna be |
203 | + executed on, but since we're just talking to the GDBus |
204 | + thread it isn't an issue today. Be careful in changing |
205 | + this code. */ |
206 | + }); |
207 | + }); |
208 | + handle_managerSignalStarting = managerSignalHelper( |
209 | + reg, "UnityStartingBroadcast", |
210 | + [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app, |
211 | + const std::shared_ptr<Application::Instance>& instance, |
212 | + const std::shared_ptr<GDBusConnection>& conn, const std::string& sender, |
213 | + const std::shared_ptr<GVariant>& params) { |
214 | + |
215 | + std::dynamic_pointer_cast<Base>(reg->impl->jobs) |
216 | + ->manager_->startingRequest(app, instance, [conn, sender, params](bool response) { |
217 | + /* NOTE: We have no clue what thread this is gonna be |
218 | + executed on, but since we're just talking to the GDBus |
219 | + thread it isn't an issue today. Be careful in changing |
220 | + this code. */ |
221 | + if (response) |
222 | + { |
223 | + g_dbus_connection_emit_signal(conn.get(), sender.c_str(), /* destination */ |
224 | + "/", /* path */ |
225 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
226 | + "UnityStartingSignal", /* signal */ |
227 | + params.get(), /* params, the same */ |
228 | + nullptr); /* error */ |
229 | + } |
230 | + }); |
231 | + }); |
232 | + handle_managerSignalResume = managerSignalHelper( |
233 | + reg, "UnityResumeRequest", |
234 | + [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app, |
235 | + const std::shared_ptr<Application::Instance>& instance, |
236 | + const std::shared_ptr<GDBusConnection>& conn, const std::string& sender, |
237 | + const std::shared_ptr<GVariant>& params) { |
238 | + std::dynamic_pointer_cast<Base>(reg->impl->jobs) |
239 | + ->manager_->resumeRequest(app, instance, [conn, sender, params](bool response) { |
240 | + /* NOTE: We have no clue what thread this is gonna be |
241 | + executed on, but since we're just talking to the GDBus |
242 | + thread it isn't an issue today. Be careful in changing |
243 | + this code. */ |
244 | + if (response) |
245 | + { |
246 | + g_dbus_connection_emit_signal(conn.get(), sender.c_str(), /* destination */ |
247 | + "/", /* path */ |
248 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
249 | + "UnityResumeResponse", /* signal */ |
250 | + params.get(), /* params, the same */ |
251 | + nullptr); /* error */ |
252 | + } |
253 | + }); |
254 | + }); |
255 | + |
256 | + return true; |
257 | + })) |
258 | + { |
259 | + g_warning("Unable to install manager signals"); |
260 | + } |
261 | + }); |
262 | +} |
263 | + |
264 | +/** Clear the manager pointer */ |
265 | +void Base::clearManager() |
266 | +{ |
267 | + g_debug("Clearing the manager"); |
268 | + manager_.reset(); |
269 | +} |
270 | + |
271 | } // namespace manager |
272 | |
273 | namespace instance |
274 | |
275 | === modified file 'libubuntu-app-launch/jobs-base.h' |
276 | --- libubuntu-app-launch/jobs-base.h 2016-11-10 21:58:53 +0000 |
277 | +++ libubuntu-app-launch/jobs-base.h 2016-11-10 21:58:53 +0000 |
278 | @@ -18,7 +18,12 @@ |
279 | */ |
280 | |
281 | #pragma once |
282 | + |
283 | #include "application.h" |
284 | +#include "registry.h" |
285 | + |
286 | +#include <core/signal.h> |
287 | +#include <gio/gio.h> |
288 | |
289 | namespace ubuntu |
290 | { |
291 | @@ -86,7 +91,7 @@ |
292 | { |
293 | public: |
294 | Base(const std::shared_ptr<Registry>& registry); |
295 | - virtual ~Base() = default; |
296 | + virtual ~Base(); |
297 | |
298 | virtual std::shared_ptr<Application::Instance> launch( |
299 | const AppID& appId, |
300 | @@ -107,8 +112,62 @@ |
301 | |
302 | static std::shared_ptr<Base> determineFactory(std::shared_ptr<Registry> registry); |
303 | |
304 | + /* Signals to apps */ |
305 | + virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStarted() = 0; |
306 | + virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStopped() = 0; |
307 | + virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, Registry::FailureType>& |
308 | + appFailed() = 0; |
309 | + virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& |
310 | + appPaused() = 0; |
311 | + virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& |
312 | + appResumed() = 0; |
313 | + |
314 | + /* App manager */ |
315 | + virtual void setManager(std::shared_ptr<Registry::Manager> manager); |
316 | + virtual void clearManager(); |
317 | + |
318 | protected: |
319 | + /** A link to the registry */ |
320 | std::weak_ptr<Registry> registry_; |
321 | + |
322 | + /** The DBus connection we're connecting to */ |
323 | + std::shared_ptr<GDBusConnection> dbus_; |
324 | + |
325 | + /** Application manager instance */ |
326 | + std::shared_ptr<Registry::Manager> manager_; |
327 | + |
328 | + /** Signal object for applications started */ |
329 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> sig_appStarted; |
330 | + /** Signal object for applications stopped */ |
331 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> sig_appStopped; |
332 | + /** Signal object for applications failed */ |
333 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, Registry::FailureType> |
334 | + sig_appFailed; |
335 | + /** Signal object for applications paused */ |
336 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&> |
337 | + sig_appPaused; |
338 | + /** Signal object for applications resumed */ |
339 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&> |
340 | + sig_appResumed; |
341 | + |
342 | +private: |
343 | + guint handle_managerSignalFocus{0}; /**< GDBus signal watcher handle for app focused signal */ |
344 | + guint handle_managerSignalResume{0}; /**< GDBus signal watcher handle for app resumed signal */ |
345 | + guint handle_managerSignalStarting{0}; /**< GDBus signal watcher handle for app starting signal */ |
346 | + |
347 | + std::once_flag flag_managerSignals; /**< Variable to track to see if signal handlers are installed for the manager |
348 | + signals of focused, resumed and starting */ |
349 | + |
350 | + static std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> managerParams( |
351 | + const std::shared_ptr<GVariant>& params, const std::shared_ptr<Registry>& reg); |
352 | + static guint managerSignalHelper(const std::shared_ptr<Registry>& reg, |
353 | + const std::string& signalname, |
354 | + std::function<void(const std::shared_ptr<Registry>& reg, |
355 | + const std::shared_ptr<Application>& app, |
356 | + const std::shared_ptr<Application::Instance>& instance, |
357 | + const std::shared_ptr<GDBusConnection>&, |
358 | + const std::string&, |
359 | + const std::shared_ptr<GVariant>&)> responsefunc); |
360 | }; |
361 | |
362 | } // namespace manager |
363 | |
364 | === modified file 'libubuntu-app-launch/jobs-upstart.cpp' |
365 | --- libubuntu-app-launch/jobs-upstart.cpp 2016-11-10 21:58:53 +0000 |
366 | +++ libubuntu-app-launch/jobs-upstart.cpp 2016-11-10 21:58:53 +0000 |
367 | @@ -403,6 +403,19 @@ |
368 | |
369 | Upstart::~Upstart() |
370 | { |
371 | + auto dohandle = [&](guint& handle) { |
372 | + if (handle != 0) |
373 | + { |
374 | + g_dbus_connection_signal_unsubscribe(dbus_.get(), handle); |
375 | + handle = 0; |
376 | + } |
377 | + }; |
378 | + |
379 | + dohandle(handle_appStarted); |
380 | + dohandle(handle_appStopped); |
381 | + dohandle(handle_appFailed); |
382 | + dohandle(handle_appPaused); |
383 | + dohandle(handle_appResumed); |
384 | } |
385 | |
386 | /** Launch an application and create a new Upstart instance object to track |
387 | @@ -576,6 +589,325 @@ |
388 | return vect; |
389 | } |
390 | |
391 | +/** Structure to track the data needed for upstart events. This cleans |
392 | + up the lifecycle as we're passing this as a pointer through the |
393 | + GLib calls. */ |
394 | +struct upstartEventData |
395 | +{ |
396 | + /** Keeping a weak pointer because the handle is held by |
397 | + the registry implementation. */ |
398 | + std::weak_ptr<Registry> weakReg; |
399 | +}; |
400 | + |
401 | +/** Regex to parse the JOB environment variable from Upstart */ |
402 | +std::regex jobenv_regex{"^JOB=(application\\-(?:click|snap|legacy))$"}; |
403 | +/** Regex to parse the INSTANCE environment variable from Upstart */ |
404 | +std::regex instanceenv_regex{"^INSTANCE=(.*?)(?:\\-([0-9]*))?+$"}; |
405 | + |
406 | +/** Core of most of the events that come from Upstart directly. Includes parsing of the |
407 | + Upstart event environment and calling the appropriate signal with the right Application |
408 | + object and eventually its instance */ |
409 | +void Upstart::upstartEventEmitted( |
410 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& signal, |
411 | + std::shared_ptr<GVariant> params, |
412 | + const std::shared_ptr<Registry>& reg) |
413 | +{ |
414 | + std::string jobname; |
415 | + std::string sappid; |
416 | + std::string instance; |
417 | + |
418 | + gchar* env = nullptr; |
419 | + GVariant* envs = g_variant_get_child_value(params.get(), 1); |
420 | + GVariantIter iter; |
421 | + g_variant_iter_init(&iter, envs); |
422 | + |
423 | + while (g_variant_iter_loop(&iter, "s", &env)) |
424 | + { |
425 | + std::smatch match; |
426 | + std::string senv = env; |
427 | + |
428 | + if (std::regex_match(senv, match, jobenv_regex)) |
429 | + { |
430 | + jobname = match[1].str(); |
431 | + } |
432 | + else if (std::regex_match(senv, match, instanceenv_regex)) |
433 | + { |
434 | + sappid = match[1].str(); |
435 | + instance = match[2].str(); |
436 | + } |
437 | + } |
438 | + |
439 | + g_variant_unref(envs); |
440 | + |
441 | + if (jobname.empty()) |
442 | + { |
443 | + return; |
444 | + } |
445 | + |
446 | + g_debug("Upstart Event for job '%s' appid '%s' instance '%s'", jobname.c_str(), sappid.c_str(), instance.c_str()); |
447 | + |
448 | + auto appid = AppID::find(reg, sappid); |
449 | + auto app = Application::create(appid, reg); |
450 | + |
451 | + // TODO: Figure otu creating instances |
452 | + |
453 | + signal(app, {}); |
454 | +} |
455 | + |
456 | +/** Grab the signal object for application startup. If we're not already listing for |
457 | + those signals this sets up a listener for them. */ |
458 | +core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& Upstart::appStarted() |
459 | +{ |
460 | + std::call_once(flag_appStarted, [this]() { |
461 | + auto reg = registry_.lock(); |
462 | + |
463 | + reg->impl->thread.executeOnThread<bool>([this, reg]() { |
464 | + upstartEventData* data = new upstartEventData{reg}; |
465 | + |
466 | + handle_appStarted = g_dbus_connection_signal_subscribe( |
467 | + reg->impl->_dbus.get(), /* bus */ |
468 | + nullptr, /* sender */ |
469 | + DBUS_INTERFACE_UPSTART, /* interface */ |
470 | + "EventEmitted", /* signal */ |
471 | + DBUS_PATH_UPSTART, /* path */ |
472 | + "started", /* arg0 */ |
473 | + G_DBUS_SIGNAL_FLAGS_NONE, |
474 | + [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
475 | + gpointer user_data) -> void { |
476 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
477 | + auto reg = data->weakReg.lock(); |
478 | + auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
479 | + auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs); |
480 | + upstart->upstartEventEmitted(upstart->sig_appStarted, sparams, reg); |
481 | + }, /* callback */ |
482 | + data, /* user data */ |
483 | + [](gpointer user_data) { |
484 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
485 | + delete data; |
486 | + }); /* user data destroy */ |
487 | + |
488 | + return true; |
489 | + }); |
490 | + }); |
491 | + |
492 | + return sig_appStarted; |
493 | +} |
494 | + |
495 | +/** Grab the signal object for application stopping. If we're not already listing for |
496 | + those signals this sets up a listener for them. */ |
497 | +core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& Upstart::appStopped() |
498 | +{ |
499 | + std::call_once(flag_appStopped, [this]() { |
500 | + auto reg = registry_.lock(); |
501 | + |
502 | + reg->impl->thread.executeOnThread<bool>([this, reg]() { |
503 | + upstartEventData* data = new upstartEventData{reg}; |
504 | + |
505 | + handle_appStopped = g_dbus_connection_signal_subscribe( |
506 | + reg->impl->_dbus.get(), /* bus */ |
507 | + nullptr, /* sender */ |
508 | + DBUS_INTERFACE_UPSTART, /* interface */ |
509 | + "EventEmitted", /* signal */ |
510 | + DBUS_PATH_UPSTART, /* path */ |
511 | + "stopped", /* arg0 */ |
512 | + G_DBUS_SIGNAL_FLAGS_NONE, |
513 | + [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
514 | + gpointer user_data) -> void { |
515 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
516 | + auto reg = data->weakReg.lock(); |
517 | + auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
518 | + auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs); |
519 | + upstart->upstartEventEmitted(upstart->sig_appStopped, sparams, reg); |
520 | + }, /* callback */ |
521 | + data, /* user data */ |
522 | + [](gpointer user_data) { |
523 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
524 | + delete data; |
525 | + }); /* user data destroy */ |
526 | + |
527 | + return true; |
528 | + }); |
529 | + }); |
530 | + |
531 | + return sig_appStopped; |
532 | +} |
533 | + |
534 | +/** Grab the signal object for application failing. If we're not already listing for |
535 | + those signals this sets up a listener for them. */ |
536 | +core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, Registry::FailureType>& |
537 | + Upstart::appFailed() |
538 | +{ |
539 | + std::call_once(flag_appFailed, [this]() { |
540 | + auto reg = registry_.lock(); |
541 | + |
542 | + reg->impl->thread.executeOnThread<bool>([this, reg]() { |
543 | + upstartEventData* data = new upstartEventData{reg}; |
544 | + |
545 | + handle_appFailed = g_dbus_connection_signal_subscribe( |
546 | + reg->impl->_dbus.get(), /* bus */ |
547 | + nullptr, /* sender */ |
548 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
549 | + "ApplicationFailed", /* signal */ |
550 | + "/", /* path */ |
551 | + nullptr, /* arg0 */ |
552 | + G_DBUS_SIGNAL_FLAGS_NONE, |
553 | + [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
554 | + gpointer user_data) -> void { |
555 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
556 | + auto reg = data->weakReg.lock(); |
557 | + |
558 | + const gchar* sappid = NULL; |
559 | + const gchar* typestr = NULL; |
560 | + |
561 | + Registry::FailureType type = Registry::FailureType::CRASH; |
562 | + g_variant_get(params, "(&s&s)", &sappid, &typestr); |
563 | + |
564 | + if (g_strcmp0("crash", typestr) == 0) |
565 | + { |
566 | + type = Registry::FailureType::CRASH; |
567 | + } |
568 | + else if (g_strcmp0("start-failure", typestr) == 0) |
569 | + { |
570 | + type = Registry::FailureType::START_FAILURE; |
571 | + } |
572 | + else |
573 | + { |
574 | + g_warning("Application failure type '%s' unknown, reporting as a crash", typestr); |
575 | + } |
576 | + |
577 | + auto appid = AppID::find(reg, sappid); |
578 | + auto app = Application::create(appid, reg); |
579 | + |
580 | + /* TODO: Instance issues */ |
581 | + |
582 | + auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs); |
583 | + upstart->sig_appFailed(app, {}, type); |
584 | + }, /* callback */ |
585 | + data, /* user data */ |
586 | + [](gpointer user_data) { |
587 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
588 | + delete data; |
589 | + }); /* user data destroy */ |
590 | + |
591 | + return true; |
592 | + }); |
593 | + }); |
594 | + |
595 | + return sig_appFailed; |
596 | +} |
597 | + |
598 | +/** Core handler for pause and resume events. Includes turning the GVariant |
599 | + pid list into a std::vector and getting the application object. */ |
600 | +void Upstart::pauseEventEmitted( |
601 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& signal, |
602 | + const std::shared_ptr<GVariant>& params, |
603 | + const std::shared_ptr<Registry>& reg) |
604 | +{ |
605 | + std::vector<pid_t> pids; |
606 | + GVariant* vappid = g_variant_get_child_value(params.get(), 0); |
607 | + GVariant* vpids = g_variant_get_child_value(params.get(), 1); |
608 | + guint64 pid; |
609 | + GVariantIter thispid; |
610 | + g_variant_iter_init(&thispid, vpids); |
611 | + |
612 | + while (g_variant_iter_loop(&thispid, "t", &pid)) |
613 | + { |
614 | + pids.emplace_back(pid); |
615 | + } |
616 | + |
617 | + auto cappid = g_variant_get_string(vappid, NULL); |
618 | + auto appid = ubuntu::app_launch::AppID::find(reg, cappid); |
619 | + auto app = Application::create(appid, reg); |
620 | + |
621 | + /* TODO: Instance */ |
622 | + signal(app, {}, pids); |
623 | + |
624 | + g_variant_unref(vappid); |
625 | + g_variant_unref(vpids); |
626 | + |
627 | + return; |
628 | +} |
629 | + |
630 | +/** Grab the signal object for application paused. If we're not already listing for |
631 | + those signals this sets up a listener for them. */ |
632 | +core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& |
633 | + Upstart::appPaused() |
634 | +{ |
635 | + std::call_once(flag_appPaused, [this]() { |
636 | + auto reg = registry_.lock(); |
637 | + |
638 | + reg->impl->thread.executeOnThread<bool>([this, reg]() { |
639 | + upstartEventData* data = new upstartEventData{reg}; |
640 | + |
641 | + handle_appPaused = g_dbus_connection_signal_subscribe( |
642 | + reg->impl->_dbus.get(), /* bus */ |
643 | + nullptr, /* sender */ |
644 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
645 | + "ApplicationPaused", /* signal */ |
646 | + "/", /* path */ |
647 | + nullptr, /* arg0 */ |
648 | + G_DBUS_SIGNAL_FLAGS_NONE, |
649 | + [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
650 | + gpointer user_data) -> void { |
651 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
652 | + auto reg = data->weakReg.lock(); |
653 | + auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
654 | + auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs); |
655 | + upstart->pauseEventEmitted(upstart->sig_appPaused, sparams, reg); |
656 | + }, /* callback */ |
657 | + data, /* user data */ |
658 | + [](gpointer user_data) { |
659 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
660 | + delete data; |
661 | + }); /* user data destroy */ |
662 | + |
663 | + return true; |
664 | + }); |
665 | + }); |
666 | + |
667 | + return sig_appPaused; |
668 | +} |
669 | + |
670 | +/** Grab the signal object for application resumed. If we're not already listing for |
671 | + those signals this sets up a listener for them. */ |
672 | +core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& |
673 | + Upstart::appResumed() |
674 | +{ |
675 | + std::call_once(flag_appResumed, [this]() { |
676 | + auto reg = registry_.lock(); |
677 | + |
678 | + reg->impl->thread.executeOnThread<bool>([this, reg]() { |
679 | + upstartEventData* data = new upstartEventData{reg}; |
680 | + |
681 | + handle_appResumed = g_dbus_connection_signal_subscribe( |
682 | + reg->impl->_dbus.get(), /* bus */ |
683 | + nullptr, /* sender */ |
684 | + "com.canonical.UbuntuAppLaunch", /* interface */ |
685 | + "ApplicationResumed", /* signal */ |
686 | + "/", /* path */ |
687 | + nullptr, /* arg0 */ |
688 | + G_DBUS_SIGNAL_FLAGS_NONE, |
689 | + [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
690 | + gpointer user_data) -> void { |
691 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
692 | + auto reg = data->weakReg.lock(); |
693 | + auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
694 | + auto upstart = std::dynamic_pointer_cast<Upstart>(reg->impl->jobs); |
695 | + upstart->pauseEventEmitted(upstart->sig_appResumed, sparams, reg); |
696 | + }, /* callback */ |
697 | + data, /* user data */ |
698 | + [](gpointer user_data) { |
699 | + auto data = reinterpret_cast<upstartEventData*>(user_data); |
700 | + delete data; |
701 | + }); /* user data destroy */ |
702 | + |
703 | + return true; |
704 | + }); |
705 | + }); |
706 | + |
707 | + return sig_appResumed; |
708 | +} |
709 | + |
710 | /** Initialize the CGManager connection, including a timeout to disconnect |
711 | as CGManager doesn't free resources entirely well. So it's better if |
712 | we connect and disconnect occationally */ |
713 | |
714 | === modified file 'libubuntu-app-launch/jobs-upstart.h' |
715 | --- libubuntu-app-launch/jobs-upstart.h 2016-11-10 21:58:53 +0000 |
716 | +++ libubuntu-app-launch/jobs-upstart.h 2016-11-10 21:58:53 +0000 |
717 | @@ -54,6 +54,16 @@ |
718 | |
719 | virtual std::vector<std::shared_ptr<instance::Base>> instances(const AppID& appID, const std::string& job) override; |
720 | |
721 | + /* Signals to apps */ |
722 | + virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStarted() override; |
723 | + virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStopped() override; |
724 | + virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, Registry::FailureType>& |
725 | + appFailed() override; |
726 | + virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& |
727 | + appPaused() override; |
728 | + virtual core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& |
729 | + appResumed() override; |
730 | + |
731 | std::vector<pid_t> pidsFromCgroup(const std::string& jobpath); |
732 | |
733 | std::list<std::string> upstartInstancesForJob(const std::string& job); |
734 | @@ -67,6 +77,31 @@ |
735 | /** Getting the Upstart job path is relatively expensive in |
736 | that it requires a DBus call. Worth keeping a cache of. */ |
737 | std::map<std::string, std::string> upstartJobPathCache_; |
738 | + |
739 | + guint handle_appStarted{0}; /**< GDBus signal watcher handle for app started signal */ |
740 | + guint handle_appStopped{0}; /**< GDBus signal watcher handle for app stopped signal */ |
741 | + guint handle_appFailed{0}; /**< GDBus signal watcher handle for app failed signal */ |
742 | + guint handle_appPaused{0}; /**< GDBus signal watcher handle for app paused signal */ |
743 | + guint handle_appResumed{0}; /**< GDBus signal watcher handle for app resumed signal */ |
744 | + |
745 | + std::once_flag flag_appStarted; /**< Variable to track to see if signal handlers are installed for application |
746 | + started */ |
747 | + std::once_flag flag_appStopped; /**< Variable to track to see if signal handlers are installed for application |
748 | + stopped */ |
749 | + std::once_flag |
750 | + flag_appFailed; /**< Variable to track to see if signal handlers are installed for application failed */ |
751 | + std::once_flag |
752 | + flag_appPaused; /**< Variable to track to see if signal handlers are installed for application paused */ |
753 | + std::once_flag flag_appResumed; /**< Variable to track to see if signal handlers are installed for application |
754 | + resumed */ |
755 | + |
756 | + void upstartEventEmitted(core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& signal, |
757 | + std::shared_ptr<GVariant> params, |
758 | + const std::shared_ptr<Registry>& reg); |
759 | + void pauseEventEmitted( |
760 | + core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& signal, |
761 | + const std::shared_ptr<GVariant>& params, |
762 | + const std::shared_ptr<Registry>& reg); |
763 | }; |
764 | |
765 | } // namespace manager |
766 | |
767 | === modified file 'libubuntu-app-launch/registry-impl.cpp' |
768 | --- libubuntu-app-launch/registry-impl.cpp 2016-11-10 21:58:53 +0000 |
769 | +++ libubuntu-app-launch/registry-impl.cpp 2016-11-10 21:58:53 +0000 |
770 | @@ -36,23 +36,6 @@ |
771 | zgLog_.reset(); |
772 | jobs.reset(); |
773 | |
774 | - auto dohandle = [&](guint& handle) { |
775 | - if (handle != 0) |
776 | - { |
777 | - g_dbus_connection_signal_unsubscribe(_dbus.get(), handle); |
778 | - handle = 0; |
779 | - } |
780 | - }; |
781 | - |
782 | - dohandle(handle_appStarted); |
783 | - dohandle(handle_appStopped); |
784 | - dohandle(handle_appFailed); |
785 | - dohandle(handle_appPaused); |
786 | - dohandle(handle_appResumed); |
787 | - dohandle(handle_managerSignalFocus); |
788 | - dohandle(handle_managerSignalResume); |
789 | - dohandle(handle_managerSignalStarting); |
790 | - |
791 | if (_dbus) |
792 | g_dbus_connection_flush_sync(_dbus.get(), nullptr, nullptr); |
793 | _dbus.reset(); |
794 | @@ -301,194 +284,6 @@ |
795 | return _iconFinders[basePath]; |
796 | } |
797 | |
798 | -/** Structure to track the data needed for upstart events. This cleans |
799 | - up the lifecycle as we're passing this as a pointer through the |
800 | - GLib calls. */ |
801 | -struct upstartEventData |
802 | -{ |
803 | - /** Keeping a weak pointer because the handle is held by |
804 | - the registry implementation. */ |
805 | - std::weak_ptr<Registry> weakReg; |
806 | -}; |
807 | - |
808 | -/** Take the GVariant of parameters and turn them into an application and |
809 | - and instance. Easier to read in the smaller function */ |
810 | -std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> Registry::Impl::managerParams( |
811 | - const std::shared_ptr<GVariant>& params, const std::shared_ptr<Registry>& reg) |
812 | -{ |
813 | - std::shared_ptr<Application> app; |
814 | - std::shared_ptr<Application::Instance> instance; |
815 | - |
816 | - const gchar* cappid = nullptr; |
817 | - g_variant_get(params.get(), "(&s)", &cappid); |
818 | - |
819 | - auto appid = ubuntu::app_launch::AppID::find(reg, cappid); |
820 | - app = ubuntu::app_launch::Application::create(appid, reg); |
821 | - |
822 | - return std::make_tuple(app, instance); |
823 | -} |
824 | - |
825 | -/** Used to store data for manager based signal handlers. Has a link to the |
826 | - registry and the callback to use in a C++ style. */ |
827 | -struct managerEventData |
828 | -{ |
829 | - /* Keeping a weak pointer because the handle is held by |
830 | - the registry implementation. */ |
831 | - std::weak_ptr<Registry> weakReg; |
832 | - std::function<void(const std::shared_ptr<Registry>& reg, |
833 | - const std::shared_ptr<Application>& app, |
834 | - const std::shared_ptr<Application::Instance>& instance, |
835 | - const std::shared_ptr<GDBusConnection>&, |
836 | - const std::string&, |
837 | - const std::shared_ptr<GVariant>&)> |
838 | - func; |
839 | -}; |
840 | - |
841 | -/** Register for a signal for the manager. All of the signals needed this same |
842 | - code so it got pulled out into a function. Takes the same of the signal, the registry |
843 | - that we're using and a function to call after we've messaged all the parameters |
844 | - into being something C++-ish. */ |
845 | -guint Registry::Impl::managerSignalHelper(const std::shared_ptr<Registry>& reg, |
846 | - const std::string& signalname, |
847 | - std::function<void(const std::shared_ptr<Registry>& reg, |
848 | - const std::shared_ptr<Application>& app, |
849 | - const std::shared_ptr<Application::Instance>& instance, |
850 | - const std::shared_ptr<GDBusConnection>&, |
851 | - const std::string&, |
852 | - const std::shared_ptr<GVariant>&)> responsefunc) |
853 | -{ |
854 | - managerEventData* focusdata = new managerEventData{reg, responsefunc}; |
855 | - |
856 | - return g_dbus_connection_signal_subscribe( |
857 | - reg->impl->_dbus.get(), /* bus */ |
858 | - nullptr, /* sender */ |
859 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
860 | - signalname.c_str(), /* signal */ |
861 | - "/", /* path */ |
862 | - nullptr, /* arg0 */ |
863 | - G_DBUS_SIGNAL_FLAGS_NONE, |
864 | - [](GDBusConnection* cconn, const gchar* csender, const gchar*, const gchar*, const gchar*, GVariant* params, |
865 | - gpointer user_data) -> void { |
866 | - auto data = reinterpret_cast<managerEventData*>(user_data); |
867 | - auto reg = data->weakReg.lock(); |
868 | - |
869 | - /* If we're still conneted and the manager has been cleared |
870 | - we'll just be a no-op */ |
871 | - if (!reg->impl->manager_) |
872 | - { |
873 | - return; |
874 | - } |
875 | - |
876 | - auto vparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
877 | - auto conn = std::shared_ptr<GDBusConnection>(reinterpret_cast<GDBusConnection*>(g_object_ref(cconn)), |
878 | - [](GDBusConnection* con) { g_clear_object(&con); }); |
879 | - std::string sender = csender; |
880 | - std::shared_ptr<Application> app; |
881 | - std::shared_ptr<Application::Instance> instance; |
882 | - |
883 | - std::tie(app, instance) = managerParams(vparams, reg); |
884 | - |
885 | - data->func(reg, app, instance, conn, sender, vparams); |
886 | - }, |
887 | - focusdata, |
888 | - [](gpointer user_data) { |
889 | - auto data = reinterpret_cast<managerEventData*>(user_data); |
890 | - delete data; |
891 | - }); /* user data destroy */ |
892 | -} |
893 | - |
894 | -/** Set the manager for the registry. This includes tracking the pointer |
895 | - as well as setting up the signals to call back into the manager. The |
896 | - signals are only setup once per registry even if the manager is cleared |
897 | - and changed again. They will just be no-op's in those cases. |
898 | -*/ |
899 | -void Registry::Impl::setManager(std::shared_ptr<Registry::Manager> manager, std::shared_ptr<Registry> reg) |
900 | -{ |
901 | - if (reg->impl->manager_) |
902 | - { |
903 | - throw std::runtime_error("Already have a manager and trying to set another"); |
904 | - } |
905 | - |
906 | - g_debug("Setting a new manager"); |
907 | - reg->impl->manager_ = manager; |
908 | - |
909 | - std::call_once(reg->impl->flag_managerSignals, [reg]() { |
910 | - if (!reg->impl->thread.executeOnThread<bool>([reg]() { |
911 | - reg->impl->handle_managerSignalFocus = managerSignalHelper( |
912 | - reg, "UnityFocusRequest", |
913 | - [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app, |
914 | - const std::shared_ptr<Application::Instance>& instance, |
915 | - const std::shared_ptr<GDBusConnection>& conn, const std::string& sender, |
916 | - const std::shared_ptr<GVariant>& params) { |
917 | - /* Nothing to do today */ |
918 | - reg->impl->manager_->focusRequest(app, instance, [](bool response) { |
919 | - /* NOTE: We have no clue what thread this is gonna be |
920 | - executed on, but since we're just talking to the GDBus |
921 | - thread it isn't an issue today. Be careful in changing |
922 | - this code. */ |
923 | - }); |
924 | - }); |
925 | - reg->impl->handle_managerSignalStarting = managerSignalHelper( |
926 | - reg, "UnityStartingBroadcast", |
927 | - [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app, |
928 | - const std::shared_ptr<Application::Instance>& instance, |
929 | - const std::shared_ptr<GDBusConnection>& conn, const std::string& sender, |
930 | - const std::shared_ptr<GVariant>& params) { |
931 | - |
932 | - reg->impl->manager_->startingRequest(app, instance, [conn, sender, params](bool response) { |
933 | - /* NOTE: We have no clue what thread this is gonna be |
934 | - executed on, but since we're just talking to the GDBus |
935 | - thread it isn't an issue today. Be careful in changing |
936 | - this code. */ |
937 | - if (response) |
938 | - { |
939 | - g_dbus_connection_emit_signal(conn.get(), sender.c_str(), /* destination */ |
940 | - "/", /* path */ |
941 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
942 | - "UnityStartingSignal", /* signal */ |
943 | - params.get(), /* params, the same */ |
944 | - nullptr); /* error */ |
945 | - } |
946 | - }); |
947 | - }); |
948 | - reg->impl->handle_managerSignalResume = managerSignalHelper( |
949 | - reg, "UnityResumeRequest", |
950 | - [](const std::shared_ptr<Registry>& reg, const std::shared_ptr<Application>& app, |
951 | - const std::shared_ptr<Application::Instance>& instance, |
952 | - const std::shared_ptr<GDBusConnection>& conn, const std::string& sender, |
953 | - const std::shared_ptr<GVariant>& params) { |
954 | - reg->impl->manager_->resumeRequest(app, instance, [conn, sender, params](bool response) { |
955 | - /* NOTE: We have no clue what thread this is gonna be |
956 | - executed on, but since we're just talking to the GDBus |
957 | - thread it isn't an issue today. Be careful in changing |
958 | - this code. */ |
959 | - if (response) |
960 | - { |
961 | - g_dbus_connection_emit_signal(conn.get(), sender.c_str(), /* destination */ |
962 | - "/", /* path */ |
963 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
964 | - "UnityResumeResponse", /* signal */ |
965 | - params.get(), /* params, the same */ |
966 | - nullptr); /* error */ |
967 | - } |
968 | - }); |
969 | - }); |
970 | - |
971 | - return true; |
972 | - })) |
973 | - { |
974 | - g_warning("Unable to install manager signals"); |
975 | - } |
976 | - }); |
977 | -} |
978 | - |
979 | -/** Clear the manager pointer */ |
980 | -void Registry::Impl::clearManager() |
981 | -{ |
982 | - g_debug("Clearing the manager"); |
983 | - manager_.reset(); |
984 | -} |
985 | - |
986 | /** App start watching, if we're registered for the signal we |
987 | can't wait on it. We are making this static right now because |
988 | we need it to go across the C and C++ APIs smoothly, and those |
989 | @@ -510,301 +305,5 @@ |
990 | return watchingAppStarting_; |
991 | } |
992 | |
993 | -/** Regex to parse the JOB environment variable from Upstart */ |
994 | -std::regex jobenv_regex{"^JOB=(application\\-(?:click|snap|legacy))$"}; |
995 | -/** Regex to parse the INSTANCE environment variable from Upstart */ |
996 | -std::regex instanceenv_regex{"^INSTANCE=(.*?)(?:\\-([0-9]*))?+$"}; |
997 | - |
998 | -/** Core of most of the events that come from Upstart directly. Includes parsing of the |
999 | - Upstart event environment and calling the appropriate signal with the right Application |
1000 | - object and eventually its instance */ |
1001 | -void Registry::Impl::upstartEventEmitted( |
1002 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& signal, |
1003 | - std::shared_ptr<GVariant> params, |
1004 | - const std::shared_ptr<Registry>& reg) |
1005 | -{ |
1006 | - std::string jobname; |
1007 | - std::string sappid; |
1008 | - std::string instance; |
1009 | - |
1010 | - gchar* env = nullptr; |
1011 | - GVariant* envs = g_variant_get_child_value(params.get(), 1); |
1012 | - GVariantIter iter; |
1013 | - g_variant_iter_init(&iter, envs); |
1014 | - |
1015 | - while (g_variant_iter_loop(&iter, "s", &env)) |
1016 | - { |
1017 | - std::smatch match; |
1018 | - std::string senv = env; |
1019 | - |
1020 | - if (std::regex_match(senv, match, jobenv_regex)) |
1021 | - { |
1022 | - jobname = match[1].str(); |
1023 | - } |
1024 | - else if (std::regex_match(senv, match, instanceenv_regex)) |
1025 | - { |
1026 | - sappid = match[1].str(); |
1027 | - instance = match[2].str(); |
1028 | - } |
1029 | - } |
1030 | - |
1031 | - g_variant_unref(envs); |
1032 | - |
1033 | - if (jobname.empty()) |
1034 | - { |
1035 | - return; |
1036 | - } |
1037 | - |
1038 | - g_debug("Upstart Event for job '%s' appid '%s' instance '%s'", jobname.c_str(), sappid.c_str(), instance.c_str()); |
1039 | - |
1040 | - auto appid = AppID::find(reg, sappid); |
1041 | - auto app = Application::create(appid, reg); |
1042 | - |
1043 | - // TODO: Figure otu creating instances |
1044 | - |
1045 | - signal(app, {}); |
1046 | -} |
1047 | - |
1048 | -/** Grab the signal object for application startup. If we're not already listing for |
1049 | - those signals this sets up a listener for them. */ |
1050 | -core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& Registry::Impl::appStarted( |
1051 | - const std::shared_ptr<Registry>& reg) |
1052 | -{ |
1053 | - std::call_once(flag_appStarted, [reg]() { |
1054 | - reg->impl->thread.executeOnThread<bool>([reg]() { |
1055 | - upstartEventData* data = new upstartEventData{reg}; |
1056 | - |
1057 | - reg->impl->handle_appStarted = g_dbus_connection_signal_subscribe( |
1058 | - reg->impl->_dbus.get(), /* bus */ |
1059 | - nullptr, /* sender */ |
1060 | - DBUS_INTERFACE_UPSTART, /* interface */ |
1061 | - "EventEmitted", /* signal */ |
1062 | - DBUS_PATH_UPSTART, /* path */ |
1063 | - "started", /* arg0 */ |
1064 | - G_DBUS_SIGNAL_FLAGS_NONE, |
1065 | - [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
1066 | - gpointer user_data) -> void { |
1067 | - auto data = reinterpret_cast<upstartEventData*>(user_data); |
1068 | - auto reg = data->weakReg.lock(); |
1069 | - auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
1070 | - reg->impl->upstartEventEmitted(reg->impl->sig_appStarted, sparams, reg); |
1071 | - }, /* callback */ |
1072 | - data, /* user data */ |
1073 | - [](gpointer user_data) { |
1074 | - auto data = reinterpret_cast<upstartEventData*>(user_data); |
1075 | - delete data; |
1076 | - }); /* user data destroy */ |
1077 | - |
1078 | - return true; |
1079 | - }); |
1080 | - }); |
1081 | - |
1082 | - return sig_appStarted; |
1083 | -} |
1084 | - |
1085 | -/** Grab the signal object for application stopping. If we're not already listing for |
1086 | - those signals this sets up a listener for them. */ |
1087 | -core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& Registry::Impl::appStopped( |
1088 | - const std::shared_ptr<Registry>& reg) |
1089 | -{ |
1090 | - std::call_once(flag_appStopped, [reg]() { |
1091 | - reg->impl->thread.executeOnThread<bool>([reg]() { |
1092 | - upstartEventData* data = new upstartEventData{reg}; |
1093 | - |
1094 | - reg->impl->handle_appStopped = g_dbus_connection_signal_subscribe( |
1095 | - reg->impl->_dbus.get(), /* bus */ |
1096 | - nullptr, /* sender */ |
1097 | - DBUS_INTERFACE_UPSTART, /* interface */ |
1098 | - "EventEmitted", /* signal */ |
1099 | - DBUS_PATH_UPSTART, /* path */ |
1100 | - "stopped", /* arg0 */ |
1101 | - G_DBUS_SIGNAL_FLAGS_NONE, |
1102 | - [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
1103 | - gpointer user_data) -> void { |
1104 | - auto data = reinterpret_cast<upstartEventData*>(user_data); |
1105 | - auto reg = data->weakReg.lock(); |
1106 | - auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
1107 | - reg->impl->upstartEventEmitted(reg->impl->sig_appStopped, sparams, reg); |
1108 | - }, /* callback */ |
1109 | - data, /* user data */ |
1110 | - [](gpointer user_data) { |
1111 | - auto data = reinterpret_cast<upstartEventData*>(user_data); |
1112 | - delete data; |
1113 | - }); /* user data destroy */ |
1114 | - |
1115 | - return true; |
1116 | - }); |
1117 | - }); |
1118 | - |
1119 | - return sig_appStopped; |
1120 | -} |
1121 | - |
1122 | -/** Grab the signal object for application failing. If we're not already listing for |
1123 | - those signals this sets up a listener for them. */ |
1124 | -core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, Registry::FailureType>& |
1125 | - Registry::Impl::appFailed(const std::shared_ptr<Registry>& reg) |
1126 | -{ |
1127 | - std::call_once(flag_appFailed, [reg]() { |
1128 | - reg->impl->thread.executeOnThread<bool>([reg]() { |
1129 | - upstartEventData* data = new upstartEventData{reg}; |
1130 | - |
1131 | - reg->impl->handle_appFailed = g_dbus_connection_signal_subscribe( |
1132 | - reg->impl->_dbus.get(), /* bus */ |
1133 | - nullptr, /* sender */ |
1134 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
1135 | - "ApplicationFailed", /* signal */ |
1136 | - "/", /* path */ |
1137 | - nullptr, /* arg0 */ |
1138 | - G_DBUS_SIGNAL_FLAGS_NONE, |
1139 | - [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
1140 | - gpointer user_data) -> void { |
1141 | - auto data = reinterpret_cast<upstartEventData*>(user_data); |
1142 | - auto reg = data->weakReg.lock(); |
1143 | - |
1144 | - const gchar* sappid = NULL; |
1145 | - const gchar* typestr = NULL; |
1146 | - |
1147 | - Registry::FailureType type = Registry::FailureType::CRASH; |
1148 | - g_variant_get(params, "(&s&s)", &sappid, &typestr); |
1149 | - |
1150 | - if (g_strcmp0("crash", typestr) == 0) |
1151 | - { |
1152 | - type = Registry::FailureType::CRASH; |
1153 | - } |
1154 | - else if (g_strcmp0("start-failure", typestr) == 0) |
1155 | - { |
1156 | - type = Registry::FailureType::START_FAILURE; |
1157 | - } |
1158 | - else |
1159 | - { |
1160 | - g_warning("Application failure type '%s' unknown, reporting as a crash", typestr); |
1161 | - } |
1162 | - |
1163 | - auto appid = AppID::find(reg, sappid); |
1164 | - auto app = Application::create(appid, reg); |
1165 | - |
1166 | - /* TODO: Instance issues */ |
1167 | - |
1168 | - reg->impl->sig_appFailed(app, {}, type); |
1169 | - }, /* callback */ |
1170 | - data, /* user data */ |
1171 | - [](gpointer user_data) { |
1172 | - auto data = reinterpret_cast<upstartEventData*>(user_data); |
1173 | - delete data; |
1174 | - }); /* user data destroy */ |
1175 | - |
1176 | - return true; |
1177 | - }); |
1178 | - }); |
1179 | - |
1180 | - return sig_appFailed; |
1181 | -} |
1182 | - |
1183 | -/** Core handler for pause and resume events. Includes turning the GVariant |
1184 | - pid list into a std::vector and getting the application object. */ |
1185 | -void Registry::Impl::pauseEventEmitted( |
1186 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& signal, |
1187 | - const std::shared_ptr<GVariant>& params, |
1188 | - const std::shared_ptr<Registry>& reg) |
1189 | -{ |
1190 | - std::vector<pid_t> pids; |
1191 | - GVariant* vappid = g_variant_get_child_value(params.get(), 0); |
1192 | - GVariant* vpids = g_variant_get_child_value(params.get(), 1); |
1193 | - guint64 pid; |
1194 | - GVariantIter thispid; |
1195 | - g_variant_iter_init(&thispid, vpids); |
1196 | - |
1197 | - while (g_variant_iter_loop(&thispid, "t", &pid)) |
1198 | - { |
1199 | - pids.emplace_back(pid); |
1200 | - } |
1201 | - |
1202 | - auto cappid = g_variant_get_string(vappid, NULL); |
1203 | - auto appid = ubuntu::app_launch::AppID::find(reg, cappid); |
1204 | - auto app = Application::create(appid, reg); |
1205 | - |
1206 | - /* TODO: Instance */ |
1207 | - signal(app, {}, pids); |
1208 | - |
1209 | - g_variant_unref(vappid); |
1210 | - g_variant_unref(vpids); |
1211 | - |
1212 | - return; |
1213 | -} |
1214 | - |
1215 | -/** Grab the signal object for application paused. If we're not already listing for |
1216 | - those signals this sets up a listener for them. */ |
1217 | -core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& |
1218 | - Registry::Impl::appPaused(const std::shared_ptr<Registry>& reg) |
1219 | -{ |
1220 | - std::call_once(flag_appPaused, [&]() { |
1221 | - reg->impl->thread.executeOnThread<bool>([reg]() { |
1222 | - upstartEventData* data = new upstartEventData{reg}; |
1223 | - |
1224 | - reg->impl->handle_appPaused = g_dbus_connection_signal_subscribe( |
1225 | - reg->impl->_dbus.get(), /* bus */ |
1226 | - nullptr, /* sender */ |
1227 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
1228 | - "ApplicationPaused", /* signal */ |
1229 | - "/", /* path */ |
1230 | - nullptr, /* arg0 */ |
1231 | - G_DBUS_SIGNAL_FLAGS_NONE, |
1232 | - [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
1233 | - gpointer user_data) -> void { |
1234 | - auto data = reinterpret_cast<upstartEventData*>(user_data); |
1235 | - auto reg = data->weakReg.lock(); |
1236 | - auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
1237 | - reg->impl->pauseEventEmitted(reg->impl->sig_appPaused, sparams, reg); |
1238 | - }, /* callback */ |
1239 | - data, /* user data */ |
1240 | - [](gpointer user_data) { |
1241 | - auto data = reinterpret_cast<upstartEventData*>(user_data); |
1242 | - delete data; |
1243 | - }); /* user data destroy */ |
1244 | - |
1245 | - return true; |
1246 | - }); |
1247 | - }); |
1248 | - |
1249 | - return sig_appPaused; |
1250 | -} |
1251 | - |
1252 | -/** Grab the signal object for application resumed. If we're not already listing for |
1253 | - those signals this sets up a listener for them. */ |
1254 | -core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& |
1255 | - Registry::Impl::appResumed(const std::shared_ptr<Registry>& reg) |
1256 | -{ |
1257 | - std::call_once(flag_appResumed, [&]() { |
1258 | - reg->impl->thread.executeOnThread<bool>([reg]() { |
1259 | - upstartEventData* data = new upstartEventData{reg}; |
1260 | - |
1261 | - reg->impl->handle_appResumed = g_dbus_connection_signal_subscribe( |
1262 | - reg->impl->_dbus.get(), /* bus */ |
1263 | - nullptr, /* sender */ |
1264 | - "com.canonical.UbuntuAppLaunch", /* interface */ |
1265 | - "ApplicationResumed", /* signal */ |
1266 | - "/", /* path */ |
1267 | - nullptr, /* arg0 */ |
1268 | - G_DBUS_SIGNAL_FLAGS_NONE, |
1269 | - [](GDBusConnection*, const gchar*, const gchar*, const gchar*, const gchar*, GVariant* params, |
1270 | - gpointer user_data) -> void { |
1271 | - auto data = reinterpret_cast<upstartEventData*>(user_data); |
1272 | - auto reg = data->weakReg.lock(); |
1273 | - auto sparams = std::shared_ptr<GVariant>(g_variant_ref(params), g_variant_unref); |
1274 | - reg->impl->pauseEventEmitted(reg->impl->sig_appResumed, sparams, reg); |
1275 | - }, /* callback */ |
1276 | - data, /* user data */ |
1277 | - [](gpointer user_data) { |
1278 | - auto data = reinterpret_cast<upstartEventData*>(user_data); |
1279 | - delete data; |
1280 | - }); /* user data destroy */ |
1281 | - |
1282 | - return true; |
1283 | - }); |
1284 | - }); |
1285 | - |
1286 | - return sig_appResumed; |
1287 | -} |
1288 | - |
1289 | } // namespace app_launch |
1290 | } // namespace ubuntu |
1291 | |
1292 | === modified file 'libubuntu-app-launch/registry-impl.h' |
1293 | --- libubuntu-app-launch/registry-impl.h 2016-11-10 21:58:53 +0000 |
1294 | +++ libubuntu-app-launch/registry-impl.h 2016-11-10 21:58:53 +0000 |
1295 | @@ -72,23 +72,11 @@ |
1296 | |
1297 | std::shared_ptr<IconFinder> getIconFinder(std::string basePath); |
1298 | |
1299 | - void zgSendEvent(AppID appid, const std::string& eventtype); |
1300 | + virtual void zgSendEvent(AppID appid, const std::string& eventtype); |
1301 | |
1302 | static std::string printJson(std::shared_ptr<JsonObject> jsonobj); |
1303 | static std::string printJson(std::shared_ptr<JsonNode> jsonnode); |
1304 | |
1305 | - /* Signals to discover what is happening to apps */ |
1306 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStarted( |
1307 | - const std::shared_ptr<Registry>& reg); |
1308 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& appStopped( |
1309 | - const std::shared_ptr<Registry>& reg); |
1310 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, FailureType>& appFailed( |
1311 | - const std::shared_ptr<Registry>& reg); |
1312 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& appPaused( |
1313 | - const std::shared_ptr<Registry>& reg); |
1314 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& appResumed( |
1315 | - const std::shared_ptr<Registry>& reg); |
1316 | - |
1317 | /* Signal Hints */ |
1318 | /* NOTE: Static because we don't have registry instances in the C |
1319 | code right now. We want these to not be static in the future */ |
1320 | @@ -96,65 +84,11 @@ |
1321 | static bool isWatchingAppStarting(); |
1322 | |
1323 | private: |
1324 | - Registry* _registry; /**< The Registry that we're spawned from */ |
1325 | - std::shared_ptr<Registry::Manager> manager_; /**< Application manager if registered */ |
1326 | + Registry* _registry; /**< The Registry that we're spawned from */ |
1327 | |
1328 | std::shared_ptr<ClickDB> _clickDB; /**< Shared instance of the Click Database */ |
1329 | std::shared_ptr<ClickUser> _clickUser; /**< Click database filtered by the current user */ |
1330 | |
1331 | - /** Signal object for applications started */ |
1332 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> sig_appStarted; |
1333 | - /** Signal object for applications stopped */ |
1334 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> sig_appStopped; |
1335 | - /** Signal object for applications failed */ |
1336 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, FailureType> sig_appFailed; |
1337 | - /** Signal object for applications paused */ |
1338 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&> |
1339 | - sig_appPaused; |
1340 | - /** Signal object for applications resumed */ |
1341 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&> |
1342 | - sig_appResumed; |
1343 | - |
1344 | - guint handle_appStarted{0}; /**< GDBus signal watcher handle for app started signal */ |
1345 | - guint handle_appStopped{0}; /**< GDBus signal watcher handle for app stopped signal */ |
1346 | - guint handle_appFailed{0}; /**< GDBus signal watcher handle for app failed signal */ |
1347 | - guint handle_appPaused{0}; /**< GDBus signal watcher handle for app paused signal */ |
1348 | - guint handle_appResumed{0}; /**< GDBus signal watcher handle for app resumed signal */ |
1349 | - guint handle_managerSignalFocus{0}; /**< GDBus signal watcher handle for app focused signal */ |
1350 | - guint handle_managerSignalResume{0}; /**< GDBus signal watcher handle for app resumed signal */ |
1351 | - guint handle_managerSignalStarting{0}; /**< GDBus signal watcher handle for app starting signal */ |
1352 | - |
1353 | - std::once_flag flag_appStarted; /**< Variable to track to see if signal handlers are installed for application |
1354 | - started */ |
1355 | - std::once_flag flag_appStopped; /**< Variable to track to see if signal handlers are installed for application |
1356 | - stopped */ |
1357 | - std::once_flag |
1358 | - flag_appFailed; /**< Variable to track to see if signal handlers are installed for application failed */ |
1359 | - std::once_flag |
1360 | - flag_appPaused; /**< Variable to track to see if signal handlers are installed for application paused */ |
1361 | - std::once_flag flag_appResumed; /**< Variable to track to see if signal handlers are installed for application |
1362 | - resumed */ |
1363 | - std::once_flag flag_managerSignals; /**< Variable to track to see if signal handlers are installed for the manager |
1364 | - signals of focused, resumed and starting */ |
1365 | - |
1366 | - void upstartEventEmitted(core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& signal, |
1367 | - std::shared_ptr<GVariant> params, |
1368 | - const std::shared_ptr<Registry>& reg); |
1369 | - void pauseEventEmitted( |
1370 | - core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& signal, |
1371 | - const std::shared_ptr<GVariant>& params, |
1372 | - const std::shared_ptr<Registry>& reg); |
1373 | - static std::tuple<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>> managerParams( |
1374 | - const std::shared_ptr<GVariant>& params, const std::shared_ptr<Registry>& reg); |
1375 | - static guint managerSignalHelper(const std::shared_ptr<Registry>& reg, |
1376 | - const std::string& signalname, |
1377 | - std::function<void(const std::shared_ptr<Registry>& reg, |
1378 | - const std::shared_ptr<Application>& app, |
1379 | - const std::shared_ptr<Application::Instance>& instance, |
1380 | - const std::shared_ptr<GDBusConnection>&, |
1381 | - const std::string&, |
1382 | - const std::shared_ptr<GVariant>&)> responsefunc); |
1383 | - |
1384 | void initClick(); |
1385 | |
1386 | /** Shared instance of the Zeitgeist Log */ |
1387 | |
1388 | === modified file 'libubuntu-app-launch/registry.cpp' |
1389 | --- libubuntu-app-launch/registry.cpp 2016-11-10 21:58:53 +0000 |
1390 | +++ libubuntu-app-launch/registry.cpp 2016-11-10 21:58:53 +0000 |
1391 | @@ -80,14 +80,29 @@ |
1392 | return list; |
1393 | } |
1394 | |
1395 | +/* Quick little helper to bundle up standard code */ |
1396 | +inline void setJobs(const std::shared_ptr<Registry>& registry) |
1397 | +{ |
1398 | + if (!registry->impl->jobs) |
1399 | + { |
1400 | + registry->impl->jobs = jobs::manager::Base::determineFactory(registry); |
1401 | + } |
1402 | +} |
1403 | + |
1404 | void Registry::setManager(std::shared_ptr<Manager> manager, std::shared_ptr<Registry> registry) |
1405 | { |
1406 | - Registry::Impl::setManager(manager, registry); |
1407 | + setJobs(registry); |
1408 | + registry->impl->jobs->setManager(manager); |
1409 | } |
1410 | |
1411 | void Registry::clearManager() |
1412 | { |
1413 | - impl->clearManager(); |
1414 | + if (!impl->jobs) |
1415 | + { |
1416 | + return; |
1417 | + } |
1418 | + |
1419 | + impl->jobs->clearManager(); |
1420 | } |
1421 | |
1422 | std::shared_ptr<Registry> defaultRegistry; |
1423 | @@ -109,31 +124,36 @@ |
1424 | core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& Registry::appStarted( |
1425 | const std::shared_ptr<Registry>& reg) |
1426 | { |
1427 | - return reg->impl->appStarted(reg); |
1428 | + setJobs(reg); |
1429 | + return reg->impl->jobs->appStarted(); |
1430 | } |
1431 | |
1432 | core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>>& Registry::appStopped( |
1433 | const std::shared_ptr<Registry>& reg) |
1434 | { |
1435 | - return reg->impl->appStopped(reg); |
1436 | + setJobs(reg); |
1437 | + return reg->impl->jobs->appStopped(); |
1438 | } |
1439 | |
1440 | core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, Registry::FailureType>& |
1441 | Registry::appFailed(const std::shared_ptr<Registry>& reg) |
1442 | { |
1443 | - return reg->impl->appFailed(reg); |
1444 | + setJobs(reg); |
1445 | + return reg->impl->jobs->appFailed(); |
1446 | } |
1447 | |
1448 | core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& |
1449 | Registry::appPaused(const std::shared_ptr<Registry>& reg) |
1450 | { |
1451 | - return reg->impl->appPaused(reg); |
1452 | + setJobs(reg); |
1453 | + return reg->impl->jobs->appPaused(); |
1454 | } |
1455 | |
1456 | core::Signal<std::shared_ptr<Application>, std::shared_ptr<Application::Instance>, std::vector<pid_t>&>& |
1457 | Registry::appResumed(const std::shared_ptr<Registry>& reg) |
1458 | { |
1459 | - return reg->impl->appResumed(reg); |
1460 | + setJobs(reg); |
1461 | + return reg->impl->jobs->appResumed(); |
1462 | } |
1463 | |
1464 | } // namespace app_launch |
1465 | |
1466 | === modified file 'tests/CMakeLists.txt' |
1467 | --- tests/CMakeLists.txt 2016-11-10 21:58:53 +0000 |
1468 | +++ tests/CMakeLists.txt 2016-11-10 21:58:53 +0000 |
1469 | @@ -12,23 +12,21 @@ |
1470 | |
1471 | include_directories(${GTEST_INCLUDE_DIR}) |
1472 | |
1473 | -add_library (gtest STATIC |
1474 | - ${GTEST_SOURCE_DIR}/gtest-all.cc |
1475 | - ${GTEST_SOURCE_DIR}/gtest_main.cc) |
1476 | +add_subdirectory("/usr/src/gmock" gmock) |
1477 | |
1478 | # Helper test |
1479 | |
1480 | add_executable (helper-test helper-test.cc) |
1481 | add_definitions ( -DCMAKE_SOURCE_DIR="${CMAKE_CURRENT_SOURCE_DIR}" ) |
1482 | add_definitions ( -DCMAKE_BINARY_DIR="${CMAKE_CURRENT_BINARY_DIR}" ) |
1483 | -target_link_libraries (helper-test helpers gtest ${GTEST_LIBS} ${DBUSTEST_LIBRARIES}) |
1484 | +target_link_libraries (helper-test helpers gtest_main ${GTEST_LIBS} ${DBUSTEST_LIBRARIES}) |
1485 | |
1486 | add_test (helper-test helper-test) |
1487 | |
1488 | # Helper test |
1489 | |
1490 | add_executable (helper-handshake-test helper-handshake-test.cc) |
1491 | -target_link_libraries (helper-handshake-test helpers gtest ${GTEST_LIBS}) |
1492 | +target_link_libraries (helper-handshake-test helpers gtest_main ${GTEST_LIBS}) |
1493 | |
1494 | add_test (helper-handshake-test helper-handshake-test) |
1495 | |
1496 | @@ -45,13 +43,13 @@ |
1497 | add_executable (libual-test |
1498 | libual-test.cc |
1499 | mir-mock.cpp) |
1500 | -target_link_libraries (libual-test gtest ${GTEST_LIBS} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} ubuntu-launcher) |
1501 | +target_link_libraries (libual-test gtest_main ${GTEST_LIBS} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} ubuntu-launcher) |
1502 | |
1503 | add_executable (libual-cpp-test |
1504 | libual-cpp-test.cc |
1505 | ${CMAKE_SOURCE_DIR}/libubuntu-app-launch/glib-thread.cpp |
1506 | mir-mock.cpp) |
1507 | -target_link_libraries (libual-cpp-test gtest ${GTEST_LIBS} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} ubuntu-launcher) |
1508 | +target_link_libraries (libual-cpp-test gtest_main ${GTEST_LIBS} ${LIBUPSTART_LIBRARIES} ${DBUSTEST_LIBRARIES} ubuntu-launcher) |
1509 | |
1510 | add_executable (data-spew |
1511 | data-spew.c) |
1512 | @@ -63,13 +61,21 @@ |
1513 | add_test (NAME libual-test COMMAND libual-test) |
1514 | add_test (NAME libual-cpp-test COMMAND libual-cpp-test) |
1515 | |
1516 | +# Jobs Base Test |
1517 | + |
1518 | +add_executable (jobs-base-test |
1519 | + jobs-base-test.cpp) |
1520 | +target_link_libraries (jobs-base-test gmock_main ${GTEST_LIBS} launcher-static) |
1521 | + |
1522 | +add_test(NAME jobs-base-test COMMAND jobs-base-test) |
1523 | + |
1524 | # Snapd Info Test |
1525 | |
1526 | if(CURL_FOUND) |
1527 | add_definitions ( -DSNAPD_TEST_SOCKET="/tmp/snapd-test-socket" ) |
1528 | add_executable (snapd-info-test |
1529 | snapd-info-test.cpp) |
1530 | -target_link_libraries (snapd-info-test gtest ${GTEST_LIBS} launcher-static) |
1531 | +target_link_libraries (snapd-info-test gtest_main ${GTEST_LIBS} launcher-static) |
1532 | add_test (NAME snapd-info-test COMMAND snapd-info-test) |
1533 | endif() |
1534 | |
1535 | @@ -77,7 +83,7 @@ |
1536 | |
1537 | add_executable (list-apps |
1538 | list-apps.cpp) |
1539 | -target_link_libraries (list-apps gtest ${GTEST_LIBS} launcher-static) |
1540 | +target_link_libraries (list-apps gtest_main ${GTEST_LIBS} launcher-static) |
1541 | add_test (NAME list-apps COMMAND ${CMAKE_CURRENT_BINARY_DIR}/list-apps) |
1542 | |
1543 | # Application Info Desktop |
1544 | @@ -85,7 +91,7 @@ |
1545 | add_executable (application-info-desktop-test |
1546 | application-info-desktop.cpp |
1547 | ) |
1548 | -target_link_libraries (application-info-desktop-test gtest ${GTEST_LIBS} launcher-static) |
1549 | +target_link_libraries (application-info-desktop-test gtest_main ${GTEST_LIBS} launcher-static) |
1550 | |
1551 | add_test (NAME application-info-desktop-test COMMAND application-info-desktop-test) |
1552 | |
1553 | @@ -97,7 +103,7 @@ |
1554 | |
1555 | #sources |
1556 | ${CMAKE_SOURCE_DIR}/libubuntu-app-launch/application-icon-finder.cpp) |
1557 | -target_link_libraries (application-icon-finder-test gtest ${GTEST_LIBS} ubuntu-launcher) |
1558 | +target_link_libraries (application-icon-finder-test gtest_main ${GTEST_LIBS} ubuntu-launcher) |
1559 | |
1560 | add_test (NAME application-icon-finder-test COMMAND application-icon-finder-test) |
1561 | |
1562 | @@ -109,7 +115,7 @@ |
1563 | |
1564 | add_executable (failure-test |
1565 | failure-test.cc) |
1566 | -target_link_libraries (failure-test gtest ${GTEST_LIBS} ubuntu-launcher) |
1567 | +target_link_libraries (failure-test gtest_main ${GTEST_LIBS} ubuntu-launcher) |
1568 | add_test (failure-test failure-test) |
1569 | |
1570 | # ZG Test |
1571 | @@ -118,7 +124,7 @@ |
1572 | |
1573 | add_executable (zg-test |
1574 | zg-test.cc) |
1575 | -target_link_libraries (zg-test gtest ${GTEST_LIBS} ${DBUSTEST_LIBRARIES} ${GIO2_LIBRARIES}) |
1576 | +target_link_libraries (zg-test gtest_main ${GTEST_LIBS} ${DBUSTEST_LIBRARIES} ${GIO2_LIBRARIES}) |
1577 | add_test (zg-test zg-test) |
1578 | |
1579 | # Exec Line Exec Test |
1580 | @@ -130,7 +136,7 @@ |
1581 | |
1582 | add_executable (exec-util-test |
1583 | exec-util-test.cc) |
1584 | -target_link_libraries (exec-util-test gtest ubuntu-launcher ${GTEST_LIBS} ${DBUSTEST_LIBRARIES} ${GIO2_LIBRARIES}) |
1585 | +target_link_libraries (exec-util-test gtest_main ubuntu-launcher ${GTEST_LIBS} ${DBUSTEST_LIBRARIES} ${GIO2_LIBRARIES}) |
1586 | add_test (exec-util-test exec-util-test) |
1587 | |
1588 | # CGroup Reap Test |
1589 | @@ -139,7 +145,7 @@ |
1590 | |
1591 | add_executable (cgroup-reap-test |
1592 | cgroup-reap-test.cc) |
1593 | -target_link_libraries (cgroup-reap-test gtest ${GTEST_LIBS} ${DBUSTEST_LIBRARIES} ${GIO2_LIBRARIES}) |
1594 | +target_link_libraries (cgroup-reap-test gtest_main ${GTEST_LIBS} ${DBUSTEST_LIBRARIES} ${GIO2_LIBRARIES}) |
1595 | add_test (cgroup-reap-test cgroup-reap-test) |
1596 | |
1597 | # Desktop Hook Test |
1598 | @@ -162,6 +168,7 @@ |
1599 | libual-cpp-test.cc |
1600 | list-apps.cpp |
1601 | eventually-fixture.h |
1602 | + jobs-base-test.cpp |
1603 | snapd-info-test.cpp |
1604 | snapd-mock.h |
1605 | zg-test.cc |
1606 | |
1607 | === added file 'tests/jobs-base-test.cpp' |
1608 | --- tests/jobs-base-test.cpp 1970-01-01 00:00:00 +0000 |
1609 | +++ tests/jobs-base-test.cpp 2016-11-10 21:58:53 +0000 |
1610 | @@ -0,0 +1,364 @@ |
1611 | +/* |
1612 | + * Copyright © 2016 Canonical Ltd. |
1613 | + * |
1614 | + * This program is free software: you can redistribute it and/or modify it |
1615 | + * under the terms of the GNU General Public License version 3, as published |
1616 | + * by the Free Software Foundation. |
1617 | + * |
1618 | + * This program is distributed in the hope that it will be useful, but |
1619 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
1620 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1621 | + * PURPOSE. See the GNU General Public License for more details. |
1622 | + * |
1623 | + * You should have received a copy of the GNU General Public License along |
1624 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
1625 | + * |
1626 | + * Authors: |
1627 | + * Ted Gould <ted.gould@canonical.com> |
1628 | + */ |
1629 | + |
1630 | +#include "jobs-base.h" |
1631 | +#include "appid.h" |
1632 | +#include "registry-impl.h" |
1633 | +#include "registry.h" |
1634 | + |
1635 | +#include "eventually-fixture.h" |
1636 | +#include <gmock/gmock.h> |
1637 | +#include <gtest/gtest.h> |
1638 | + |
1639 | +class RegistryImplMock : public ubuntu::app_launch::Registry::Impl |
1640 | +{ |
1641 | +public: |
1642 | + RegistryImplMock(ubuntu::app_launch::Registry* reg) |
1643 | + : ubuntu::app_launch::Registry::Impl(reg) |
1644 | + { |
1645 | + } |
1646 | + |
1647 | + MOCK_METHOD2(zgSendEvent, void(ubuntu::app_launch::AppID, const std::string& eventtype)); |
1648 | +}; |
1649 | + |
1650 | +class RegistryMock : public ubuntu::app_launch::Registry |
1651 | +{ |
1652 | +public: |
1653 | + RegistryMock() |
1654 | + { |
1655 | + impl = std::unique_ptr<RegistryImplMock>(new RegistryImplMock(this)); |
1656 | + } |
1657 | +}; |
1658 | + |
1659 | +class instanceMock : public ubuntu::app_launch::jobs::instance::Base |
1660 | +{ |
1661 | +public: |
1662 | + instanceMock(const ubuntu::app_launch::AppID& appId, |
1663 | + const std::string& job, |
1664 | + const std::string& instance, |
1665 | + const std::vector<ubuntu::app_launch::Application::URL>& urls, |
1666 | + const std::shared_ptr<ubuntu::app_launch::Registry>& registry) |
1667 | + : ubuntu::app_launch::jobs::instance::Base(appId, job, instance, urls, registry) |
1668 | + { |
1669 | + } |
1670 | + |
1671 | + MOCK_METHOD0(primaryPid, pid_t()); |
1672 | + MOCK_METHOD0(logPath, std::string()); |
1673 | + MOCK_METHOD0(pids, std::vector<pid_t>()); |
1674 | + |
1675 | + MOCK_METHOD0(stop, void()); |
1676 | +}; |
1677 | + |
1678 | +class SpewMaster |
1679 | +{ |
1680 | +public: |
1681 | + SpewMaster() |
1682 | + : thread( |
1683 | + [this]() { |
1684 | + gint spewstdout = 0; |
1685 | + std::array<const gchar*, 2> spewline{SPEW_UTILITY, nullptr}; |
1686 | + ASSERT_TRUE(g_spawn_async_with_pipes(NULL, /* directory */ |
1687 | + (char**)spewline.data(), /* command line */ |
1688 | + NULL, /* environment */ |
1689 | + G_SPAWN_DEFAULT, /* flags */ |
1690 | + NULL, /* child setup */ |
1691 | + NULL, /* child setup */ |
1692 | + &pid_, /* pid */ |
1693 | + NULL, /* stdin */ |
1694 | + &spewstdout, /* stdout */ |
1695 | + NULL, /* stderr */ |
1696 | + NULL)); /* error */ |
1697 | + |
1698 | + spewoutchan = g_io_channel_unix_new(spewstdout); |
1699 | + g_io_channel_set_flags(spewoutchan, G_IO_FLAG_NONBLOCK, NULL); |
1700 | + |
1701 | + iosource = g_io_create_watch(spewoutchan, G_IO_IN); |
1702 | + g_source_set_callback(iosource, (GSourceFunc)datain, this, nullptr); |
1703 | + g_source_attach(iosource, g_main_context_get_thread_default()); |
1704 | + |
1705 | + /* Setup our OOM adjust file */ |
1706 | + gchar* procdir = g_strdup_printf(CMAKE_BINARY_DIR "/jobs-base-proc/%d", pid_); |
1707 | + ASSERT_EQ(0, g_mkdir_with_parents(procdir, 0700)); |
1708 | + oomadjfile = g_strdup_printf("%s/oom_score_adj", procdir); |
1709 | + g_free(procdir); |
1710 | + ASSERT_TRUE(g_file_set_contents(oomadjfile, "0", -1, NULL)); |
1711 | + }, |
1712 | + [this]() { |
1713 | + /* Clean up */ |
1714 | + gchar* killstr = g_strdup_printf("kill -9 %d", pid_); |
1715 | + ASSERT_TRUE(g_spawn_command_line_sync(killstr, NULL, NULL, NULL, NULL)); |
1716 | + g_free(killstr); |
1717 | + |
1718 | + g_source_destroy(iosource); |
1719 | + g_io_channel_unref(spewoutchan); |
1720 | + g_clear_pointer(&oomadjfile, g_free); |
1721 | + }) |
1722 | + { |
1723 | + datacnt_ = 0; |
1724 | + } |
1725 | + |
1726 | + ~SpewMaster() |
1727 | + { |
1728 | + } |
1729 | + |
1730 | + std::string oomScore() |
1731 | + { |
1732 | + gchar* oomvalue = nullptr; |
1733 | + g_file_get_contents(oomadjfile, &oomvalue, nullptr, nullptr); |
1734 | + if (oomvalue != nullptr) |
1735 | + { |
1736 | + return std::string(oomvalue); |
1737 | + } |
1738 | + else |
1739 | + { |
1740 | + return {}; |
1741 | + } |
1742 | + } |
1743 | + |
1744 | + GPid pid() |
1745 | + { |
1746 | + return pid_; |
1747 | + } |
1748 | + |
1749 | + gsize dataCnt() |
1750 | + { |
1751 | + g_debug("Data Count for %d: %d", pid_, int(datacnt_)); |
1752 | + return datacnt_; |
1753 | + } |
1754 | + |
1755 | + void reset() |
1756 | + { |
1757 | + bool endofqueue = thread.executeOnThread<bool>([this]() { |
1758 | + while (G_IO_STATUS_AGAIN == g_io_channel_flush(spewoutchan, nullptr)) |
1759 | + ; |
1760 | + return true; /* the main loop has processed */ |
1761 | + }); |
1762 | + g_debug("Reset %d", pid_); |
1763 | + if (endofqueue) |
1764 | + datacnt_ = 0; |
1765 | + else |
1766 | + g_warning("Unable to clear mainloop on reset"); |
1767 | + } |
1768 | + |
1769 | + std::atomic<gsize> datacnt_; |
1770 | + |
1771 | +private: |
1772 | + GPid pid_ = 0; |
1773 | + gchar* oomadjfile = nullptr; |
1774 | + GIOChannel* spewoutchan = nullptr; |
1775 | + GSource* iosource = nullptr; |
1776 | + GLib::ContextThread thread; |
1777 | + |
1778 | + static gboolean datain(GIOChannel* source, GIOCondition cond, gpointer data) |
1779 | + { |
1780 | + auto spew = static_cast<SpewMaster*>(data); |
1781 | + gchar* str = NULL; |
1782 | + gsize len = 0; |
1783 | + GError* error = NULL; |
1784 | + |
1785 | + g_io_channel_read_line(source, &str, &len, NULL, &error); |
1786 | + g_free(str); |
1787 | + |
1788 | + if (error != NULL) |
1789 | + { |
1790 | + g_warning("Unable to read from channel: %s", error->message); |
1791 | + g_error_free(error); |
1792 | + } |
1793 | + |
1794 | + spew->datacnt_ += len; |
1795 | + |
1796 | + return TRUE; |
1797 | + } |
1798 | +}; |
1799 | + |
1800 | +class JobBaseTest : public EventuallyFixture |
1801 | +{ |
1802 | +protected: |
1803 | + std::shared_ptr<RegistryMock> registry; |
1804 | + |
1805 | + virtual void SetUp() |
1806 | + { |
1807 | + registry = std::make_shared<RegistryMock>(); |
1808 | + } |
1809 | + |
1810 | + virtual void TearDown() |
1811 | + { |
1812 | + registry.reset(); |
1813 | + } |
1814 | + |
1815 | + ubuntu::app_launch::AppID simpleAppID() |
1816 | + { |
1817 | + return {ubuntu::app_launch::AppID::Package::from_raw("package"), |
1818 | + ubuntu::app_launch::AppID::AppName::from_raw("appname"), |
1819 | + ubuntu::app_launch::AppID::Version::from_raw("version")}; |
1820 | + } |
1821 | + |
1822 | + std::shared_ptr<instanceMock> simpleInstance() |
1823 | + { |
1824 | + return std::make_shared<instanceMock>(simpleAppID(), "application-job", "1234567890", |
1825 | + std::vector<ubuntu::app_launch::Application::URL>{}, registry); |
1826 | + } |
1827 | +}; |
1828 | + |
1829 | +TEST_F(JobBaseTest, InitTest) |
1830 | +{ |
1831 | + auto instance = simpleInstance(); |
1832 | + |
1833 | + instance.reset(); |
1834 | +} |
1835 | + |
1836 | +TEST_F(JobBaseTest, isRunning) |
1837 | +{ |
1838 | + auto instance = simpleInstance(); |
1839 | + |
1840 | + EXPECT_CALL(*instance, primaryPid()).WillOnce(testing::Return(0)); |
1841 | + |
1842 | + EXPECT_FALSE(instance->isRunning()); |
1843 | + |
1844 | + EXPECT_CALL(*instance, primaryPid()).WillOnce(testing::Return(100)); |
1845 | + |
1846 | + EXPECT_TRUE(instance->isRunning()); |
1847 | +} |
1848 | + |
1849 | +TEST_F(JobBaseTest, pauseResume) |
1850 | +{ |
1851 | + g_setenv("UBUNTU_APP_LAUNCH_OOM_PROC_PATH", CMAKE_BINARY_DIR "/jobs-base-proc", TRUE); |
1852 | + |
1853 | + /* Setup some spew */ |
1854 | + SpewMaster spew; |
1855 | + std::vector<pid_t> pids{spew.pid()}; |
1856 | + |
1857 | + /* Build our instance */ |
1858 | + auto instance = simpleInstance(); |
1859 | + EXPECT_CALL(*instance, pids()).WillRepeatedly(testing::Return(pids)); |
1860 | + |
1861 | + /* Setup registry */ |
1862 | + EXPECT_CALL(dynamic_cast<RegistryImplMock&>(*registry->impl), zgSendEvent(simpleAppID(), ZEITGEIST_ZG_LEAVE_EVENT)) |
1863 | + .WillOnce(testing::Return()); |
1864 | + |
1865 | + /* Make sure it is running */ |
1866 | + EXPECT_EVENTUALLY_NE(0, spew.datacnt_); |
1867 | + |
1868 | + /*** Do Pause ***/ |
1869 | + instance->pause(); |
1870 | + |
1871 | + spew.reset(); |
1872 | + pause(100); // give spew a chance to send data if it is running |
1873 | + |
1874 | + EXPECT_EQ(0, spew.dataCnt()); |
1875 | + |
1876 | + EXPECT_EQ(std::to_string(int(ubuntu::app_launch::oom::paused())), spew.oomScore()); |
1877 | + |
1878 | + /* Setup for Resume */ |
1879 | + EXPECT_CALL(dynamic_cast<RegistryImplMock&>(*registry->impl), zgSendEvent(simpleAppID(), ZEITGEIST_ZG_ACCESS_EVENT)) |
1880 | + .WillOnce(testing::Return()); |
1881 | + |
1882 | + spew.reset(); |
1883 | + EXPECT_EQ(0, spew.dataCnt()); |
1884 | + |
1885 | + /*** Do Resume ***/ |
1886 | + instance->resume(); |
1887 | + |
1888 | + EXPECT_EVENTUALLY_NE(0, spew.datacnt_); |
1889 | + |
1890 | + EXPECT_EQ(std::to_string(int(ubuntu::app_launch::oom::focused())), spew.oomScore()); |
1891 | +} |
1892 | + |
1893 | +TEST_F(JobBaseTest, pauseResumeNone) |
1894 | +{ |
1895 | + std::vector<pid_t> pids{}; |
1896 | + |
1897 | + /* Build our instance */ |
1898 | + auto instance = simpleInstance(); |
1899 | + EXPECT_CALL(*instance, pids()).WillRepeatedly(testing::Return(pids)); |
1900 | + |
1901 | + /* Setup registry */ |
1902 | + EXPECT_CALL(dynamic_cast<RegistryImplMock&>(*registry->impl), zgSendEvent(simpleAppID(), ZEITGEIST_ZG_LEAVE_EVENT)) |
1903 | + .WillOnce(testing::Return()); |
1904 | + |
1905 | + /*** Do Pause ***/ |
1906 | + instance->pause(); |
1907 | + |
1908 | + /* Setup for Resume */ |
1909 | + EXPECT_CALL(dynamic_cast<RegistryImplMock&>(*registry->impl), zgSendEvent(simpleAppID(), ZEITGEIST_ZG_ACCESS_EVENT)) |
1910 | + .WillOnce(testing::Return()); |
1911 | + |
1912 | + /*** Do Resume ***/ |
1913 | + instance->resume(); |
1914 | +} |
1915 | + |
1916 | +TEST_F(JobBaseTest, pauseResumeMany) |
1917 | +{ |
1918 | + g_setenv("UBUNTU_APP_LAUNCH_OOM_PROC_PATH", CMAKE_BINARY_DIR "/jobs-base-proc", TRUE); |
1919 | + |
1920 | + /* Setup some A TON OF spew */ |
1921 | + std::array<SpewMaster, 50> spews; |
1922 | + std::vector<pid_t> pids(50); |
1923 | + std::transform(spews.begin(), spews.end(), pids.begin(), [](SpewMaster& spew) { return spew.pid(); }); |
1924 | + |
1925 | + /* Build our instance */ |
1926 | + auto instance = simpleInstance(); |
1927 | + EXPECT_CALL(*instance, pids()).WillRepeatedly(testing::Return(pids)); |
1928 | + |
1929 | + /* Setup registry */ |
1930 | + EXPECT_CALL(dynamic_cast<RegistryImplMock&>(*registry->impl), zgSendEvent(simpleAppID(), ZEITGEIST_ZG_LEAVE_EVENT)) |
1931 | + .WillOnce(testing::Return()); |
1932 | + |
1933 | + /* Make sure it is running */ |
1934 | + for (auto& spew : spews) |
1935 | + { |
1936 | + EXPECT_EVENTUALLY_NE(0, spew.datacnt_); |
1937 | + } |
1938 | + |
1939 | + /*** Do Pause ***/ |
1940 | + instance->pause(); |
1941 | + |
1942 | + for (auto& spew : spews) |
1943 | + { |
1944 | + spew.reset(); |
1945 | + } |
1946 | + pause(100); // give spew a chance to send data if it is running |
1947 | + |
1948 | + for (auto& spew : spews) |
1949 | + { |
1950 | + EXPECT_EQ(0, spew.dataCnt()); |
1951 | + |
1952 | + EXPECT_EQ(std::to_string(int(ubuntu::app_launch::oom::paused())), spew.oomScore()); |
1953 | + } |
1954 | + |
1955 | + /* Setup for Resume */ |
1956 | + EXPECT_CALL(dynamic_cast<RegistryImplMock&>(*registry->impl), zgSendEvent(simpleAppID(), ZEITGEIST_ZG_ACCESS_EVENT)) |
1957 | + .WillOnce(testing::Return()); |
1958 | + |
1959 | + for (auto& spew : spews) |
1960 | + { |
1961 | + spew.reset(); |
1962 | + EXPECT_EQ(0, spew.dataCnt()); |
1963 | + } |
1964 | + |
1965 | + /*** Do Resume ***/ |
1966 | + instance->resume(); |
1967 | + |
1968 | + for (auto& spew : spews) |
1969 | + { |
1970 | + EXPECT_EVENTUALLY_NE(0, spew.datacnt_); |
1971 | + |
1972 | + EXPECT_EQ(std::to_string(int(ubuntu::app_launch::oom::focused())), spew.oomScore()); |
1973 | + } |
1974 | +} |