Merge lp:~dobey/unity-scope-click/check-purchased into lp:unity-scope-click/devel
- check-purchased
- Merge into devel
Status: | Merged |
---|---|
Approved by: | Alejandro J. Cura |
Approved revision: | 333 |
Merged at revision: | 343 |
Proposed branch: | lp:~dobey/unity-scope-click/check-purchased |
Merge into: | lp:unity-scope-click/devel |
Diff against target: |
876 lines (+517/-39) 13 files modified
debian/control (+2/-0) libclickscope/click/preview.cpp (+2/-1) scope/clickstore/CMakeLists.txt (+4/-0) scope/clickstore/pay.cpp (+150/-0) scope/clickstore/pay.h (+67/-0) scope/clickstore/store-query.cpp (+30/-11) scope/clickstore/store-query.h (+9/-12) scope/clickstore/store-scope.cpp (+3/-1) scope/clickstore/store-scope.h (+3/-0) scope/tests/CMakeLists.txt (+1/-0) scope/tests/mock_pay.h (+57/-0) scope/tests/test_pay.cpp (+56/-0) scope/tests/test_query.cpp (+133/-14) |
To merge this branch: | bzr merge lp:~dobey/unity-scope-click/check-purchased |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alejandro J. Cura (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+227111@code.launchpad.net |
Commit message
Check for already purchased apps in search results in the store scope.
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:329
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Alejandro J. Cura (alecu) wrote : | # |
Jenkins is crashing on this test:
QueryTest.
it seems to need some extra mocking in the bootstrap code.
Alejandro J. Cura (alecu) wrote : | # |
Please check in the test that the values for these keys are the expected ones:
To do this, the Property matcher used in line 682 of the diff should be replaced by a custom matcher, like used in some other tests in our codebase.
---
I couldn't find any unit test for pay.cpp. Perhaps you forgot to bzr add some test file?
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:330
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:332
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:333
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alejandro J. Cura (alecu) wrote : | # |
Looks good now, thanks for adding moar testz!
Preview Diff
1 | === modified file 'debian/control' |
2 | --- debian/control 2014-07-11 21:56:59 +0000 |
3 | +++ debian/control 2014-07-17 20:26:32 +0000 |
4 | @@ -9,6 +9,7 @@ |
5 | libboost-locale-dev, |
6 | libglib2.0-dev (>= 2.32), |
7 | libjsoncpp-dev, |
8 | + libpay1-dev, |
9 | libubuntu-download-manager-client-dev (>= 0.3+14.10.20140430-0ubuntu1), |
10 | libubuntu-download-manager-common-dev (>= 0.3+14.10.20140430-0ubuntu1), |
11 | libubuntuoneauth-2.0-dev, |
12 | @@ -27,6 +28,7 @@ |
13 | Architecture: armhf i386 amd64 |
14 | Depends: account-plugin-ubuntuone, |
15 | packagekit-tools, |
16 | + pay-service, |
17 | ubuntu-app-launch-tools, |
18 | ubuntu-download-manager, |
19 | ubuntu-sdk-libs, |
20 | |
21 | === modified file 'libclickscope/click/preview.cpp' |
22 | --- libclickscope/click/preview.cpp 2014-07-14 15:35:10 +0000 |
23 | +++ libclickscope/click/preview.cpp 2014-07-17 20:26:32 +0000 |
24 | @@ -761,7 +761,8 @@ |
25 | scopes::PreviewWidgetList UninstalledPreview::uninstalledActionButtonWidgets(const PackageDetails &details) |
26 | { |
27 | scopes::PreviewWidgetList widgets; |
28 | - if (details.package.price > double(0.00)) { |
29 | + if (details.package.price > double(0.00) |
30 | + && result["purchased"].get_bool() == false) { |
31 | scopes::PreviewWidget payments("purchase", "payments"); |
32 | scopes::VariantMap tuple; |
33 | tuple["currency"] = "$"; |
34 | |
35 | === modified file 'scope/clickstore/CMakeLists.txt' |
36 | --- scope/clickstore/CMakeLists.txt 2014-07-02 15:24:07 +0000 |
37 | +++ scope/clickstore/CMakeLists.txt 2014-07-17 20:26:32 +0000 |
38 | @@ -3,6 +3,7 @@ |
39 | find_package (Qt5Core REQUIRED) |
40 | find_package (Qt5Sql REQUIRED) |
41 | pkg_check_modules(JSON_CPP REQUIRED jsoncpp) |
42 | +pkg_check_modules(LIBPAY REQUIRED pay-1) |
43 | |
44 | add_definitions( |
45 | -DGETTEXT_PACKAGE=\"${PROJECT_NAME}\" |
46 | @@ -10,6 +11,7 @@ |
47 | ) |
48 | |
49 | add_library(${STORE_LIB_UNVERSIONED} SHARED |
50 | + pay.cpp |
51 | store-query.cpp |
52 | store-scope.cpp |
53 | ) |
54 | @@ -18,6 +20,7 @@ |
55 | include_directories( |
56 | ${CMAKE_SOURCE_DIR}/libclickscope |
57 | ${JSON_CPP_INCLUDE_DIRS} |
58 | + ${LIBPAY_INCLUDE_DIRS} |
59 | ) |
60 | |
61 | qt5_use_modules (${STORE_LIB_UNVERSIONED} Network Sql) |
62 | @@ -27,6 +30,7 @@ |
63 | ${JSON_CPP_LDFLAGS} |
64 | ${UNITY_SCOPES_LDFLAGS} |
65 | ${UBUNTUONE_LDFLAGS} |
66 | + ${LIBPAY_LDFLAGS} |
67 | ${UBUNTU_DOWNLOAD_MANAGER_CLIENT_LDFLAGS} |
68 | ${UBUNTU_DOWNLOAD_MANAGER_COMMON_LDFLAGS} |
69 | ) |
70 | |
71 | === added file 'scope/clickstore/pay.cpp' |
72 | --- scope/clickstore/pay.cpp 1970-01-01 00:00:00 +0000 |
73 | +++ scope/clickstore/pay.cpp 2014-07-17 20:26:32 +0000 |
74 | @@ -0,0 +1,150 @@ |
75 | +/* |
76 | + * Copyright (C) 2014 Canonical Ltd. |
77 | + * |
78 | + * This program is free software: you can redistribute it and/or modify it |
79 | + * under the terms of the GNU General Public License version 3, as published |
80 | + * by the Free Software Foundation. |
81 | + * |
82 | + * This program is distributed in the hope that it will be useful, but |
83 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
84 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
85 | + * PURPOSE. See the GNU General Public License for more details. |
86 | + * |
87 | + * You should have received a copy of the GNU General Public License along |
88 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
89 | + * |
90 | + * In addition, as a special exception, the copyright holders give |
91 | + * permission to link the code of portions of this program with the |
92 | + * OpenSSL library under certain conditions as described in each |
93 | + * individual source file, and distribute linked combinations |
94 | + * including the two. |
95 | + * You must obey the GNU General Public License in all respects |
96 | + * for all of the code used other than OpenSSL. If you modify |
97 | + * file(s) with this exception, you may extend this exception to your |
98 | + * version of the file(s), but you are not obligated to do so. If you |
99 | + * do not wish to do so, delete this exception statement from your |
100 | + * version. If you delete this exception statement from all source |
101 | + * files in the program, then also delete it here. |
102 | + */ |
103 | + |
104 | +#include "pay.h" |
105 | + |
106 | +#include <future> |
107 | + |
108 | +#include <glib.h> |
109 | +#include <libpay/pay-package.h> |
110 | + |
111 | +#include <QDebug> |
112 | + |
113 | +struct pay::Package::Private |
114 | +{ |
115 | + Private() |
116 | + { |
117 | + } |
118 | + |
119 | + virtual ~Private() |
120 | + { |
121 | + } |
122 | + |
123 | + PayPackage *pay_package; |
124 | +}; |
125 | + |
126 | + |
127 | +static void pay_verification_observer(PayPackage*, |
128 | + const char* item_id, |
129 | + PayPackageItemStatus status, |
130 | + void* user_data) |
131 | +{ |
132 | + pay::Package* p = static_cast<pay::Package*>(user_data); |
133 | + if (p->callbacks.count(item_id) == 0) { |
134 | + // Do nothing if we don't have a callback registered. |
135 | + return; |
136 | + } |
137 | + |
138 | + switch (status) { |
139 | + case PAY_PACKAGE_ITEM_STATUS_PURCHASED: |
140 | + p->callbacks[item_id](item_id, true); |
141 | + break; |
142 | + case PAY_PACKAGE_ITEM_STATUS_NOT_PURCHASED: |
143 | + p->callbacks[item_id](item_id, false); |
144 | + break; |
145 | + default: |
146 | + break; |
147 | + } |
148 | +} |
149 | + |
150 | + |
151 | +namespace pay { |
152 | + |
153 | +Package::Package() : |
154 | + impl(new Private()) |
155 | +{ |
156 | +} |
157 | + |
158 | +Package::~Package() |
159 | +{ |
160 | + if (running) { |
161 | + pay_package_item_observer_uninstall(impl->pay_package, |
162 | + pay_verification_observer, |
163 | + this); |
164 | + pay_package_delete(impl->pay_package); |
165 | + } |
166 | +} |
167 | + |
168 | +bool Package::verify(const std::string& pkg_name) |
169 | +{ |
170 | + typedef std::pair<std::string, bool> _PurchasedTuple; |
171 | + std::promise<_PurchasedTuple> purchased_promise; |
172 | + std::future<_PurchasedTuple> purchased_future = purchased_promise.get_future(); |
173 | + _PurchasedTuple result; |
174 | + |
175 | + if (callbacks.count(pkg_name) == 0) { |
176 | + callbacks[pkg_name] = [pkg_name, |
177 | + &purchased_promise](const std::string& item_id, |
178 | + bool purchased) { |
179 | + if (item_id == pkg_name) { |
180 | + _PurchasedTuple found_purchase{item_id, purchased}; |
181 | + try { |
182 | + purchased_promise.set_value(found_purchase); |
183 | + } catch (std::future_error) { |
184 | + // Just log this to avoid crashing, as it seems that |
185 | + // sometimes this callback may be called more than once. |
186 | + qDebug() << "Callback called again for:" << item_id.c_str(); |
187 | + } |
188 | + } |
189 | + }; |
190 | + qDebug() << "Checking if " << pkg_name.c_str() << " was purchased."; |
191 | + pay_package_verify(pkg_name); |
192 | + |
193 | + result = purchased_future.get(); |
194 | + |
195 | + callbacks.erase(pkg_name); |
196 | + |
197 | + return result.second; |
198 | + } |
199 | + return false; |
200 | +} |
201 | + |
202 | +void Package::setup_pay_service() |
203 | +{ |
204 | + impl->pay_package = pay_package_new(Package::NAME); |
205 | + pay_package_item_observer_install(impl->pay_package, |
206 | + pay_verification_observer, |
207 | + this); |
208 | + running = true; |
209 | +} |
210 | + |
211 | +void Package::pay_package_verify(const std::string& pkg_name) |
212 | +{ |
213 | + if (!running) { |
214 | + setup_pay_service(); |
215 | + } |
216 | + |
217 | + if (callbacks.count(pkg_name) == 0) { |
218 | + return; |
219 | + } |
220 | + |
221 | + pay_package_item_start_verification(impl->pay_package, pkg_name.c_str()); |
222 | +} |
223 | + |
224 | +} // namespace pay |
225 | |
226 | === added file 'scope/clickstore/pay.h' |
227 | --- scope/clickstore/pay.h 1970-01-01 00:00:00 +0000 |
228 | +++ scope/clickstore/pay.h 2014-07-17 20:26:32 +0000 |
229 | @@ -0,0 +1,67 @@ |
230 | +/* |
231 | + * Copyright (C) 2014 Canonical Ltd. |
232 | + * |
233 | + * This program is free software: you can redistribute it and/or modify it |
234 | + * under the terms of the GNU General Public License version 3, as published |
235 | + * by the Free Software Foundation. |
236 | + * |
237 | + * This program is distributed in the hope that it will be useful, but |
238 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
239 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
240 | + * PURPOSE. See the GNU General Public License for more details. |
241 | + * |
242 | + * You should have received a copy of the GNU General Public License along |
243 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
244 | + * |
245 | + * In addition, as a special exception, the copyright holders give |
246 | + * permission to link the code of portions of this program with the |
247 | + * OpenSSL library under certain conditions as described in each |
248 | + * individual source file, and distribute linked combinations |
249 | + * including the two. |
250 | + * You must obey the GNU General Public License in all respects |
251 | + * for all of the code used other than OpenSSL. If you modify |
252 | + * file(s) with this exception, you may extend this exception to your |
253 | + * version of the file(s), but you are not obligated to do so. If you |
254 | + * do not wish to do so, delete this exception statement from your |
255 | + * version. If you delete this exception statement from all source |
256 | + * files in the program, then also delete it here. |
257 | + */ |
258 | + |
259 | +#ifndef _PAY_H_ |
260 | +#define _PAY_H_ |
261 | + |
262 | +#include <map> |
263 | +#include <memory> |
264 | + |
265 | + |
266 | +namespace pay |
267 | +{ |
268 | + class Package |
269 | + { |
270 | + public: |
271 | + typedef std::function<void(const std::string& item_id, |
272 | + bool status)> StatusFunction; |
273 | + |
274 | + constexpr static const char* NAME{"click-scope"}; |
275 | + |
276 | + Package(); |
277 | + virtual ~Package(); |
278 | + |
279 | + virtual bool verify(const std::string& pkg_name); |
280 | + |
281 | + protected: |
282 | + virtual void setup_pay_service(); |
283 | + virtual void pay_package_verify(const std::string& pkg_name); |
284 | + |
285 | + private: |
286 | + struct Private; |
287 | + std::shared_ptr<pay::Package::Private> impl; |
288 | + |
289 | + bool running = false; |
290 | + public: |
291 | + std::map<std::string, StatusFunction> callbacks; |
292 | + }; |
293 | + |
294 | +} //namespace pay |
295 | + |
296 | +#endif // _PAY_H_ |
297 | |
298 | === modified file 'scope/clickstore/store-query.cpp' |
299 | --- scope/clickstore/store-query.cpp 2014-07-14 08:49:39 +0000 |
300 | +++ scope/clickstore/store-query.cpp 2014-07-17 20:26:32 +0000 |
301 | @@ -27,15 +27,15 @@ |
302 | * files in the program, then also delete it here. |
303 | */ |
304 | |
305 | +#include "store-query.h" |
306 | +#include "store-scope.h" |
307 | + |
308 | #include <click/application.h> |
309 | #include <click/interface.h> |
310 | -#include "store-query.h" |
311 | -#include "store-scope.h" |
312 | +#include <click/key_file_locator.h> |
313 | #include <click/qtbridge.h> |
314 | #include <click/departments-db.h> |
315 | |
316 | -#include <click/key_file_locator.h> |
317 | - |
318 | #include <unity/scopes/Annotation.h> |
319 | #include <unity/scopes/CategoryRenderer.h> |
320 | #include <unity/scopes/CategorisedResult.h> |
321 | @@ -116,12 +116,15 @@ |
322 | { |
323 | Private(click::Index& index, click::DepartmentLookup& depts, |
324 | std::shared_ptr<click::DepartmentsDb> depts_db, |
325 | - click::HighlightList& highlights, const scopes::SearchMetadata& metadata) |
326 | + click::HighlightList& highlights, |
327 | + const scopes::SearchMetadata& metadata, |
328 | + pay::Package& in_package) |
329 | : index(index), |
330 | department_lookup(depts), |
331 | depts_db(depts_db), |
332 | highlights(highlights), |
333 | - meta(metadata) |
334 | + meta(metadata), |
335 | + pay_package(in_package) |
336 | { |
337 | } |
338 | click::Index& index; |
339 | @@ -130,14 +133,18 @@ |
340 | click::HighlightList& highlights; |
341 | scopes::SearchMetadata meta; |
342 | click::web::Cancellable search_operation; |
343 | + pay::Package& pay_package; |
344 | }; |
345 | |
346 | -click::Query::Query(unity::scopes::CannedQuery const& query, click::Index& index, click::DepartmentLookup& depts, |
347 | - std::shared_ptr<click::DepartmentsDb> depts_db, |
348 | - click::HighlightList& highlights, |
349 | - scopes::SearchMetadata const& metadata) |
350 | +click::Query::Query(unity::scopes::CannedQuery const& query, |
351 | + click::Index& index, |
352 | + click::DepartmentLookup& depts, |
353 | + std::shared_ptr<click::DepartmentsDb> depts_db, |
354 | + click::HighlightList& highlights, |
355 | + scopes::SearchMetadata const& metadata, |
356 | + pay::Package& in_package) |
357 | : unity::scopes::SearchQueryBase(query, metadata), |
358 | - impl(new Private(index, depts, depts_db, highlights, metadata)) |
359 | + impl(new Private(index, depts, depts_db, highlights, metadata, in_package)) |
360 | { |
361 | } |
362 | |
363 | @@ -264,12 +271,24 @@ |
364 | res.set_uri(pkg.url); |
365 | res[click::Query::ResultKeys::NAME] = pkg.name; |
366 | auto installed = installedPackages.find(pkg); |
367 | + |
368 | + bool purchased = false; |
369 | + if (pkg.price > 0.00f) { |
370 | + // Check if the priced app was already purchased. |
371 | + purchased = impl->pay_package.verify(pkg.name); |
372 | + } |
373 | if (installed != installedPackages.end()) { |
374 | res[click::Query::ResultKeys::INSTALLED] = true; |
375 | + res[click::Query::ResultKeys::PURCHASED] = purchased; |
376 | res["subtitle"] = _("✔ INSTALLED"); |
377 | res[click::Query::ResultKeys::VERSION] = installed->version; |
378 | + } else if (purchased) { |
379 | + res[click::Query::ResultKeys::PURCHASED] = true; |
380 | + res[click::Query::ResultKeys::INSTALLED] = false; |
381 | + res["subtitle"] = _("✔ PURCHASED"); |
382 | } else { |
383 | res[click::Query::ResultKeys::INSTALLED] = false; |
384 | + res[click::Query::ResultKeys::PURCHASED] = false; |
385 | res["subtitle"] = _("FREE"); |
386 | // TODO: get the real price from the webservice (upcoming branch) |
387 | } |
388 | |
389 | === modified file 'scope/clickstore/store-query.h' |
390 | --- scope/clickstore/store-query.h 2014-07-02 15:24:07 +0000 |
391 | +++ scope/clickstore/store-query.h 2014-07-17 20:26:32 +0000 |
392 | @@ -30,6 +30,7 @@ |
393 | #ifndef STORE_QUERY_H |
394 | #define STORE_QUERY_H |
395 | |
396 | +#include "pay.h" |
397 | |
398 | #include <unity/scopes/SearchQueryBase.h> |
399 | #include <unity/scopes/Department.h> |
400 | @@ -55,16 +56,6 @@ |
401 | class Query : public scopes::SearchQueryBase |
402 | { |
403 | public: |
404 | - struct JsonKeys |
405 | - { |
406 | - JsonKeys() = delete; |
407 | - |
408 | - constexpr static const char* RESOURCE_URL{"resource_url"}; |
409 | - constexpr static const char* TITLE{"title"}; |
410 | - constexpr static const char* ICON_URL{"icon_url"}; |
411 | - constexpr static const char* NAME{"name"}; |
412 | - }; |
413 | - |
414 | struct ResultKeys |
415 | { |
416 | ResultKeys() = delete; |
417 | @@ -73,12 +64,18 @@ |
418 | constexpr static const char* DESCRIPTION{"description"}; |
419 | constexpr static const char* MAIN_SCREENSHOT{"main_screenshot"}; |
420 | constexpr static const char* INSTALLED{"installed"}; |
421 | + constexpr static const char* PURCHASED{"purchased"}; |
422 | constexpr static const char* DOWNLOAD_URL{"download_url"}; |
423 | constexpr static const char* VERSION{"version"}; |
424 | }; |
425 | |
426 | - Query(unity::scopes::CannedQuery const& query, click::Index& index, click::DepartmentLookup& dept_lookup, std::shared_ptr<click::DepartmentsDb> depts_db, click::HighlightList& highlights, |
427 | - scopes::SearchMetadata const& metadata); |
428 | + Query(unity::scopes::CannedQuery const& query, |
429 | + click::Index& index, |
430 | + click::DepartmentLookup& dept_lookup, |
431 | + std::shared_ptr<click::DepartmentsDb> depts_db, |
432 | + click::HighlightList& highlights, |
433 | + scopes::SearchMetadata const& metadata, |
434 | + pay::Package& in_package); |
435 | virtual ~Query(); |
436 | |
437 | virtual void cancelled() override; |
438 | |
439 | === modified file 'scope/clickstore/store-scope.cpp' |
440 | --- scope/clickstore/store-scope.cpp 2014-07-02 15:24:07 +0000 |
441 | +++ scope/clickstore/store-scope.cpp 2014-07-17 20:26:32 +0000 |
442 | @@ -54,6 +54,8 @@ |
443 | index.reset(new click::Index(client)); |
444 | depts.reset(new click::DepartmentLookup()); |
445 | highlights.reset(new click::HighlightList()); |
446 | + pay_package.reset(new pay::Package()); |
447 | + |
448 | try |
449 | { |
450 | depts_db = click::DepartmentsDb::create_db(); |
451 | @@ -104,7 +106,7 @@ |
452 | |
453 | scopes::SearchQueryBase::UPtr click::Scope::search(unity::scopes::CannedQuery const& q, scopes::SearchMetadata const& metadata) |
454 | { |
455 | - return scopes::SearchQueryBase::UPtr(new click::Query(q, *index, *depts, depts_db, *highlights, metadata)); |
456 | + return scopes::SearchQueryBase::UPtr(new click::Query(q, *index, *depts, depts_db, *highlights, metadata, *pay_package)); |
457 | } |
458 | |
459 | |
460 | |
461 | === modified file 'scope/clickstore/store-scope.h' |
462 | --- scope/clickstore/store-scope.h 2014-07-02 15:24:07 +0000 |
463 | +++ scope/clickstore/store-scope.h 2014-07-17 20:26:32 +0000 |
464 | @@ -30,6 +30,8 @@ |
465 | #ifndef CLICK_SCOPE_H |
466 | #define CLICK_SCOPE_H |
467 | |
468 | +#include "pay.h" |
469 | + |
470 | #include <memory> |
471 | #include <click/network_access_manager.h> |
472 | #include <click/webclient.h> |
473 | @@ -75,6 +77,7 @@ |
474 | std::shared_ptr<click::DepartmentLookup> depts; |
475 | std::shared_ptr<click::HighlightList> highlights; |
476 | std::shared_ptr<click::DepartmentsDb> depts_db; |
477 | + std::shared_ptr<pay::Package> pay_package; |
478 | |
479 | std::string installApplication(unity::scopes::Result const& result); |
480 | static bool old_api; |
481 | |
482 | === modified file 'scope/tests/CMakeLists.txt' |
483 | --- scope/tests/CMakeLists.txt 2014-07-10 07:51:36 +0000 |
484 | +++ scope/tests/CMakeLists.txt 2014-07-17 20:26:32 +0000 |
485 | @@ -18,6 +18,7 @@ |
486 | ) |
487 | |
488 | add_executable (${CLICKSCOPE_TESTS_TARGET} |
489 | + test_pay.cpp |
490 | test_query.cpp |
491 | ) |
492 | |
493 | |
494 | === added file 'scope/tests/mock_pay.h' |
495 | --- scope/tests/mock_pay.h 1970-01-01 00:00:00 +0000 |
496 | +++ scope/tests/mock_pay.h 2014-07-17 20:26:32 +0000 |
497 | @@ -0,0 +1,57 @@ |
498 | +/* |
499 | + * Copyright (C) 2014 Canonical Ltd. |
500 | + * |
501 | + * This program is free software: you can redistribute it and/or modify it |
502 | + * under the terms of the GNU General Public License version 3, as published |
503 | + * by the Free Software Foundation. |
504 | + * |
505 | + * This program is distributed in the hope that it will be useful, but |
506 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
507 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
508 | + * PURPOSE. See the GNU General Public License for more details. |
509 | + * |
510 | + * You should have received a copy of the GNU General Public License along |
511 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
512 | + * |
513 | + * In addition, as a special exception, the copyright holders give |
514 | + * permission to link the code of portions of this program with the |
515 | + * OpenSSL library under certain conditions as described in each |
516 | + * individual source file, and distribute linked combinations |
517 | + * including the two. |
518 | + * You must obey the GNU General Public License in all respects |
519 | + * for all of the code used other than OpenSSL. If you modify |
520 | + * file(s) with this exception, you may extend this exception to your |
521 | + * version of the file(s), but you are not obligated to do so. If you |
522 | + * do not wish to do so, delete this exception statement from your |
523 | + * version. If you delete this exception statement from all source |
524 | + * files in the program, then also delete it here. |
525 | + */ |
526 | + |
527 | +#include "clickstore/pay.h" |
528 | + |
529 | +#include <gtest/gtest.h> |
530 | +#include <gmock/gmock.h> |
531 | + |
532 | + |
533 | +namespace |
534 | +{ |
535 | + |
536 | + class MockPayPackage : public pay::Package { |
537 | + public: |
538 | + MockPayPackage() |
539 | + { |
540 | + } |
541 | + |
542 | + void pay_package_verify(const std::string& pkg_name) |
543 | + { |
544 | + callbacks[pkg_name](pkg_name, purchased); |
545 | + do_pay_package_verify(pkg_name); |
546 | + } |
547 | + |
548 | + MOCK_METHOD0(setup_pay_service, void()); |
549 | + MOCK_METHOD1(do_pay_package_verify, void(const std::string&)); |
550 | + |
551 | + bool purchased = false; |
552 | +}; |
553 | + |
554 | +} // namespace |
555 | |
556 | === added file 'scope/tests/test_pay.cpp' |
557 | --- scope/tests/test_pay.cpp 1970-01-01 00:00:00 +0000 |
558 | +++ scope/tests/test_pay.cpp 2014-07-17 20:26:32 +0000 |
559 | @@ -0,0 +1,56 @@ |
560 | +/* |
561 | + * Copyright (C) 2014 Canonical Ltd. |
562 | + * |
563 | + * This program is free software: you can redistribute it and/or modify it |
564 | + * under the terms of the GNU General Public License version 3, as published |
565 | + * by the Free Software Foundation. |
566 | + * |
567 | + * This program is distributed in the hope that it will be useful, but |
568 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
569 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
570 | + * PURPOSE. See the GNU General Public License for more details. |
571 | + * |
572 | + * You should have received a copy of the GNU General Public License along |
573 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
574 | + * |
575 | + * In addition, as a special exception, the copyright holders give |
576 | + * permission to link the code of portions of this program with the |
577 | + * OpenSSL library under certain conditions as described in each |
578 | + * individual source file, and distribute linked combinations |
579 | + * including the two. |
580 | + * You must obey the GNU General Public License in all respects |
581 | + * for all of the code used other than OpenSSL. If you modify |
582 | + * file(s) with this exception, you may extend this exception to your |
583 | + * version of the file(s), but you are not obligated to do so. If you |
584 | + * do not wish to do so, delete this exception statement from your |
585 | + * version. If you delete this exception statement from all source |
586 | + * files in the program, then also delete it here. |
587 | + */ |
588 | + |
589 | +#include "mock_pay.h" |
590 | + |
591 | +#include <gtest/gtest.h> |
592 | +#include <gmock/gmock.h> |
593 | + |
594 | + |
595 | +TEST(PayTest, testPayPackageVerifyCalled) |
596 | +{ |
597 | + MockPayPackage package; |
598 | + EXPECT_CALL(package, do_pay_package_verify("foo")).Times(1); |
599 | + EXPECT_EQ(false, package.verify("foo")); |
600 | +} |
601 | + |
602 | +TEST(PayTest, testPayPackageVerifyNotCalledIfCallbackExists) |
603 | +{ |
604 | + MockPayPackage package; |
605 | + package.callbacks["foo"] = [](const std::string&, bool) {}; |
606 | + EXPECT_CALL(package, do_pay_package_verify("foo")).Times(0); |
607 | + EXPECT_EQ(false, package.verify("foo")); |
608 | +} |
609 | + |
610 | +TEST(PayTest, testVerifyReturnsTrueForPurchasedItem) |
611 | +{ |
612 | + MockPayPackage package; |
613 | + package.purchased = true; |
614 | + EXPECT_EQ(true, package.verify("foo")); |
615 | +} |
616 | |
617 | === modified file 'scope/tests/test_query.cpp' |
618 | --- scope/tests/test_query.cpp 2014-07-16 11:53:51 +0000 |
619 | +++ scope/tests/test_query.cpp 2014-07-17 20:26:32 +0000 |
620 | @@ -27,6 +27,10 @@ |
621 | * files in the program, then also delete it here. |
622 | */ |
623 | |
624 | +#include "mock_pay.h" |
625 | + |
626 | +#include "clickstore/store-query.h" |
627 | + |
628 | #include <string> |
629 | #include <memory> |
630 | |
631 | @@ -34,6 +38,7 @@ |
632 | #include <gmock/gmock.h> |
633 | |
634 | #include "click/qtbridge.h" |
635 | +#include "click/index.h" |
636 | #include "clickstore/store-query.h" |
637 | #include "click/application.h" |
638 | #include "click/departments-db.h" |
639 | @@ -61,9 +66,10 @@ |
640 | click::DepartmentLookup& depts, |
641 | std::shared_ptr<click::DepartmentsDb> depts_db, |
642 | click::HighlightList& highlights, |
643 | - scopes::SearchMetadata const& metadata) : click::Query(query, index, depts, depts_db, highlights, metadata) |
644 | + scopes::SearchMetadata const& metadata, |
645 | + pay::Package& in_package) : |
646 | + click::Query(query, index, depts, depts_db, highlights, metadata, in_package) |
647 | { |
648 | - |
649 | } |
650 | |
651 | void run_under_qt(const std::function<void()> &task) { |
652 | @@ -78,9 +84,10 @@ |
653 | click::DepartmentLookup& depts, |
654 | std::shared_ptr<click::DepartmentsDb> depts_db, |
655 | click::HighlightList& highlights, |
656 | - scopes::SearchMetadata const& metadata) : MockQueryBase(query, index, depts, depts_db, highlights, metadata) |
657 | + scopes::SearchMetadata const& metadata, |
658 | + pay::Package& in_package) : |
659 | + MockQueryBase(query, index, depts, depts_db, highlights, metadata, in_package) |
660 | { |
661 | - |
662 | } |
663 | void wrap_add_available_apps(const scopes::SearchReplyProxy &searchReply, |
664 | const PackageSet &installedPackages, |
665 | @@ -105,9 +112,10 @@ |
666 | click::DepartmentLookup& depts, |
667 | std::shared_ptr<click::DepartmentsDb> depts_db, |
668 | click::HighlightList& highlights, |
669 | - scopes::SearchMetadata const& metadata) : MockQueryBase(query, index, depts, depts_db, highlights, metadata) |
670 | + scopes::SearchMetadata const& metadata, |
671 | + pay::Package& in_package) : |
672 | + MockQueryBase(query, index, depts, depts_db, highlights, metadata, in_package) |
673 | { |
674 | - |
675 | } |
676 | MOCK_METHOD3(add_available_apps, |
677 | void(scopes::SearchReplyProxy const&searchReply, |
678 | @@ -126,9 +134,10 @@ |
679 | click::DepartmentLookup dept_lookup; |
680 | click::HighlightList highlights; |
681 | scopes::SearchMetadata metadata("en_EN", "phone"); |
682 | + MockPayPackage pay_pkg; |
683 | PackageSet no_installed_packages; |
684 | const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, ""); |
685 | - MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata); |
686 | + MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg); |
687 | EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _)).Times(1); |
688 | |
689 | scopes::testing::MockSearchReply mock_reply; |
690 | @@ -151,9 +160,10 @@ |
691 | click::DepartmentLookup dept_lookup; |
692 | click::HighlightList highlights; |
693 | scopes::SearchMetadata metadata("en_EN", "phone"); |
694 | + MockPayPackage pay_pkg; |
695 | PackageSet no_installed_packages; |
696 | const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, ""); |
697 | - MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata); |
698 | + MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg); |
699 | EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _)); |
700 | |
701 | scopes::CategoryRenderer renderer("{}"); |
702 | @@ -180,9 +190,10 @@ |
703 | click::DepartmentLookup dept_lookup; |
704 | click::HighlightList highlights; |
705 | scopes::SearchMetadata metadata("en_EN", "phone"); |
706 | + MockPayPackage pay_pkg; |
707 | PackageSet no_installed_packages; |
708 | const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, ""); |
709 | - MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata); |
710 | + MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg); |
711 | EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _)); |
712 | |
713 | scopes::CategoryRenderer renderer("{}"); |
714 | @@ -204,9 +215,10 @@ |
715 | click::DepartmentLookup dept_lookup; |
716 | click::HighlightList highlights; |
717 | scopes::SearchMetadata metadata("en_EN", "phone"); |
718 | + MockPayPackage pay_pkg; |
719 | PackageSet no_installed_packages; |
720 | const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, ""); |
721 | - MockQueryRun q(query, mock_index, dept_lookup, nullptr, highlights, metadata); |
722 | + MockQueryRun q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg); |
723 | auto reply = scopes::SearchReplyProxy(); |
724 | EXPECT_CALL(q, get_installed_packages()).WillOnce(Return(no_installed_packages)); |
725 | EXPECT_CALL(q, add_available_apps(reply, no_installed_packages, _)); |
726 | @@ -230,8 +242,9 @@ |
727 | }; |
728 | click::DepartmentLookup dept_lookup; |
729 | click::HighlightList highlights; |
730 | + MockPayPackage pay_pkg; |
731 | const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, ""); |
732 | - MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata); |
733 | + MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg); |
734 | EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _)); |
735 | |
736 | scopes::CategoryRenderer renderer("{}"); |
737 | @@ -260,8 +273,9 @@ |
738 | }; |
739 | click::DepartmentLookup dept_lookup; |
740 | click::HighlightList highlights; |
741 | + MockPayPackage pay_pkg; |
742 | const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, ""); |
743 | - MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata); |
744 | + MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg); |
745 | EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _)); |
746 | |
747 | scopes::CategoryRenderer renderer("{}"); |
748 | @@ -295,8 +309,9 @@ |
749 | }; |
750 | click::DepartmentLookup dept_lookup; |
751 | click::HighlightList highlights; |
752 | + MockPayPackage pay_pkg; |
753 | const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, ""); |
754 | - MockQuery q(query, mock_index, dept_lookup, depts_db, highlights, metadata); |
755 | + MockQuery q(query, mock_index, dept_lookup, depts_db, highlights, metadata, pay_pkg); |
756 | EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _)); |
757 | |
758 | scopes::CategoryRenderer renderer("{}"); |
759 | @@ -323,8 +338,9 @@ |
760 | scopes::SearchMetadata metadata("en_EN", "phone"); |
761 | click::DepartmentLookup dept_lookup; |
762 | click::HighlightList highlights; |
763 | + MockPayPackage pay_pkg; |
764 | const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, ""); |
765 | - MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata); |
766 | + MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg); |
767 | PackageSet installed_packages{{"package_1", "0.1"}}; |
768 | |
769 | FakeInterface fake_interface; |
770 | @@ -336,3 +352,106 @@ |
771 | |
772 | ASSERT_EQ(q.get_installed_packages(), installed_packages); |
773 | } |
774 | + |
775 | +typedef std::pair<bool, bool> _PurchasedValues; |
776 | +MATCHER_P(PurchasedProperties, b, "") { return arg[click::Query::ResultKeys::PURCHASED].get_bool() == b.first && arg[click::Query::ResultKeys::INSTALLED].get_bool() == b.second; } |
777 | + |
778 | +TEST(QueryTest, testQueryRunCallsPayPackageVerify) |
779 | +{ |
780 | + click::Packages packages { |
781 | + {"name", "title", 0.99, "icon", "uri"} |
782 | + }; |
783 | + MockIndex mock_index(packages); |
784 | + click::DepartmentLookup dept_lookup; |
785 | + click::HighlightList highlights; |
786 | + scopes::SearchMetadata metadata("en_EN", "phone"); |
787 | + MockPayPackage pay_pkg; |
788 | + PackageSet no_installed_packages; |
789 | + const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, ""); |
790 | + MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg); |
791 | + EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _)); |
792 | + |
793 | + scopes::CategoryRenderer renderer("{}"); |
794 | + auto ptrCat = std::make_shared<FakeCategory>("id", "", "", renderer); |
795 | + |
796 | + ON_CALL(q, register_category(_, _, _, _, _)).WillByDefault(Return(ptrCat)); |
797 | + EXPECT_CALL(q, register_category(_, "appstore", CategoryHasNumberOfResults(1), _, _)); |
798 | + EXPECT_CALL(q, register_category(_, "recommends", _, _, _)); |
799 | + |
800 | + scopes::testing::MockSearchReply mock_reply; |
801 | + scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){}); |
802 | + |
803 | + EXPECT_CALL(pay_pkg, do_pay_package_verify(_)).Times(1); |
804 | + EXPECT_CALL(q, push_result(_, PurchasedProperties(_PurchasedValues{false, false}))).Times(1); |
805 | + EXPECT_CALL(q, finished(_)); |
806 | + |
807 | + q.wrap_add_available_apps(reply, no_installed_packages, FAKE_CATEGORY_TEMPLATE); |
808 | +} |
809 | + |
810 | +TEST(QueryTest, testQueryRunPurchased) |
811 | +{ |
812 | + click::Packages packages { |
813 | + {"name", "title", 0.99, "icon", "uri"} |
814 | + }; |
815 | + MockIndex mock_index(packages); |
816 | + click::DepartmentLookup dept_lookup; |
817 | + click::HighlightList highlights; |
818 | + scopes::SearchMetadata metadata("en_EN", "phone"); |
819 | + MockPayPackage pay_pkg; |
820 | + pay_pkg.purchased = true; |
821 | + PackageSet no_installed_packages; |
822 | + const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, ""); |
823 | + MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg); |
824 | + EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _)); |
825 | + |
826 | + scopes::CategoryRenderer renderer("{}"); |
827 | + auto ptrCat = std::make_shared<FakeCategory>("id", "", "", renderer); |
828 | + |
829 | + ON_CALL(q, register_category(_, _, _, _, _)).WillByDefault(Return(ptrCat)); |
830 | + EXPECT_CALL(q, register_category(_, "appstore", CategoryHasNumberOfResults(1), _, _)); |
831 | + EXPECT_CALL(q, register_category(_, "recommends", _, _, _)); |
832 | + |
833 | + scopes::testing::MockSearchReply mock_reply; |
834 | + scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){}); |
835 | + |
836 | + EXPECT_CALL(pay_pkg, do_pay_package_verify(_)).Times(1); |
837 | + EXPECT_CALL(q, push_result(_, PurchasedProperties(_PurchasedValues{true, false}))).Times(1); |
838 | + EXPECT_CALL(q, finished(_)); |
839 | + |
840 | + q.wrap_add_available_apps(reply, no_installed_packages, FAKE_CATEGORY_TEMPLATE); |
841 | +} |
842 | + |
843 | +TEST(QueryTest, testQueryRunPurchasedAndInstalled) |
844 | +{ |
845 | + click::Packages packages { |
846 | + {"name", "title", 0.99, "icon", "uri"} |
847 | + }; |
848 | + PackageSet one_installed_package { |
849 | + {"name", "0.2"} |
850 | + }; |
851 | + MockIndex mock_index(packages); |
852 | + click::DepartmentLookup dept_lookup; |
853 | + click::HighlightList highlights; |
854 | + scopes::SearchMetadata metadata("en_EN", "phone"); |
855 | + MockPayPackage pay_pkg; |
856 | + pay_pkg.purchased = true; |
857 | + const unity::scopes::CannedQuery query("foo.scope", FAKE_QUERY, ""); |
858 | + MockQuery q(query, mock_index, dept_lookup, nullptr, highlights, metadata, pay_pkg); |
859 | + EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _)); |
860 | + |
861 | + scopes::CategoryRenderer renderer("{}"); |
862 | + auto ptrCat = std::make_shared<FakeCategory>("id", "", "", renderer); |
863 | + |
864 | + ON_CALL(q, register_category(_, _, _, _, _)).WillByDefault(Return(ptrCat)); |
865 | + EXPECT_CALL(q, register_category(_, "appstore", CategoryHasNumberOfResults(1), _, _)); |
866 | + EXPECT_CALL(q, register_category(_, "recommends", _, _, _)); |
867 | + |
868 | + scopes::testing::MockSearchReply mock_reply; |
869 | + scopes::SearchReplyProxy reply(&mock_reply, [](unity::scopes::SearchReply*){}); |
870 | + |
871 | + EXPECT_CALL(pay_pkg, do_pay_package_verify(_)).Times(1); |
872 | + EXPECT_CALL(q, push_result(_, PurchasedProperties(_PurchasedValues{true, true}))).Times(1); |
873 | + EXPECT_CALL(q, finished(_)); |
874 | + |
875 | + q.wrap_add_available_apps(reply, one_installed_package, FAKE_CATEGORY_TEMPLATE); |
876 | +} |
FAILED: Continuous integration, rev:328 jenkins. qa.ubuntu. com/job/ unity-team- unity-scope- click-devel- ci/208/ jenkins. qa.ubuntu. com/job/ unity-team- unity-scope- click-devel- utopic- amd64-ci/ 183/console jenkins. qa.ubuntu. com/job/ unity-team- unity-scope- click-devel- utopic- armhf-ci/ 182/console jenkins. qa.ubuntu. com/job/ unity-team- unity-scope- click-devel- utopic- i386-ci/ 182/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity- team-unity- scope-click- devel-ci/ 208/rebuild
http://