Merge lp:~ted/ubuntu-app-launch/system-app-watch into lp:ubuntu-app-launch
- system-app-watch
- Merge into trunk.17.04
Status: | Merged |
---|---|
Approved by: | Marcus Tomlinson |
Approved revision: | 340 |
Merged at revision: | 311 |
Proposed branch: | lp:~ted/ubuntu-app-launch/system-app-watch |
Merge into: | lp:ubuntu-app-launch |
Prerequisite: | lp:~ted/ubuntu-app-launch/registry-cleanup |
Diff against target: |
1009 lines (+694/-39) 16 files modified
libubuntu-app-launch/app-store-legacy.cpp (+172/-0) libubuntu-app-launch/app-store-legacy.h (+14/-0) libubuntu-app-launch/info-watcher.h (+14/-0) libubuntu-app-launch/registry-impl.cpp (+40/-14) libubuntu-app-launch/registry-impl.h (+17/-2) libubuntu-app-launch/registry.cpp (+10/-0) libubuntu-app-launch/registry.h (+19/-0) tests/CMakeLists.txt (+10/-0) tests/app-store-legacy.cpp (+155/-0) tests/eventually-fixture.h (+76/-0) tests/jobs-systemd.cpp (+2/-2) tests/libual-cpp-test.cc (+43/-8) tests/libual-test.cc (+2/-8) tests/registry-mock.h (+13/-0) tests/test-directory.h (+94/-0) tools/ubuntu-app-watch.cpp (+13/-5) |
To merge this branch: | bzr merge lp:~ted/ubuntu-app-launch/system-app-watch |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Pete Woods (community) | Approve | ||
Marcus Tomlinson (community) | Approve | ||
unity-api-1-bot | continuous-integration | Needs Fixing | |
Review via email: mp+321241@code.launchpad.net |
Commit message
Watch system folders for apps added and removed
Description of the change
This branch adds to signals, appAdded and appRemoved, and populates the backend for them with the legacy backend. It sets up file watches on the appropriate directories and then signals when things are changed.
Also it adds a bit to the testing framework to not wait forever on futures. Hopefully this will help some with tests timing out.
unity-api-1-bot (unity-api-1-bot) wrote : | # |
Marcus Tomlinson (marcustomlinson) wrote : | # |
When trying to CMake with "-DCMAKE_
CMake Error at /usr/share/
set_property could not find TARGET exec-util-test. Perhaps it has not yet
been created.
Call Stack (most recent call first):
CMakeLists.
CMake Error at /usr/share/
set_property could not find TARGET failure-test. Perhaps it has not yet
been created.
Call Stack (most recent call first):
CMakeLists.
CMake Error at /usr/share/
set_property could not find TARGET zg-test. Perhaps it has not yet been
created.
Call Stack (most recent call first):
CMakeLists.
Marcus Tomlinson (marcustomlinson) wrote : | # |
The jobs-systems tests seem quite flaky. At least half the time I run them I get this mid-way through a test (no particular test, it varies from run to run):
systemd: Shutting down
DBus daemon: Shutdown
At this point the test process freezes. Looks like your test daemons are shutting down before the test is complete. Seen this at all?
Marcus Tomlinson (marcustomlinson) wrote : | # |
Following from my last comment, I saw this same issue with libual-test (and I assume I'd probably see it with any other test using those test daemons). I restarted my machine and the tests began running smoother again. Zombie services hanging around perhaps? Sorry for the rambling, I don't just saying it as I see it.
Marcus Tomlinson (marcustomlinson) wrote : | # |
While a brief scan of the code looks alright, I'd really like to run valgrind over the new code you've added to check the sanity of the memory handling.
I see that the bits you've added/changed to app-store-
Marcus Tomlinson (marcustomlinson) wrote : | # |
Changing to needs fixing.
unity-api-1-bot (unity-api-1-bot) wrote : | # |
FAILED: Continuous integration, rev:333
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
unity-api-1-bot (unity-api-1-bot) wrote : | # |
FAILED: Continuous integration, rev:335
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
unity-api-1-bot (unity-api-1-bot) wrote : | # |
FAILED: Continuous integration, rev:337
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
unity-api-1-bot (unity-api-1-bot) wrote : | # |
FAILED: Continuous integration, rev:338
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
unity-api-1-bot (unity-api-1-bot) wrote : | # |
FAILED: Continuous integration, rev:339
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
unity-api-1-bot (unity-api-1-bot) wrote : | # |
FAILED: Continuous integration, rev:340
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Pete Woods (pete-woods) wrote : | # |
WOrks for me on the zesty u8 session.
Preview Diff
1 | === modified file 'libubuntu-app-launch/app-store-legacy.cpp' |
2 | --- libubuntu-app-launch/app-store-legacy.cpp 2017-04-04 06:03:50 +0000 |
3 | +++ libubuntu-app-launch/app-store-legacy.cpp 2017-04-04 06:03:50 +0000 |
4 | @@ -19,6 +19,7 @@ |
5 | |
6 | #include "app-store-legacy.h" |
7 | #include "application-impl-legacy.h" |
8 | +#include "registry-impl.h" |
9 | #include "string-util.h" |
10 | |
11 | #include <regex> |
12 | @@ -192,6 +193,177 @@ |
13 | return std::make_shared<app_impls::Legacy>(appid.appname, getReg()); |
14 | } |
15 | |
16 | +/** Turns a directory changed event from a file monitor into an |
17 | + * internal signal. Makes sure we can deal with it first, and |
18 | + * then propegates up the stack. */ |
19 | +void Legacy::directoryChanged(GFile* file, GFileMonitorEvent type) |
20 | +{ |
21 | + g_debug("Getting event for '%s'", unique_gchar(g_file_get_path(file)).get()); |
22 | + |
23 | + auto filetype = g_file_query_file_type(file, G_FILE_QUERY_INFO_NONE, nullptr); |
24 | + if (filetype != G_FILE_TYPE_REGULAR && filetype != G_FILE_TYPE_UNKNOWN) |
25 | + { |
26 | + g_debug("\tNot a regular file"); |
27 | + return; |
28 | + } |
29 | + |
30 | + auto cdesktopname = unique_gchar(g_file_get_basename(file)); |
31 | + if (!cdesktopname) |
32 | + { |
33 | + g_debug("\tNo basename"); |
34 | + return; |
35 | + } |
36 | + std::string desktopname{cdesktopname.get()}; |
37 | + |
38 | + std::string appname; |
39 | + std::smatch match; |
40 | + if (std::regex_match(desktopname, match, desktop_remover)) |
41 | + { |
42 | + appname = match[1].str(); |
43 | + } |
44 | + else |
45 | + { |
46 | + return; |
47 | + } |
48 | + |
49 | + auto reg = getReg(); |
50 | + |
51 | + switch (type) |
52 | + { |
53 | + case G_FILE_MONITOR_EVENT_CREATED: |
54 | + { |
55 | + auto app = std::make_shared<app_impls::Legacy>(AppID::AppName::from_raw(appname), reg); |
56 | + |
57 | + appAdded_(app); |
58 | + break; |
59 | + } |
60 | + case G_FILE_MONITOR_EVENT_CHANGED: |
61 | + { |
62 | + auto app = std::make_shared<app_impls::Legacy>(AppID::AppName::from_raw(appname), reg); |
63 | + |
64 | + infoChanged_(app); |
65 | + break; |
66 | + } |
67 | + case G_FILE_MONITOR_EVENT_DELETED: |
68 | + { |
69 | + AppID appid{AppID::Package::from_raw({}), AppID::AppName::from_raw(appname), AppID::Version::from_raw({})}; |
70 | + if (verifyAppname(appid.package, appid.appname)) |
71 | + { |
72 | + /* Check to see if we've got a shadow situation and we |
73 | + * can still build this app */ |
74 | + auto app = std::make_shared<app_impls::Legacy>(AppID::AppName::from_raw(appname), reg); |
75 | + infoChanged_(app); |
76 | + } |
77 | + else |
78 | + { |
79 | + appRemoved_(appid); |
80 | + } |
81 | + break; |
82 | + } |
83 | + default: |
84 | + break; |
85 | + }; |
86 | +} |
87 | + |
88 | +/** Function that setups file monitors on all of the system application |
89 | + * directories and the user application directory. Any time an application |
90 | + * is added or removed or changed we send the appropriate signal up the |
91 | + * stack. */ |
92 | +void Legacy::setupMonitors() |
93 | +{ |
94 | + std::call_once(monitorsSetup_, [this]() { |
95 | + auto reg = getReg(); |
96 | + monitors_ = |
97 | + reg->thread.executeOnThread<std::set<std::unique_ptr<GFileMonitor, unity::util::GObjectDeleter>>>([this]() { |
98 | + std::set<std::unique_ptr<GFileMonitor, unity::util::GObjectDeleter>> monitors; |
99 | + |
100 | + auto monitorDir = [this](const gchar* dirname) { |
101 | + auto appdir = unique_gchar(g_build_filename(dirname, "applications", nullptr)); |
102 | + auto gfile = unity::util::unique_gobject(g_file_new_for_path(appdir.get())); |
103 | + |
104 | + if (!g_file_query_exists(gfile.get(), nullptr)) |
105 | + { |
106 | + throw std::runtime_error{std::string{"Directory '"} + appdir.get() + "' doesn't exist"}; |
107 | + } |
108 | + |
109 | + if (g_file_query_file_type(gfile.get(), G_FILE_QUERY_INFO_NONE, nullptr) != G_FILE_TYPE_DIRECTORY) |
110 | + { |
111 | + throw std::runtime_error{std::string{"'"} + appdir.get() + "' is not a directory"}; |
112 | + } |
113 | + |
114 | + GError* error = nullptr; |
115 | + auto monitor = unity::util::unique_gobject( |
116 | + g_file_monitor_directory(gfile.get(), G_FILE_MONITOR_NONE, nullptr, &error)); |
117 | + |
118 | + if (error != nullptr) |
119 | + { |
120 | + std::string message = std::string{"Unable to create file monitor: "} + error->message; |
121 | + g_error_free(error); |
122 | + throw std::runtime_error{message}; |
123 | + } |
124 | + |
125 | + g_signal_connect( |
126 | + monitor.get(), "changed", |
127 | + G_CALLBACK(+[](GFileMonitor*, GFile* file, GFile*, GFileMonitorEvent type, gpointer user_data) { |
128 | + auto pthis = static_cast<Legacy*>(user_data); |
129 | + pthis->directoryChanged(file, type); |
130 | + }), |
131 | + this); |
132 | + |
133 | + return monitor; |
134 | + }; |
135 | + |
136 | + auto dirs = g_get_system_data_dirs(); |
137 | + for (int i = 0; dirs != nullptr && dirs[i] != nullptr; i++) |
138 | + { |
139 | + try |
140 | + { |
141 | + monitors.insert(monitorDir(dirs[i])); |
142 | + } |
143 | + catch (std::runtime_error& e) |
144 | + { |
145 | + g_debug("Unable to create directory monitor for system dir '%s': %s", dirs[i], e.what()); |
146 | + } |
147 | + } |
148 | + |
149 | + try |
150 | + { |
151 | + monitors.insert(monitorDir(g_get_user_data_dir())); |
152 | + } |
153 | + catch (std::runtime_error& e) |
154 | + { |
155 | + g_debug("Unable to create directory monitor for user data dir: %s", e.what()); |
156 | + } |
157 | + |
158 | + return monitors; |
159 | + }); |
160 | + }); |
161 | +} |
162 | + |
163 | +/** Return the signal object, but make sure we have the |
164 | + * monitors setup first */ |
165 | +core::Signal<const std::shared_ptr<Application>&>& Legacy::infoChanged() |
166 | +{ |
167 | + setupMonitors(); |
168 | + return infoChanged_; |
169 | +} |
170 | + |
171 | +/** Return the signal object, but make sure we have the |
172 | + * monitors setup first */ |
173 | +core::Signal<const std::shared_ptr<Application>&>& Legacy::appAdded() |
174 | +{ |
175 | + setupMonitors(); |
176 | + return appAdded_; |
177 | +} |
178 | + |
179 | +/** Return the signal object, but make sure we have the |
180 | + * monitors setup first */ |
181 | +core::Signal<const AppID&>& Legacy::appRemoved() |
182 | +{ |
183 | + setupMonitors(); |
184 | + return appRemoved_; |
185 | +} |
186 | + |
187 | } // namespace app_store |
188 | } // namespace app_launch |
189 | } // namespace ubuntu |
190 | |
191 | === modified file 'libubuntu-app-launch/app-store-legacy.h' |
192 | --- libubuntu-app-launch/app-store-legacy.h 2017-04-04 06:03:50 +0000 |
193 | +++ libubuntu-app-launch/app-store-legacy.h 2017-04-04 06:03:50 +0000 |
194 | @@ -21,6 +21,8 @@ |
195 | |
196 | #include "app-store-base.h" |
197 | |
198 | +#include <unity/util/GObjectMemory.h> |
199 | + |
200 | namespace ubuntu |
201 | { |
202 | namespace app_launch |
203 | @@ -46,6 +48,18 @@ |
204 | |
205 | /* Application Creation */ |
206 | virtual std::shared_ptr<app_impls::Base> create(const AppID& appid) override; |
207 | + |
208 | + /* Info watching */ |
209 | + virtual core::Signal<const std::shared_ptr<Application>&>& infoChanged() override; |
210 | + virtual core::Signal<const std::shared_ptr<Application>&>& appAdded() override; |
211 | + virtual core::Signal<const AppID&>& appRemoved() override; |
212 | + |
213 | +private: |
214 | + std::set<std::unique_ptr<GFileMonitor, unity::util::GObjectDeleter>> monitors_; |
215 | + std::once_flag monitorsSetup_; |
216 | + |
217 | + void directoryChanged(GFile* file, GFileMonitorEvent type); |
218 | + void setupMonitors(); |
219 | }; |
220 | |
221 | } // namespace app_store |
222 | |
223 | === modified file 'libubuntu-app-launch/info-watcher.h' |
224 | --- libubuntu-app-launch/info-watcher.h 2017-04-04 06:03:50 +0000 |
225 | +++ libubuntu-app-launch/info-watcher.h 2017-04-04 06:03:50 +0000 |
226 | @@ -43,9 +43,23 @@ |
227 | return infoChanged_; |
228 | } |
229 | |
230 | + virtual core::Signal<const std::shared_ptr<Application>&>& appAdded() |
231 | + { |
232 | + return appAdded_; |
233 | + } |
234 | + |
235 | + virtual core::Signal<const AppID&>& appRemoved() |
236 | + { |
237 | + return appRemoved_; |
238 | + } |
239 | + |
240 | protected: |
241 | /** Signal for info changed on an application */ |
242 | core::Signal<const std::shared_ptr<Application>&> infoChanged_; |
243 | + /** Signal for applications added */ |
244 | + core::Signal<const std::shared_ptr<Application>&> appAdded_; |
245 | + /** Signal for applications removed */ |
246 | + core::Signal<const AppID&> appRemoved_; |
247 | |
248 | /** Accessor function to the registry that ensures we can still |
249 | get it, which we always should be able to, but in case. */ |
250 | |
251 | === modified file 'libubuntu-app-launch/registry-impl.cpp' |
252 | --- libubuntu-app-launch/registry-impl.cpp 2017-04-04 06:03:50 +0000 |
253 | +++ libubuntu-app-launch/registry-impl.cpp 2017-04-04 06:03:50 +0000 |
254 | @@ -171,25 +171,51 @@ |
255 | return watchingAppStarting_; |
256 | } |
257 | |
258 | +/** Sets up the signals down to the info watchers and we aggregate |
259 | + them up to users of UAL. We connect to all their signals and |
260 | + pass them up. */ |
261 | +void Registry::Impl::infoWatchersSetup() |
262 | +{ |
263 | + std::call_once(flag_infoWatchersSetup, [this] { |
264 | + g_debug("Info watchers signals setup"); |
265 | + |
266 | + /* Grab all the app stores and the ZG info watcher */ |
267 | + std::list<std::shared_ptr<info_watcher::Base>> watchers{_appStores.begin(), _appStores.end()}; |
268 | + watchers.push_back(getZgWatcher()); |
269 | + |
270 | + /* Connect each of their signals to us, and track that connection */ |
271 | + for (const auto& watcher : watchers) |
272 | + { |
273 | + infoWatchers_.emplace_back(std::make_pair( |
274 | + watcher, |
275 | + infoWatcherConnections{ |
276 | + watcher->infoChanged().connect( |
277 | + [this](const std::shared_ptr<Application>& app) { sig_appInfoUpdated(app); }), |
278 | + watcher->appAdded().connect([this](const std::shared_ptr<Application>& app) { sig_appAdded(app); }), |
279 | + watcher->appRemoved().connect([this](const AppID& appid) { sig_appRemoved(appid); }), |
280 | + })); |
281 | + } |
282 | + }); |
283 | +} |
284 | + |
285 | core::Signal<const std::shared_ptr<Application>&>& Registry::Impl::appInfoUpdated() |
286 | { |
287 | - std::call_once(flag_appInfoUpdated, [this] { |
288 | - g_debug("App Info Updated Signal Initialized"); |
289 | - |
290 | - std::list<std::shared_ptr<info_watcher::Base>> apps{_appStores.begin(), _appStores.end()}; |
291 | - apps.push_back(getZgWatcher()); |
292 | - |
293 | - for (const auto& app : apps) |
294 | - { |
295 | - infoWatchers_.emplace_back( |
296 | - std::make_pair(app, app->infoChanged().connect([this](const std::shared_ptr<Application>& app) { |
297 | - sig_appInfoUpdated(app); |
298 | - }))); |
299 | - } |
300 | - }); |
301 | + infoWatchersSetup(); |
302 | return sig_appInfoUpdated; |
303 | } |
304 | |
305 | +core::Signal<const std::shared_ptr<Application>&>& Registry::Impl::appAdded() |
306 | +{ |
307 | + infoWatchersSetup(); |
308 | + return sig_appAdded; |
309 | +} |
310 | + |
311 | +core::Signal<const AppID&>& Registry::Impl::appRemoved() |
312 | +{ |
313 | + infoWatchersSetup(); |
314 | + return sig_appRemoved; |
315 | +} |
316 | + |
317 | std::shared_ptr<Application> Registry::Impl::createApp(const AppID& appid) |
318 | { |
319 | for (const auto& appStore : appStores()) |
320 | |
321 | === modified file 'libubuntu-app-launch/registry-impl.h' |
322 | --- libubuntu-app-launch/registry-impl.h 2017-04-04 06:03:50 +0000 |
323 | +++ libubuntu-app-launch/registry-impl.h 2017-04-04 06:03:50 +0000 |
324 | @@ -98,6 +98,8 @@ |
325 | } |
326 | |
327 | core::Signal<const std::shared_ptr<Application>&>& appInfoUpdated(); |
328 | + core::Signal<const std::shared_ptr<Application>&>& appAdded(); |
329 | + core::Signal<const AppID&>& appRemoved(); |
330 | |
331 | const std::list<std::shared_ptr<app_store::Base>>& appStores() |
332 | { |
333 | @@ -156,10 +158,23 @@ |
334 | |
335 | /** Signal for application info changing */ |
336 | core::Signal<const std::shared_ptr<Application>&> sig_appInfoUpdated; |
337 | + /** Signal for applications added */ |
338 | + core::Signal<const std::shared_ptr<Application>&> sig_appAdded; |
339 | + /** Signal for applications removed */ |
340 | + core::Signal<const AppID&> sig_appRemoved; |
341 | + |
342 | + void infoWatchersSetup(const std::shared_ptr<Registry>& reg); |
343 | /** Flag to see if we've initialized the info watcher list */ |
344 | - std::once_flag flag_appInfoUpdated; |
345 | + std::once_flag flag_infoWatchersSetup; |
346 | + struct infoWatcherConnections |
347 | + { |
348 | + core::ScopedConnection infoUpdated; |
349 | + core::ScopedConnection appAdded; |
350 | + core::ScopedConnection appRemoved; |
351 | + }; |
352 | /** List of info watchers along with a signal handle to our connection to their update signal */ |
353 | - std::list<std::pair<std::shared_ptr<info_watcher::Base>, core::ScopedConnection>> infoWatchers_; |
354 | + std::list<std::pair<std::shared_ptr<info_watcher::Base>, infoWatcherConnections>> infoWatchers_; |
355 | + void infoWatchersSetup(); |
356 | |
357 | /** ZG Info Watcher */ |
358 | std::shared_ptr<info_watcher::Zeitgeist> zgWatcher_; |
359 | |
360 | === modified file 'libubuntu-app-launch/registry.cpp' |
361 | --- libubuntu-app-launch/registry.cpp 2017-04-04 06:03:50 +0000 |
362 | +++ libubuntu-app-launch/registry.cpp 2017-04-04 06:03:50 +0000 |
363 | @@ -154,5 +154,15 @@ |
364 | return reg->impl->appInfoUpdated(); |
365 | } |
366 | |
367 | +core::Signal<const std::shared_ptr<Application>&>& Registry::appAdded(const std::shared_ptr<Registry>& reg) |
368 | +{ |
369 | + return reg->impl->appAdded(); |
370 | +} |
371 | + |
372 | +core::Signal<const AppID&>& Registry::appRemoved(const std::shared_ptr<Registry>& reg) |
373 | +{ |
374 | + return reg->impl->appRemoved(); |
375 | +} |
376 | + |
377 | } // namespace app_launch |
378 | } // namespace ubuntu |
379 | |
380 | === modified file 'libubuntu-app-launch/registry.h' |
381 | --- libubuntu-app-launch/registry.h 2017-04-04 06:03:50 +0000 |
382 | +++ libubuntu-app-launch/registry.h 2017-04-04 06:03:50 +0000 |
383 | @@ -137,6 +137,25 @@ |
384 | static core::Signal<const std::shared_ptr<Application>&>& appInfoUpdated( |
385 | const std::shared_ptr<Registry>& reg = getDefault()); |
386 | |
387 | + /** Get the signal object that is signaled when there is a new application |
388 | + that has been added to the system. |
389 | + |
390 | + \note This signal handler is activated on the UAL thread |
391 | + |
392 | + \param reg Registry to get the handler from |
393 | + */ |
394 | + static core::Signal<const std::shared_ptr<Application>&>& appAdded( |
395 | + const std::shared_ptr<Registry>& reg = getDefault()); |
396 | + |
397 | + /** Get the signal object that is signaled when an application is |
398 | + removed from the system. |
399 | + |
400 | + \note This signal handler is activated on the UAL thread |
401 | + |
402 | + \param reg Registry to get the handler from |
403 | + */ |
404 | + static core::Signal<const AppID&>& appRemoved(const std::shared_ptr<Registry>& reg = getDefault()); |
405 | + |
406 | /** The Application Manager, almost always if you're not Unity8, don't |
407 | use this API. Testing is a special case. Subclass this interface and |
408 | implement these functions. |
409 | |
410 | === modified file 'tests/CMakeLists.txt' |
411 | --- tests/CMakeLists.txt 2017-03-14 16:46:00 +0000 |
412 | +++ tests/CMakeLists.txt 2017-04-04 06:03:50 +0000 |
413 | @@ -50,6 +50,15 @@ |
414 | add_test (NAME libual-test COMMAND libual-test) |
415 | add_test (NAME libual-cpp-test COMMAND libual-cpp-test) |
416 | |
417 | +# App Store Legacy |
418 | + |
419 | +add_executable (app-store-legacy |
420 | + app-store-legacy.cpp) |
421 | +target_link_libraries (app-store-legacy ${GMOCK_LIBRARIES} ${GTEST_MAIN_LIBRARIES} launcher-static ${DBUSTEST_LIBRARIES}) |
422 | + |
423 | +add_test(NAME app-store-legacy COMMAND "${CMAKE_CURRENT_BINARY_DIR}/app-store-legacy" --gtest_list_tests "|" grep "\"^ \"" "|" xargs -n 1 printf "\"--gtest_filter=*.%s\\n\"" "|" xargs -n 1 "${CMAKE_CURRENT_BINARY_DIR}/app-store-legacy") |
424 | + |
425 | + |
426 | # Jobs Base Test |
427 | |
428 | add_executable (jobs-base-test |
429 | @@ -129,6 +138,7 @@ |
430 | add_custom_target(format-tests |
431 | COMMAND clang-format -i -style=file |
432 | application-info-desktop.cpp |
433 | + app-store-legacy.cpp |
434 | libual-cpp-test.cc |
435 | libual-test.cc |
436 | list-apps.cpp |
437 | |
438 | === added file 'tests/app-store-legacy.cpp' |
439 | --- tests/app-store-legacy.cpp 1970-01-01 00:00:00 +0000 |
440 | +++ tests/app-store-legacy.cpp 2017-04-04 06:03:50 +0000 |
441 | @@ -0,0 +1,155 @@ |
442 | +/* |
443 | + * Copyright © 2017 Canonical Ltd. |
444 | + * |
445 | + * This program is free software: you can redistribute it and/or modify it |
446 | + * under the terms of the GNU General Public License version 3, as published |
447 | + * by the Free Software Foundation. |
448 | + * |
449 | + * This program is distributed in the hope that it will be useful, but |
450 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
451 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
452 | + * PURPOSE. See the GNU General Public License for more details. |
453 | + * |
454 | + * You should have received a copy of the GNU General Public License along |
455 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
456 | + * |
457 | + * Authors: |
458 | + * Ted Gould <ted.gould@canonical.com> |
459 | + */ |
460 | + |
461 | +#include "app-store-legacy.h" |
462 | + |
463 | +#include "eventually-fixture.h" |
464 | +#include "registry-mock.h" |
465 | +#include "test-directory.h" |
466 | +#include <gmock/gmock.h> |
467 | +#include <gtest/gtest.h> |
468 | +#include <libdbustest/dbus-test.h> |
469 | +#include <unity/util/GObjectMemory.h> |
470 | +#include <unity/util/GlibMemory.h> |
471 | + |
472 | +class AppStoreLegacy : public EventuallyFixture |
473 | +{ |
474 | +protected: |
475 | + std::unique_ptr<DbusTestService, unity::util::GObjectDeleter> service; |
476 | + std::shared_ptr<RegistryMock> registry; |
477 | + |
478 | + virtual void SetUp() |
479 | + { |
480 | + setenv("XDG_DATA_DIRS", CMAKE_SOURCE_DIR, 1); |
481 | + |
482 | + service = unity::util::unique_gobject(dbus_test_service_new(nullptr)); |
483 | + dbus_test_service_start_tasks(service.get()); |
484 | + registry = std::make_shared<RegistryMock>(std::list<std::shared_ptr<ubuntu::app_launch::app_store::Base>>{}, |
485 | + std::shared_ptr<ubuntu::app_launch::jobs::manager::Base>{}); |
486 | + } |
487 | +}; |
488 | + |
489 | +TEST_F(AppStoreLegacy, Init) |
490 | +{ |
491 | + auto store = std::make_shared<ubuntu::app_launch::app_store::Legacy>(registry->impl); |
492 | + store.reset(); |
493 | +} |
494 | + |
495 | +TEST_F(AppStoreLegacy, FindApp) |
496 | +{ |
497 | + TestDirectory testdir; |
498 | + testdir.addApp("testapp", |
499 | + {{G_KEY_FILE_DESKTOP_GROUP, |
500 | + { |
501 | + {G_KEY_FILE_DESKTOP_KEY_NAME, "Test App"}, |
502 | + {G_KEY_FILE_DESKTOP_KEY_TYPE, "Application"}, |
503 | + {G_KEY_FILE_DESKTOP_KEY_ICON, "foo.png"}, |
504 | + {G_KEY_FILE_DESKTOP_KEY_EXEC, "foo"}, |
505 | + }}}); |
506 | + |
507 | + auto store = std::make_shared<ubuntu::app_launch::app_store::Legacy>(registry->impl); |
508 | + |
509 | + EXPECT_TRUE(store->verifyAppname(ubuntu::app_launch::AppID::Package::from_raw({}), |
510 | + ubuntu::app_launch::AppID::AppName::from_raw("testapp"))); |
511 | +} |
512 | + |
513 | +TEST_F(AppStoreLegacy, RemoveApp) |
514 | +{ |
515 | + TestDirectory testdir; |
516 | + testdir.addApp("testapp", |
517 | + {{G_KEY_FILE_DESKTOP_GROUP, |
518 | + { |
519 | + {G_KEY_FILE_DESKTOP_KEY_NAME, "Test App"}, |
520 | + {G_KEY_FILE_DESKTOP_KEY_TYPE, "Application"}, |
521 | + {G_KEY_FILE_DESKTOP_KEY_ICON, "foo.png"}, |
522 | + {G_KEY_FILE_DESKTOP_KEY_EXEC, "foo"}, |
523 | + }}}); |
524 | + |
525 | + auto store = std::make_shared<ubuntu::app_launch::app_store::Legacy>(registry->impl); |
526 | + |
527 | + std::promise<std::string> removedAppId; |
528 | + store->appRemoved().connect([&](const ubuntu::app_launch::AppID &appid) { removedAppId.set_value(appid); }); |
529 | + |
530 | + testdir.removeApp("testapp"); |
531 | + |
532 | + EXPECT_EVENTUALLY_FUTURE_EQ(std::string{"testapp"}, removedAppId.get_future()); |
533 | +} |
534 | + |
535 | +TEST_F(AppStoreLegacy, AddedApp) |
536 | +{ |
537 | + TestDirectory testdir; |
538 | + auto store = std::make_shared<ubuntu::app_launch::app_store::Legacy>(registry->impl); |
539 | + |
540 | + std::promise<std::string> addedAppId; |
541 | + store->appAdded().connect( |
542 | + [&](const std::shared_ptr<ubuntu::app_launch::Application> &app) { addedAppId.set_value(app->appId()); }); |
543 | + |
544 | + testdir.addApp("testapp", |
545 | + {{G_KEY_FILE_DESKTOP_GROUP, |
546 | + { |
547 | + {G_KEY_FILE_DESKTOP_KEY_NAME, "Test App"}, |
548 | + {G_KEY_FILE_DESKTOP_KEY_TYPE, "Application"}, |
549 | + {G_KEY_FILE_DESKTOP_KEY_ICON, "foo.png"}, |
550 | + {G_KEY_FILE_DESKTOP_KEY_EXEC, "foo"}, |
551 | + }}}); |
552 | + |
553 | + EXPECT_EVENTUALLY_FUTURE_EQ(std::string{"testapp"}, addedAppId.get_future()); |
554 | +} |
555 | + |
556 | +TEST_F(AppStoreLegacy, ShadowDelete) |
557 | +{ |
558 | + TestDirectory testdir; |
559 | + testdir.addApp("testapp", |
560 | + {{G_KEY_FILE_DESKTOP_GROUP, |
561 | + { |
562 | + {G_KEY_FILE_DESKTOP_KEY_NAME, "Test App"}, |
563 | + {G_KEY_FILE_DESKTOP_KEY_TYPE, "Application"}, |
564 | + {G_KEY_FILE_DESKTOP_KEY_ICON, "foo.png"}, |
565 | + {G_KEY_FILE_DESKTOP_KEY_EXEC, "foo"}, |
566 | + }}}); |
567 | + |
568 | + TestDirectory testdir2; |
569 | + testdir2.addApp("testapp", |
570 | + {{G_KEY_FILE_DESKTOP_GROUP, |
571 | + { |
572 | + {G_KEY_FILE_DESKTOP_KEY_NAME, "Test App"}, |
573 | + {G_KEY_FILE_DESKTOP_KEY_TYPE, "Application"}, |
574 | + {G_KEY_FILE_DESKTOP_KEY_ICON, "foo.png"}, |
575 | + {G_KEY_FILE_DESKTOP_KEY_EXEC, "foo"}, |
576 | + }}}); |
577 | + |
578 | + auto store = std::make_shared<ubuntu::app_launch::app_store::Legacy>(registry->impl); |
579 | + |
580 | + std::promise<std::string> updatedAppId; |
581 | + store->infoChanged().connect( |
582 | + [&](const std::shared_ptr<ubuntu::app_launch::Application> &app) { updatedAppId.set_value(app->appId()); }); |
583 | + |
584 | + std::promise<std::string> deleteAppId; |
585 | + store->appRemoved().connect([&](const ubuntu::app_launch::AppID &appid) { deleteAppId.set_value(appid); }); |
586 | + std::shared_future<std::string> deleteFuture = deleteAppId.get_future(); |
587 | + |
588 | + testdir.removeApp("testapp"); |
589 | + |
590 | + EXPECT_EVENTUALLY_FUTURE_EQ(std::string{"testapp"}, updatedAppId.get_future()); |
591 | + EXPECT_NE(std::future_status::ready, deleteFuture.wait_for(std::chrono::seconds{0})); |
592 | + |
593 | + testdir2.removeApp("testapp"); |
594 | + |
595 | + EXPECT_EVENTUALLY_FUTURE_EQ(std::string{"testapp"}, deleteFuture); |
596 | +} |
597 | |
598 | === modified file 'tests/eventually-fixture.h' |
599 | --- tests/eventually-fixture.h 2017-01-18 20:43:25 +0000 |
600 | +++ tests/eventually-fixture.h 2017-04-04 06:03:50 +0000 |
601 | @@ -118,6 +118,37 @@ |
602 | return eventuallyLoop(func); \ |
603 | } |
604 | |
605 | +#define _EVENTUALLY_FUTURE_HELPER(oper) \ |
606 | + template <typename comptype> \ |
607 | + testing::AssertionResult eventuallyFutureHelper##oper(const char *desca, const char *descb, comptype expected, \ |
608 | + std::future<comptype> future) \ |
609 | + { \ |
610 | + std::function<testing::AssertionResult(void)> func = [&]() { \ |
611 | + auto status = future.wait_for(std::chrono::seconds{0}); \ |
612 | + if (status != std::future_status::ready) \ |
613 | + { \ |
614 | + return testing::AssertionFailure(); \ |
615 | + } \ |
616 | + return testing::internal::CmpHelper##oper(desca, descb, expected, future.get()); \ |
617 | + }; \ |
618 | + return eventuallyLoop(func); \ |
619 | + } \ |
620 | + \ |
621 | + template <typename comptype> \ |
622 | + testing::AssertionResult eventuallyFutureHelper##oper(const char *desca, const char *descb, comptype expected, \ |
623 | + std::shared_future<comptype> future) \ |
624 | + { \ |
625 | + std::function<testing::AssertionResult(void)> func = [&]() { \ |
626 | + auto status = future.wait_for(std::chrono::seconds{0}); \ |
627 | + if (status != std::future_status::ready) \ |
628 | + { \ |
629 | + return testing::AssertionFailure(); \ |
630 | + } \ |
631 | + return testing::internal::CmpHelper##oper(desca, descb, expected, future.get()); \ |
632 | + }; \ |
633 | + return eventuallyLoop(func); \ |
634 | + } |
635 | + |
636 | _EVENTUALLY_HELPER(EQ); |
637 | _EVENTUALLY_HELPER(NE); |
638 | _EVENTUALLY_HELPER(LT); |
639 | @@ -132,8 +163,16 @@ |
640 | _EVENTUALLY_FUNC_HELPER(STREQ); |
641 | _EVENTUALLY_FUNC_HELPER(STRNE); |
642 | |
643 | + _EVENTUALLY_FUTURE_HELPER(EQ); |
644 | + _EVENTUALLY_FUTURE_HELPER(NE); |
645 | + _EVENTUALLY_FUTURE_HELPER(LT); |
646 | + _EVENTUALLY_FUTURE_HELPER(GT); |
647 | + _EVENTUALLY_FUTURE_HELPER(STREQ); |
648 | + _EVENTUALLY_FUTURE_HELPER(STRNE); |
649 | + |
650 | #undef _EVENTUALLY_HELPER |
651 | #undef _EVENTUALLY_FUNC_HELPER |
652 | +#undef _EVENTUALLY_FUTURE_HELPER |
653 | }; |
654 | |
655 | /* Helpers */ |
656 | @@ -209,3 +248,40 @@ |
657 | |
658 | #define ASSERT_EVENTUALLY_FUNC_STRNE(expected, actual) \ |
659 | ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFuncHelperSTRNE, expected, actual) |
660 | + |
661 | +/* Future Helpers */ |
662 | +#define EXPECT_EVENTUALLY_FUTURE_EQ(expected, actual) \ |
663 | + EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperEQ, expected, actual) |
664 | + |
665 | +#define EXPECT_EVENTUALLY_FUTURE_NE(expected, actual) \ |
666 | + EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperNE, expected, actual) |
667 | + |
668 | +#define EXPECT_EVENTUALLY_FUTURE_LT(expected, actual) \ |
669 | + EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperLT, expected, actual) |
670 | + |
671 | +#define EXPECT_EVENTUALLY_FUTURE_GT(expected, actual) \ |
672 | + EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperGT, expected, actual) |
673 | + |
674 | +#define EXPECT_EVENTUALLY_FUTURE_STREQ(expected, actual) \ |
675 | + EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperSTREQ, expected, actual) |
676 | + |
677 | +#define EXPECT_EVENTUALLY_FUTURE_STRNE(expected, actual) \ |
678 | + EXPECT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperSTRNE, expected, actual) |
679 | + |
680 | +#define ASSERT_EVENTUALLY_FUTURE_EQ(expected, actual) \ |
681 | + ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperEQ, expected, actual) |
682 | + |
683 | +#define ASSERT_EVENTUALLY_FUTURE_NE(expected, actual) \ |
684 | + ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperNE, expected, actual) |
685 | + |
686 | +#define ASSERT_EVENTUALLY_FUTURE_LT(expected, actual) \ |
687 | + ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperLT, expected, actual) |
688 | + |
689 | +#define ASSERT_EVENTUALLY_FUTURE_GT(expected, actual) \ |
690 | + ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperGT, expected, actual) |
691 | + |
692 | +#define ASSERT_EVENTUALLY_FUTURE_STREQ(expected, actual) \ |
693 | + ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperSTREQ, expected, actual) |
694 | + |
695 | +#define ASSERT_EVENTUALLY_FUTURE_STRNE(expected, actual) \ |
696 | + ASSERT_PRED_FORMAT2(EventuallyFixture::eventuallyFutureHelperSTRNE, expected, actual) |
697 | |
698 | === modified file 'tests/jobs-systemd.cpp' |
699 | --- tests/jobs-systemd.cpp 2017-04-04 06:03:50 +0000 |
700 | +++ tests/jobs-systemd.cpp 2017-04-04 06:03:50 +0000 |
701 | @@ -326,7 +326,7 @@ |
702 | {defaultJobName(), std::string{multipleAppID()}, "1234", 1, {}}), |
703 | "/foo"); |
704 | |
705 | - EXPECT_EQ(multipleAppID(), newunit.get_future().get()); |
706 | + EXPECT_EVENTUALLY_FUTURE_EQ(multipleAppID(), newunit.get_future()); |
707 | } |
708 | |
709 | TEST_F(JobsSystemd, SignalRemove) |
710 | @@ -362,7 +362,7 @@ |
711 | {defaultJobName(), std::string{multipleAppID()}, "1234567890", 1, {}}), |
712 | "/foo"); |
713 | |
714 | - EXPECT_EQ(multipleAppID(), removeunit.get_future().get()); |
715 | + EXPECT_EVENTUALLY_FUTURE_EQ(multipleAppID(), removeunit.get_future()); |
716 | } |
717 | |
718 | TEST_F(JobsSystemd, UnitFailure) |
719 | |
720 | === modified file 'tests/libual-cpp-test.cc' |
721 | --- tests/libual-cpp-test.cc 2017-04-04 06:03:50 +0000 |
722 | +++ tests/libual-cpp-test.cc 2017-04-04 06:03:50 +0000 |
723 | @@ -44,6 +44,7 @@ |
724 | #include "snapd-mock.h" |
725 | #include "spew-master.h" |
726 | #include "systemd-mock.h" |
727 | +#include "test-directory.h" |
728 | #include "zg-mock.h" |
729 | |
730 | #define LOCAL_SNAPD_TEST_SOCKET (SNAPD_TEST_SOCKET "-libual-cpp-test") |
731 | @@ -1154,6 +1155,46 @@ |
732 | g_spawn_command_line_sync("rm -rf " CMAKE_BINARY_DIR "/libual-proc", NULL, NULL, NULL, NULL); |
733 | } |
734 | |
735 | +TEST_F(LibUAL, AppInfoSignals) |
736 | +{ |
737 | + /* Setup the stores mock */ |
738 | + auto mockstore = std::make_shared<MockStore>(registry->impl); |
739 | + registry = |
740 | + std::make_shared<RegistryMock>(std::list<std::shared_ptr<ubuntu::app_launch::app_store::Base>>{mockstore}, |
741 | + std::shared_ptr<ubuntu::app_launch::jobs::manager::Base>{}); |
742 | + |
743 | + /* Build an app */ |
744 | + auto singleappid = ubuntu::app_launch::AppID::find(registry, "single"); |
745 | + auto myapp = std::make_shared<MockApp>(singleappid, registry->impl); |
746 | + |
747 | + /* Setup an app added signal handler */ |
748 | + std::promise<ubuntu::app_launch::AppID> addedAppId; |
749 | + ubuntu::app_launch::Registry::appAdded(registry).connect( |
750 | + [&](const std::shared_ptr<ubuntu::app_launch::Application>& app) { addedAppId.set_value(app->appId()); }); |
751 | + |
752 | + mockstore->mock_signalAppAdded(myapp); |
753 | + |
754 | + EXPECT_EVENTUALLY_FUTURE_EQ(singleappid, addedAppId.get_future()); |
755 | + |
756 | + /* Setup an info changed signal handler */ |
757 | + std::promise<ubuntu::app_launch::AppID> changedAppId; |
758 | + ubuntu::app_launch::Registry::appInfoUpdated(registry).connect( |
759 | + [&](const std::shared_ptr<ubuntu::app_launch::Application>& app) { changedAppId.set_value(app->appId()); }); |
760 | + |
761 | + mockstore->mock_signalAppInfoChanged(myapp); |
762 | + |
763 | + EXPECT_EVENTUALLY_FUTURE_EQ(singleappid, changedAppId.get_future()); |
764 | + |
765 | + /* Setup an app removed signal handler */ |
766 | + std::promise<ubuntu::app_launch::AppID> removedAppId; |
767 | + ubuntu::app_launch::Registry::appRemoved(registry).connect( |
768 | + [&](const ubuntu::app_launch::AppID& appid) { removedAppId.set_value(appid); }); |
769 | + |
770 | + mockstore->mock_signalAppRemoved(singleappid); |
771 | + |
772 | + EXPECT_EVENTUALLY_FUTURE_EQ(singleappid, removedAppId.get_future()); |
773 | +} |
774 | + |
775 | TEST_F(LibUAL, OOMSet) |
776 | { |
777 | g_setenv("UBUNTU_APP_LAUNCH_OOM_PROC_PATH", CMAKE_BINARY_DIR "/libual-proc", 1); |
778 | @@ -1277,13 +1318,7 @@ |
779 | }); |
780 | t.detach(); |
781 | |
782 | - auto outputfuture = outputpromise.get_future(); |
783 | - while (outputfuture.wait_for(std::chrono::milliseconds{1}) != std::future_status::ready) |
784 | - { |
785 | - pause(); |
786 | - } |
787 | - |
788 | - ASSERT_STREQ(filedata, outputfuture.get().c_str()); |
789 | + EXPECT_EVENTUALLY_FUTURE_EQ(std::string{filedata}, outputpromise.get_future()); |
790 | |
791 | return; |
792 | } |
793 | @@ -1376,7 +1411,7 @@ |
794 | std::vector<std::string> execList{"Foo", "Bar", "Really really really long value", "Another value"}; |
795 | ubuntu::app_launch::Helper::setExec(execList); |
796 | |
797 | - EXPECT_EQ(execList, socketpromise.get_future().get()); |
798 | + EXPECT_EVENTUALLY_FUTURE_EQ(execList, socketpromise.get_future()); |
799 | } |
800 | |
801 | TEST_F(LibUAL, AppInfo) |
802 | |
803 | === modified file 'tests/libual-test.cc' |
804 | --- tests/libual-test.cc 2017-03-20 15:21:13 +0000 |
805 | +++ tests/libual-test.cc 2017-04-04 06:03:50 +0000 |
806 | @@ -892,13 +892,7 @@ |
807 | }); |
808 | t.detach(); |
809 | |
810 | - auto outputfuture = outputpromise.get_future(); |
811 | - while (outputfuture.wait_for(std::chrono::milliseconds{1}) != std::future_status::ready) |
812 | - { |
813 | - pause(); |
814 | - } |
815 | - |
816 | - ASSERT_STREQ(filedata, outputfuture.get().c_str()); |
817 | + EXPECT_EVENTUALLY_FUTURE_EQ(std::string{filedata}, outputpromise.get_future()); |
818 | |
819 | return; |
820 | } |
821 | @@ -1002,7 +996,7 @@ |
822 | .c_str(), |
823 | nullptr); |
824 | |
825 | - EXPECT_EQ(execList, socketpromise.get_future().get()); |
826 | + EXPECT_EVENTUALLY_FUTURE_EQ(execList, socketpromise.get_future()); |
827 | } |
828 | |
829 | TEST_F(LibUAL, AppInfo) |
830 | |
831 | === modified file 'tests/registry-mock.h' |
832 | --- tests/registry-mock.h 2017-04-04 06:03:50 +0000 |
833 | +++ tests/registry-mock.h 2017-04-04 06:03:50 +0000 |
834 | @@ -54,6 +54,19 @@ |
835 | |
836 | /* Application Creation */ |
837 | MOCK_METHOD1(create, std::shared_ptr<ubuntu::app_launch::app_impls::Base>(const ubuntu::app_launch::AppID&)); |
838 | + |
839 | + void mock_signalAppAdded(const std::shared_ptr<ubuntu::app_launch::Application>& app) |
840 | + { |
841 | + appAdded_(app); |
842 | + } |
843 | + void mock_signalAppRemoved(const ubuntu::app_launch::AppID& appid) |
844 | + { |
845 | + appRemoved_(appid); |
846 | + } |
847 | + void mock_signalAppInfoChanged(const std::shared_ptr<ubuntu::app_launch::Application>& app) |
848 | + { |
849 | + infoChanged_(app); |
850 | + } |
851 | }; |
852 | |
853 | class MockApp : public ubuntu::app_launch::app_impls::Base |
854 | |
855 | === added file 'tests/test-directory.h' |
856 | --- tests/test-directory.h 1970-01-01 00:00:00 +0000 |
857 | +++ tests/test-directory.h 2017-04-04 06:03:50 +0000 |
858 | @@ -0,0 +1,94 @@ |
859 | +/* |
860 | + * Copyright © 2017 Canonical Ltd. |
861 | + * |
862 | + * This program is free software: you can redistribute it and/or modify it |
863 | + * under the terms of the GNU General Public License version 3, as published |
864 | + * by the Free Software Foundation. |
865 | + * |
866 | + * This program is distributed in the hope that it will be useful, but |
867 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
868 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
869 | + * PURPOSE. See the GNU General Public License for more details. |
870 | + * |
871 | + * You should have received a copy of the GNU General Public License along |
872 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
873 | + * |
874 | + * Authors: |
875 | + * Ted Gould <ted.gould@canonical.com> |
876 | + */ |
877 | + |
878 | +#include <unity/util/GlibMemory.h> |
879 | +#include <string> |
880 | + |
881 | +class TestDirectory |
882 | +{ |
883 | + std::string dirname_; |
884 | + std::string appdir_; |
885 | + |
886 | +public: |
887 | + TestDirectory() |
888 | + { |
889 | + GError *error{nullptr}; |
890 | + |
891 | + auto dirname = ubuntu::app_launch::unique_gchar(g_dir_make_tmp("xdg-data-tmp-XXXXXX", &error)); |
892 | + if (error != nullptr) |
893 | + { |
894 | + auto message = std::string{"Unable to create temporary directory: "} + error->message; |
895 | + g_error_free(error); |
896 | + throw std::runtime_error{message}; |
897 | + } |
898 | + dirname_ = dirname.get(); |
899 | + g_debug("Setting temp XDG_DATA directory: %s", dirname.get()); |
900 | + |
901 | + appdir_ = ubuntu::app_launch::unique_gchar(g_build_filename(dirname.get(), "applications", nullptr)).get(); |
902 | + g_mkdir_with_parents(appdir_.c_str(), 0700); |
903 | + |
904 | + auto datadirs = |
905 | + ubuntu::app_launch::unique_gchar(g_strdup_printf("%s:%s", dirname.get(), g_getenv("XDG_DATA_DIRS"))); |
906 | + setenv("XDG_DATA_DIRS", datadirs.get(), 1); |
907 | + } |
908 | + |
909 | + ~TestDirectory() |
910 | + { |
911 | + auto command = ubuntu::app_launch::unique_gchar(g_strdup_printf("rm -rf %s", dirname_.c_str())); |
912 | + g_spawn_command_line_sync(command.get(), nullptr, nullptr, nullptr, nullptr); |
913 | + g_debug("Removing test directory: %s", dirname_.c_str()); |
914 | + } |
915 | + |
916 | + void addApp(const std::string &appname, |
917 | + const std::list<std::pair<std::string, std::list<std::pair<std::string, std::string>>>> &keydata) |
918 | + { |
919 | + auto keyfile = unity::util::unique_glib(g_key_file_new()); |
920 | + |
921 | + for (const auto &groupset : keydata) |
922 | + { |
923 | + auto groupname = groupset.first; |
924 | + for (const auto &dataset : groupset.second) |
925 | + { |
926 | + auto key = dataset.first; |
927 | + auto value = dataset.second; |
928 | + |
929 | + g_key_file_set_string(keyfile.get(), groupname.c_str(), key.c_str(), value.c_str()); |
930 | + } |
931 | + } |
932 | + |
933 | + auto path = ubuntu::app_launch::unique_gchar( |
934 | + g_build_filename(appdir_.c_str(), (appname + ".desktop").c_str(), nullptr)); |
935 | + GError *error{nullptr}; |
936 | + |
937 | + g_key_file_save_to_file(keyfile.get(), path.get(), &error); |
938 | + if (error != nullptr) |
939 | + { |
940 | + auto message = std::string{"Unable to write desktop file for '"} + appname + "': " + error->message; |
941 | + g_error_free(error); |
942 | + throw std::runtime_error{message}; |
943 | + } |
944 | + } |
945 | + |
946 | + void removeApp(const std::string &appname) |
947 | + { |
948 | + auto path = ubuntu::app_launch::unique_gchar( |
949 | + g_build_filename(appdir_.c_str(), (appname + ".desktop").c_str(), nullptr)); |
950 | + unlink(path.get()); |
951 | + } |
952 | +}; |
953 | |
954 | === modified file 'tools/ubuntu-app-watch.cpp' |
955 | --- tools/ubuntu-app-watch.cpp 2017-02-08 17:34:52 +0000 |
956 | +++ tools/ubuntu-app-watch.cpp 2017-04-04 06:03:50 +0000 |
957 | @@ -29,16 +29,16 @@ |
958 | |
959 | registry.appStarted().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app, |
960 | const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance) { |
961 | - std::cout << "Started: " << (std::string)app->appId() << std::endl; |
962 | + std::cout << "Started: " << std::string{app->appId()} << std::endl; |
963 | }); |
964 | registry.appStopped().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app, |
965 | const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance) { |
966 | - std::cout << "Stopped: " << (std::string)app->appId() << std::endl; |
967 | + std::cout << "Stopped: " << std::string{app->appId()} << std::endl; |
968 | }); |
969 | registry.appPaused().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app, |
970 | const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance, |
971 | const std::vector<pid_t>& pids) { |
972 | - std::cout << "Paused: " << (std::string)app->appId() << " ("; |
973 | + std::cout << "Paused: " << std::string{app->appId()} << " ("; |
974 | |
975 | for (auto pid : pids) |
976 | { |
977 | @@ -50,7 +50,7 @@ |
978 | registry.appResumed().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app, |
979 | const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance, |
980 | const std::vector<pid_t>& pids) { |
981 | - std::cout << "Resumed: " << (std::string)app->appId() << " ("; |
982 | + std::cout << "Resumed: " << std::string{app->appId()} << " ("; |
983 | |
984 | for (auto pid : pids) |
985 | { |
986 | @@ -62,7 +62,7 @@ |
987 | registry.appFailed().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app, |
988 | const std::shared_ptr<ubuntu::app_launch::Application::Instance>& instance, |
989 | ubuntu::app_launch::Registry::FailureType type) { |
990 | - std::cout << "Failed: " << (std::string)app->appId(); |
991 | + std::cout << "Failed: " << std::string{app->appId()}; |
992 | switch (type) |
993 | { |
994 | case ubuntu::app_launch::Registry::FailureType::CRASH: |
995 | @@ -74,6 +74,14 @@ |
996 | } |
997 | std::cout << std::endl; |
998 | }); |
999 | + registry.appAdded().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app) { |
1000 | + std::cout << "Added: " << std::string{app->appId()} << std::endl; |
1001 | + }); |
1002 | + registry.appRemoved().connect( |
1003 | + [](const ubuntu::app_launch::AppID& appid) { std::cout << "Removed: " << std::string{appid} << std::endl; }); |
1004 | + registry.appInfoUpdated().connect([](const std::shared_ptr<ubuntu::app_launch::Application>& app) { |
1005 | + std::cout << "Updated: " << std::string{app->appId()} << std::endl; |
1006 | + }); |
1007 | |
1008 | std::signal(SIGTERM, [](int signal) -> void { retval.set_value(EXIT_SUCCESS); }); |
1009 | return retval.get_future().get(); |
FAILED: Continuous integration, rev:333 /jenkins. canonical. com/unity- api-1/job/ lp-ubuntu- app-launch- ci/285/ /jenkins. canonical. com/unity- api-1/job/ build/1894/ console /jenkins. canonical. com/unity- api-1/job/ build-0- fetch/1901 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 1683/console /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=amd64, release= zesty/1683/ console /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 1683 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 1683/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= zesty/1683 /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=armhf, release= zesty/1683/ artifact/ output/ *zip*/output. zip /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 1683/console /jenkins. canonical. com/unity- api-1/job/ build-2- binpkg/ arch=i386, release= zesty/1683/ console
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
ABORTED: https:/
ABORTED: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
ABORTED: https:/
FAILURE: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/unity- api-1/job/ lp-ubuntu- app-launch- ci/285/ rebuild
https:/