Merge lp:~justinmcp/unity-chromium-extension/generic-extension into lp:unity-chromium-extension

Proposed by Justin McPherson
Status: Work in progress
Proposed branch: lp:~justinmcp/unity-chromium-extension/generic-extension
Merge into: lp:unity-chromium-extension
Diff against target: 4642 lines (+2399/-1482)
67 files modified
CMakeLists.txt (+32/-0)
chromium-extension/CMakeLists.txt (+69/-0)
chromium-extension/background-page.html (+2/-2)
chromium-extension/background-page.js (+64/-61)
chromium-extension/browser.js (+24/-24)
chromium-extension/build.sh (+0/-27)
chromium-extension/chromium-extension.pro (+0/-66)
chromium-extension/infobar.css (+0/-20)
chromium-extension/infobar.html (+0/-20)
chromium-extension/infobar.js (+0/-33)
chromium-extension/manifest.json.in (+41/-35)
chromium-extension/options.html (+4/-6)
chromium-extension/options.js (+3/-3)
chromium-extension/popup.css (+21/-0)
chromium-extension/popup.html (+20/-0)
chromium-extension/popup.js (+36/-0)
chromium-extension/unity-api-page-proxy.js (+1/-1)
chromium-extension/unity-webapps.json.in (+2/-2)
common-project-config.pri (+0/-41)
common-vars.pri (+0/-6)
coverage.pri (+0/-49)
debian/changelog (+7/-0)
debian/control (+13/-5)
debian/unity-chromium-extension.install (+2/-3)
debian/unity-webapps-extension-process.install (+1/-0)
messaging-host/CMakeLists.txt (+101/-0)
messaging-host/Makefile.am (+0/-2)
messaging-host/click-handler.cpp (+386/-0)
messaging-host/click-handler.h (+55/-0)
messaging-host/com.canonical.webapp.extension.json.in (+9/-0)
messaging-host/com.canonical.webapp.installer.json.in (+0/-9)
messaging-host/main.cpp (+28/-8)
messaging-host/messaging-host.pro (+0/-42)
messaging-host/service-handler.cpp (+75/-0)
messaging-host/service-handler.h (+54/-0)
messaging-host/service.cpp (+18/-11)
messaging-host/webapps-handler.cpp (+11/-17)
messaging-host/webapps-handler.h (+0/-1)
tests/CMakeLists.txt (+1/-0)
tests/tests.pro (+0/-3)
tests/unit/CMakeLists.txt (+1/-0)
tests/unit/messaging-host/CMakeLists.txt (+5/-0)
tests/unit/messaging-host/click-handler/CMakeLists.txt (+38/-0)
tests/unit/messaging-host/click-handler/tst_click-handler.cpp (+291/-0)
tests/unit/messaging-host/connection-host.cpp (+0/-71)
tests/unit/messaging-host/connection/CMakeLists.txt (+40/-0)
tests/unit/messaging-host/connection/connection-host.cpp (+71/-0)
tests/unit/messaging-host/connection/tst_connection.cpp (+112/-0)
tests/unit/messaging-host/inactivity-timer/CMakeLists.txt (+23/-0)
tests/unit/messaging-host/inactivity-timer/tst_inactivity_timer.cpp (+125/-0)
tests/unit/messaging-host/messaging-host.pri (+0/-9)
tests/unit/messaging-host/messaging-host.pro (+0/-12)
tests/unit/messaging-host/service/CMakeLists.txt (+23/-0)
tests/unit/messaging-host/service/tst_service.cpp (+189/-0)
tests/unit/messaging-host/tst_connection.cpp (+0/-112)
tests/unit/messaging-host/tst_connection.pro (+0/-14)
tests/unit/messaging-host/tst_connection_host.pro (+0/-14)
tests/unit/messaging-host/tst_inactivity_timer.cpp (+0/-125)
tests/unit/messaging-host/tst_inactivity_timer.pro (+0/-18)
tests/unit/messaging-host/tst_service.cpp (+0/-189)
tests/unit/messaging-host/tst_service.pro (+0/-18)
tests/unit/messaging-host/tst_webapps-handler.cpp (+0/-354)
tests/unit/messaging-host/tst_webapps-handler.pro (+0/-32)
tests/unit/messaging-host/webapps-handler/CMakeLists.txt (+47/-0)
tests/unit/messaging-host/webapps-handler/tst_webapps-handler.cpp (+354/-0)
tests/unit/unit.pro (+0/-3)
unity-chromium-extension.pro (+0/-14)
To merge this branch: bzr merge lp:~justinmcp/unity-chromium-extension/generic-extension
Reviewer Review Type Date Requested Status
WebApps Pending
Review via email: mp+272066@code.launchpad.net

Commit message

Signal available webapps while navigating with Chrome and Webbrowser-app.
Look for compatible webapps in the installed click packages.

Description of the change

Signal available webapps while navigating with Chrome and Webbrowser-app.
Look for compatible webapps in the installed click packages.

To post a comment you must log in.
251. By Justin McPherson

WIP

252. By Justin McPherson

WIP

253. By Justin McPherson

WIP

254. By Justin McPherson

WIP

255. By Justin McPherson

WIP

256. By Justin McPherson

WIP

257. By Justin McPherson

WIP

258. By Justin McPherson

Add tests

259. By Justin McPherson

Finish click related tests

260. By Justin McPherson

Make checking for maintainer configurable

261. By Justin McPherson

Fix leak

Unmerged revisions

261. By Justin McPherson

Fix leak

260. By Justin McPherson

Make checking for maintainer configurable

259. By Justin McPherson

Finish click related tests

258. By Justin McPherson

Add tests

257. By Justin McPherson

WIP

256. By Justin McPherson

WIP

255. By Justin McPherson

WIP

254. By Justin McPherson

WIP

253. By Justin McPherson

WIP

252. By Justin McPherson

WIP

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'CMakeLists.txt'
--- CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ CMakeLists.txt 2015-10-07 04:25:10 +0000
@@ -0,0 +1,32 @@
1# vim:expandtab:shiftwidth=2:tabstop=2:
2
3# Copyright (C) 2015 Canonical Ltd.
4
5# This library is free software; you can redistribute it and/or
6# modify it under the terms of the GNU Lesser General Public
7# License as published by the Free Software Foundation; either
8# version 2.1 of the License, or (at your option) any later version.
9
10# This library is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# Lesser General Public License for more details.
14
15# You should have received a copy of the GNU Lesser GeneraGl Public
16# License along with this library; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19cmake_minimum_required(VERSION 2.8.11)
20
21project(unity-chromium-extension)
22
23set(PROJECT_NAME "unity_webapps_chromium")
24set(PROJECT_VERSION "3.3")
25
26include(GNUInstallDirs)
27
28add_subdirectory(chromium-extension)
29add_subdirectory(messaging-host)
30
31enable_testing()
32add_subdirectory(tests)
033
=== added file 'chromium-extension/CMakeLists.txt'
--- chromium-extension/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ chromium-extension/CMakeLists.txt 2015-10-07 04:25:10 +0000
@@ -0,0 +1,69 @@
1
2set(PEMFILE unity-webapps.pem)
3
4set(EXTENSION_DIR ${CMAKE_INSTALL_FULL_LIBDIR}/libunity-chromium)
5set(EXTENSION_NAME unity-webapps)
6set(EXTENSION_FILE ${EXTENSION_NAME}.crx)
7set(EXTENSION_WORKING_DIR ${CMAKE_CURRENT_BINARY_DIR}/${EXTENSION_NAME})
8set(EXTENSION_FILES)
9
10list(
11 APPEND EXTENSION_FILES
12 background-page.html
13 background-page.js
14 base-content-script.js
15 browser.js
16 popup.css
17 popup.html
18 popup.js
19 _locales
20 options.html
21 options.js
22 skin
23 unity-api-page-proxy-builder-gen.js
24 unity-api-page-proxy.js
25)
26
27# Create a directory for archiving+signing extension and copy in necessary files
28file(MAKE_DIRECTORY ${EXTENSION_WORKING_DIR})
29file(COPY ${EXTENSION_FILES} DESTINATION ${EXTENSION_WORKING_DIR})
30
31# If we already have a signing key, copy it to the working directory
32if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/${PEMFILE})
33 file(COPY ${CMAKE_CURRENT_LIST_DIR}/${PEMFILE} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
34endif()
35
36# fill out config files
37configure_file(manifest.json.in ${EXTENSION_WORKING_DIR}/manifest.json)
38configure_file(unity-webapps.json.in ${CMAKE_CURRENT_BINARY_DIR}/unity-webapps.json)
39
40# If not using the included signing key, generate one TODO: use key id
41add_custom_command(
42 OUTPUT ${PEMFILE}
43 COMMAND openssl genrsa 1024 > ${PEMFILE}
44)
45
46# Prepare extension
47add_custom_command(
48 OUTPUT ${EXTENSION_FILE}
49 COMMAND ${CMAKE_CURRENT_LIST_DIR}/crxmake.sh ${EXTENSION_NAME} ${PEMFILE}
50 DEPENDS ${PEMFILE}
51)
52
53add_custom_target(
54 build-extension ALL
55 DEPENDS ${EXTENSION_FILE}
56)
57
58# Install extension description in chrome data dir
59# The crxmake.sh script writes this file to ./res
60install(
61 DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/res/
62 DESTINATION ${CMAKE_INSTALL_DATADIR}/chromium/extensions
63 FILES_MATCHING PATTERN "*.json"
64)
65
66install(
67 FILES ${CMAKE_CURRENT_BINARY_DIR}/${EXTENSION_FILE}
68 DESTINATION ${EXTENSION_DIR}
69)
070
=== modified file 'chromium-extension/background-page.html'
--- chromium-extension/background-page.html 2014-05-20 13:40:09 +0000
+++ chromium-extension/background-page.html 2015-10-07 04:25:10 +0000
@@ -4,9 +4,9 @@
44
5 <title>Unity Webapps Extension Background Page</title>5 <title>Unity Webapps Extension Background Page</title>
6 <embed type="application/x-unity-webapps-npapi" id="unityChromiumExtensionId"/>6 <embed type="application/x-unity-webapps-npapi" id="unityChromiumExtensionId"/>
7 7
8 <script src="background-page.js"></script>8 <script src="background-page.js"></script>
9 9
10 </head>10 </head>
1111
12 <body>12 <body>
1313
=== modified file 'chromium-extension/background-page.js'
--- chromium-extension/background-page.js 2014-06-20 06:16:48 +0000
+++ chromium-extension/background-page.js 2015-10-07 04:25:10 +0000
@@ -1,28 +1,28 @@
1/* Chromium Unity integration extension1/* Chromium Unity integration extension
2 * 2 *
3 * Copyright 2012 Canonical Ltd.3 * Copyright 2012 Canonical Ltd.
4 *4 *
5 * This program is free software: you can redistribute it and/or modify it 5 * This program is free software: you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 3, as published 6 * under the terms of the GNU General Public License version 3, as published
7 * by the Free Software Foundation.7 * by the Free Software Foundation.
8 *8 *
9 * This program is distributed in the hope that it will be useful, but 9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranties of 10 * WITHOUT ANY WARRANTY; without even the implied warranties of
11 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR 11 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
12 * PURPOSE. See the GNU General Public License for more details.12 * PURPOSE. See the GNU General Public License for more details.
13 *13 *
14 * You should have received a copy of the GNU General Public License along 14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 **/16 **/
1717
18var background_page = (function () {18var background_page = (function () {
19 // Native messaging support19 // Native messaging support
20 var HOST_ADDRESS = 'com.canonical.webapp.installer';20 var HOST_ADDRESS = 'com.canonical.webapp.extension';
21 var port = null;21 var port = null;
22 var host_callbacks = [];22 var host_callbacks = [];
2323
24 var portListener = function (msg) {24 var portListener = function (msg) {
25 callback = host_callbacks.pop(); 25 callback = host_callbacks.pop();
26 if (callback === undefined) {26 if (callback === undefined) {
27 return;27 return;
28 }28 }
@@ -30,12 +30,10 @@
30 };30 };
3131
32 var portDisconnecter = function () {32 var portDisconnecter = function () {
33 console.log('UCX: port disconnected');33 port = null;
34 port = null
35 };34 };
3635
37 var sendNativeMessage = function (msg, callback) {36 var sendNativeMessage = function (msg, callback) {
38 console.log("UCX: sendnativemessage: port=" + port);
39 if (port === null) {37 if (port === null) {
40 port = chrome.runtime.connectNative(HOST_ADDRESS);38 port = chrome.runtime.connectNative(HOST_ADDRESS);
41 port.onMessage.addListener(portListener);39 port.onMessage.addListener(portListener);
@@ -50,46 +48,42 @@
5048
5149
52 /////////////////////////////////////////////////////////50 /////////////////////////////////////////////////////////
53 // 51 //
54 // Scafolding to keep track of data associated w/ infobar requests 52 // Scafolding to keep track of data associated w/ pageaction requests
55 // (Chromium's structure imposes some kind of state being maintained53 // (Chromium's structure imposes some kind of state being maintained
56 // in order to communicate data) 54 // in order to communicate data)
57 // 55 //
58 ////////////////////////////////////////////////////////56 ////////////////////////////////////////////////////////
59 // 57 //
60 // list of callback that are to be called asynchronously58 // list of callback that are to be called asynchronously
61 // per tab. Used in the user integration/installation resquests context.59 // per tab. Used in the user integration/installation resquests context.
62 //
63 // One thing to keep in mind is that one constraint, that bring some amount of
64 // 'soundness' is that there is a hard limit (provided by the browser) of one infobar per tab.
6560
66 var user_infobar_request_callbacks = {};61 var user_popup_request_callbacks = {};
67 var addInfobarRequestCallbackFor = function (infobarRequestId, callback, message, details) {62 var addPopupRequestCallbackFor = function (popupRequestId, callback, message, details) {
68 user_infobar_request_callbacks[infobarRequestId] = {63 user_popup_request_callbacks[popupRequestId] = {
69 callback: callback,64 callback: callback,
70 message: message,65 message: message,
71 details: details66 details: details
72 };67 };
73 };68 };
7469
75 var getDataIfAnyFor = function (infobarRequestId) {70 var getDataIfAnyFor = function (popupRequestId) {
76 if (user_infobar_request_callbacks[infobarRequestId] === undefined) {71 if (user_popup_request_callbacks[popupRequestId] === undefined) {
77 return "";72 return "";
78 }73 }
79 return {74 return {
80 message: user_infobar_request_callbacks[infobarRequestId].message,75 message: user_popup_request_callbacks[popupRequestId].message,
81 details: user_infobar_request_callbacks[infobarRequestId].details76 details: user_popup_request_callbacks[popupRequestId].details
82 };77 };
83 };78 };
8479 var invokeAndRemoveCallbackIfAnyFor = function (popupRequestId, args) {
85 var invokeAndRemoveCallbackIfAnyFor = function (infobarRequestId, arguments) {80 if (user_popup_request_callbacks[popupRequestId] === undefined) {
86 if (user_infobar_request_callbacks[infobarRequestId] === undefined) {
87 return;81 return;
88 }82 }
89 var callback = user_infobar_request_callbacks[infobarRequestId].callback;83 var callback = user_popup_request_callbacks[popupRequestId].callback;
90 user_infobar_request_callbacks[infobarRequestId] = undefined;84 user_popup_request_callbacks[popupRequestId] = undefined;
91 if (typeof(callback) === 'function') {85 if (typeof(callback) === 'function') {
92 callback(arguments);86 callback(args);
93 }87 }
94 };88 };
9589
@@ -106,35 +100,37 @@
106 },100 },
107 function (response) {101 function (response) {
108 if (response.available) {102 if (response.available) {
109 addInfobarRequestCallbackFor(103 addPopupRequestCallbackFor(
110 windowInfos.tabId,104 windowInfos.tabId,
111 function (result) {105 function (result) {
112 if (result && result.integrate) {106 if (result && result.integrate) {
113 sendNativeMessage({107 sendNativeMessage({
114 "method" : "install",108 "method" : "install",
115 "url" : url109 "url" : url
116 })110 });
117 } else {111 } else {
118 sendNativeMessage({112 sendNativeMessage({
119 "method" : "dont_ask",113 "method" : "dont_ask",
120 "url" : url114 "url" : url
121 })115 });
122 }116 }
117
118 chrome.pageAction.hide(windowInfos.tabId);
123 },119 },
124 chrome.i18n.getMessage("integration_copy", [ response.appName, response.appDomain ]),120 chrome.i18n.getMessage("integration_copy", [ response.appName, response.appDomain ]),
125 null);121 null);
126122
127 chrome.infobars.show({ tabId: windowInfos.tabId, path: "infobar.html" });123 chrome.pageAction.show(windowInfos.tabId);
128 }124 }
129 });125 });
130 }; 126 };
131 127
132 128
133 // {{{ main request handler129 // {{{ main request handler
134 130
135 /**131 /**
136 * Handles & responds to content script requests.132 * Handles & responds to content script requests.
137 * 133 *
138 */134 */
139 var init_requested_stamps = {};135 var init_requested_stamps = {};
140 var contentScriptsRequestHandler = function (request, sender, callback) {136 var contentScriptsRequestHandler = function (request, sender, callback) {
@@ -144,10 +140,10 @@
144 logging: false,140 logging: false,
145 incognito: sender.tab.incognito141 incognito: sender.tab.incognito
146 };142 };
147 143
148 try {144 try {
149 if (window.localStorage) {145 if (window.localStorage) {
150 settings.logging = localStorage['logging'];146 settings.logging = localStorage.logging;
151 }147 }
152 }148 }
153 catch (e) {149 catch (e) {
@@ -156,8 +152,8 @@
156152
157 callback (settings);153 callback (settings);
158 },154 },
159 on_user_infobar_request_result: function (request, sender, callback) {155 on_user_popup_request_result: function (request, sender, callback) {
160 invokeAndRemoveCallbackIfAnyFor (request.tabId, request);156 invokeAndRemoveCallbackIfAnyFor(request.tabId, request);
161 },157 },
162 init_requested: function (request, sender, callback) {158 init_requested: function (request, sender, callback) {
163 sendNativeMessage({159 sendNativeMessage({
@@ -166,30 +162,32 @@
166 },162 },
167 function (response) {163 function (response) {
168 if (response.available) {164 if (response.available) {
169 addInfobarRequestCallbackFor(165 addPopupRequestCallbackFor(
170 sender.tab.id,166 sender.tab.id,
171 function (result) {167 function (result) {
172 if (result && result.integrate) {168 if (result && result.integrate) {
173 sendNativeMessage({169 sendNativeMessage({
174 "method" : "install",170 "method" : "install",
175 "url" : request.options.url171 "url" : request.options.url
176 })172 });
177 } else {173 } else {
178 sendNativeMessage({174 sendNativeMessage({
179 "method" : "dont_ask",175 "method" : "dont_ask",
180 "url" : request.options.url176 "url" : request.options.url
181 })177 });
182 }178 }
179
180 chrome.pageAction.hide(windowInfos.tabId);
183 },181 },
184 chrome.i18n.getMessage("integration_copy", [ response.appName, response.appDomain ]),182 chrome.i18n.getMessage("integration_copy", [ response.appName, response.appDomain ]),
185 null);183 null);
186184
187 chrome.infobars.show({ tabId: windowInfos.tabId, path: "infobar.html" });185 chrome.pageAction.show(windowInfos.tabId);
188 }186 }
189 });187 });
190 }188 }
191 };189 };
192 190
193 // validate request191 // validate request
194 if (!request || !request.method) {192 if (!request || !request.method) {
195 callback({ error: "Invalid request structure" });193 callback({ error: "Invalid request structure" });
@@ -200,20 +198,18 @@
200 return true;198 return true;
201 }199 }
202200
203 if (typeof(request.method) != 'string' || request.method.length == 0) {201 if (typeof(request.method) != 'string' || request.method.length === 0) {
204 callback({ error: "Invalid request method" });202 callback({ error: "Invalid request method" });
205 return true;203 return true;
206 }204 }
207205
208 console.log('Got request: ' + request.method);
209
210 var handler = handlers [request.method];206 var handler = handlers [request.method];
211 if (handler !== undefined && typeof(handler) == 'function') {207 if (handler !== undefined && typeof(handler) == 'function') {
212 handler(request, sender, callback);208 handler(request, sender, callback);
213 return true;209 return true;
214 }210 }
215 return false;211 return false;
216 }212 };
217213
218 // Main event handler and communication link214 // Main event handler and communication link
219 // w/ content scripts215 // w/ content scripts
@@ -221,18 +217,16 @@
221 // }}}217 // }}}
222218
223 ///////////////////////////////////////////////////////////////////////219 ///////////////////////////////////////////////////////////////////////
224 // 220 //
225 // Window management related functions. In chromeless mode, we have specific221 // Window management related functions. In chromeless mode, we have specific
226 // rules for tab management to make webapps feel more "native" than plain222 // rules for tab management to make webapps feel more "native" than plain
227 // web applications.223 // web applications.
228 // 224 //
229 ///////////////////////////////////////////////////////////////////////225 ///////////////////////////////////////////////////////////////////////
230226
231 var onTabChanged = function (tabId, windowId, url) {227 var onTabChanged = function (tabId, windowId, url) {
232 var onInstalled = function (installed, packageName, appName, appDomain) { };228 var onInstalled = function (installed, packageName, appName, appDomain) { };
233229
234 console.log("onTabChanged: " + url);
235
236 matchesIntegrationScripts(230 matchesIntegrationScripts(
237 null, //plugin,231 null, //plugin,
238 url,232 url,
@@ -255,15 +249,24 @@
255249
256 chrome.tabs.onUpdated.addListener(250 chrome.tabs.onUpdated.addListener(
257 function(tabId, changeInfo, tab) {251 function(tabId, changeInfo, tab) {
258 console.log("onUpdated " + changeInfo.url);
259 if (changeInfo && changeInfo.url) {252 if (changeInfo && changeInfo.url) {
260 onTabChanged(tabId, tab.windowId, changeInfo.url);253 onTabChanged(tabId, tab.windowId, changeInfo.url);
261 }254 }
262 }255 }
263 );256 );
264257
258 chrome.tabs.onReplaced.addListener(
259 function(addedTabId, removedTabId) {
260 chrome.tabs.get(addedTabId, function(tab) {
261 if (tab && tab.url) {
262 onTabChanged(addedTabId, tab.windowId, tab.url);
263 }
264 });
265 }
266 );
267
265 /*268 /*
266 * Returns a potential message associated with a tab id (infobar)269 * Returns a potential message associated with a tab id (popup)
267 */270 */
268 return {271 return {
269 getMessageForTabId: function (tabId) {272 getMessageForTabId: function (tabId) {
270273
=== modified file 'chromium-extension/browser.js'
--- chromium-extension/browser.js 2014-05-20 13:40:09 +0000
+++ chromium-extension/browser.js 2015-10-07 04:25:10 +0000
@@ -10,20 +10,21 @@
10 var service = null;10 var service = null;
11 var api = {11 var api = {
12 init: function (options) {12 init: function (options) {
13 options.url = window.location.href;13 options.url = window.location.href;
14 options.hostname = window.location.hostname;14 options.hostname = window.location.hostname;
15 options.host = window.location.host;15 options.host = window.location.host;
16 options.protocol = window.location.protocol;16 options.protocol = window.location.protocol;
17 chrome.runtime.sendMessage (17 chrome.runtime.sendMessage(
18 {method: "init_requested", options: options}18 {method: "init_requested", options: options},
19 , function (response) {});19 function (response) {}
20 );
20 }21 }
21 };22 };
2223
23 /**24 /**
24 * Inserts a given script in the webpage.25 * Inserts a given script in the webpage.
25 * Needs chrome.extension functionality.26 * Needs chrome.extension functionality.
26 * 27 *
27 * @param path of file to be injected (part of the extension)28 * @param path of file to be injected (part of the extension)
28 */29 */
29 var insertScriptIntoWebpage = function (path) {30 var insertScriptIntoWebpage = function (path) {
@@ -47,14 +48,14 @@
47 var e = document.createEvent ("Events");48 var e = document.createEvent ("Events");
48 d.style.cssText = "display:none;";49 d.style.cssText = "display:none;";
49 d.value = id;50 d.value = id;
50 d.addEventListener ("unity-webapps-chromium-api-com-link-callback-called-ack"51 d.addEventListener("unity-webapps-chromium-api-com-link-callback-called-ack",
51 , function() { d.parentNode.removeChild (d); }52 function() { d.parentNode.removeChild (d); },
52 , true);53 true);
53 document.body.appendChild (d);54 document.body.appendChild (d);
54 e.initEvent ("unity-webapps-chromium-api-com-link-callback-called", false, true);55 e.initEvent ("unity-webapps-chromium-api-com-link-callback-called", false, true);
55 d.dispatchEvent (e);56 d.dispatchEvent (e);
56 };57 };
57 };58 }
5859
59 // TODO: should be shared / generated w/ web page code60 // TODO: should be shared / generated w/ web page code
60 var isIterableObject = function(obj) {61 var isIterableObject = function(obj) {
@@ -75,9 +76,9 @@
75 if ( ! isIterableObject(obj)) {76 if ( ! isIterableObject(obj)) {
76 return obj;77 return obj;
77 }78 }
78 if (obj79 if (obj &&
79 && obj.hasOwnProperty('callbackid')80 obj.hasOwnProperty('callbackid') &&
80 && obj.callbackid != null) {81 obj.callbackid !== null) {
81 return makeWebpageCallback (obj.callbackid);82 return makeWebpageCallback (obj.callbackid);
82 }83 }
8384
@@ -87,7 +88,7 @@
8788
88 if (isIterableObject (obj[key])) {89 if (isIterableObject (obj[key])) {
8990
90 if (obj[key].callbackid != null) {91 if (obj[key].callbackid !== null) {
91 ret[key] = makeWebpageCallback (obj[key].callbackid);92 ret[key] = makeWebpageCallback (obj[key].callbackid);
92 }93 }
93 else {94 else {
@@ -100,7 +101,7 @@
100 }101 }
101 }102 }
102 return ret;103 return ret;
103 };104 }
104105
105 // 2. open the communication mean between the two106 // 2. open the communication mean between the two
106107
@@ -120,9 +121,9 @@
120 console.log ('Error while dispatching call to ' + funcnames.join('.') + ': ' + err);121 console.log ('Error while dispatching call to ' + funcnames.join('.') + ': ' + err);
121 }122 }
122 };123 };
123 124
124 document.addEventListener("unity-webapps-chromium-api-com-link"125 document.addEventListener("unity-webapps-chromium-api-com-link",
125 , function(event) {126 function(event) {
126 var from = event.target;127 var from = event.target;
127 if (from) {128 if (from) {
128 var type = from.getAttribute("data-eventType");129 var type = from.getAttribute("data-eventType");
@@ -133,7 +134,7 @@
133 // Actuall call, e.g. 'Notification.showNotification("a","b")134 // Actuall call, e.g. 'Notification.showNotification("a","b")
134 // being reduces to successive calls to associated objects:135 // being reduces to successive calls to associated objects:
135 // Notification, showNotification136 // Notification, showNotification
136 // 137 //
137 // TODO add proper error handling138 // TODO add proper error handling
138 dispatchActualFunctionCall(type, args);139 dispatchActualFunctionCall(type, args);
139 }140 }
@@ -142,8 +143,8 @@
142 var ret = document.createEvent('Events');143 var ret = document.createEvent('Events');
143 ret.initEvent('unity-webapps-chromium-api-com-link-ack', true, false);144 ret.initEvent('unity-webapps-chromium-api-com-link-ack', true, false);
144 from.dispatchEvent(ret);145 from.dispatchEvent(ret);
145 }146 },
146 , true);147 true);
147 };148 };
148149
149 // handle the proxy side of the api which is being injected on the150 // handle the proxy side of the api which is being injected on the
@@ -151,4 +152,3 @@
151 injectApiProxy();152 injectApiProxy();
152 }153 }
153)(window);154)(window);
154
155155
=== removed file 'chromium-extension/build.sh'
--- chromium-extension/build.sh 2012-04-27 19:34:47 +0000
+++ chromium-extension/build.sh 1970-01-01 00:00:00 +0000
@@ -1,27 +0,0 @@
1#!/bin/bash -e
2
3
4CRX_FILENAME=`pwd`/../chromium-extension.crx
5PEM_FILENAME=`pwd`/../chromium-extension.pem
6
7if [ -e "$CRX_FILENAME" ]
8then
9 rm -f "$CRX_FILENAME"
10fi
11
12#if [ -e "$PEM_FILENAME" ]
13#then
14# rm -f "$PEM_FILENAME"
15#fi
16
17if test -n "`which google-chrome`"; then
18 google-chrome --no-message-box --pack-extension=`pwd` --pack-extension-key=../chromium-extension.pem
19else
20 chromium-browser --no-message-box --pack-extension=`pwd`
21fi
22
23# not necessary
24# mv `pwd`/../unity-chromium-extension.crx .
25
26
27
280
=== removed file 'chromium-extension/chromium-extension.pro'
--- chromium-extension/chromium-extension.pro 2014-05-21 12:53:43 +0000
+++ chromium-extension/chromium-extension.pro 1970-01-01 00:00:00 +0000
@@ -1,66 +0,0 @@
1include(../common-project-config.pri)
2include($${TOP_SRC_DIR}/common-vars.pri)
3
4TEMPLATE = aux
5
6EXTENSION_DIR = $${INSTALL_LIBDIR}/libunity-chromium
7EXTENSION_NAME = unity-webapps
8EXTENSION_FILE = $${EXTENSION_NAME}.crx
9
10STATIC_EXTENSION_FILES = \
11 background-page.html \
12 background-page.js \
13 base-content-script.js \
14 browser.js \
15 infobar.css \
16 infobar.html \
17 infobar.js \
18 _locales \
19 options.html \
20 options.js \
21 skin \
22 unity-api-page-proxy-builder-gen.js \
23 unity-api-page-proxy.js \
24
25SCRIPT_FILES = \
26 $${STATIC_EXTENSION_FILES} \
27 manifest.json \
28 unity-webapps.json
29
30QMAKE_SUBSTITUTES += \
31 manifest.json.in \
32 unity-webapps.json.in
33
34pemfile.target = unity-webapps.pem
35pemfile.commands = "openssl genrsa 1024 > $${pemfile.target}"
36
37static_files.depends = \
38 $${SCRIPT_FILES}
39static_files.commands = mkdir -p $${OUT_PWD}/$${EXTENSION_NAME} && ${COPY_DIR} $${SCRIPT_FILES} $${OUT_PWD}/$${EXTENSION_NAME}
40
41static_files_stamp.target = buildstamp
42static_files_stamp.depends = static_files
43static_files_stamp.commands = touch $${static_files_stamp.target}
44
45extension.target = res/$${EXTENSION_NAME}.crx
46extension.commands = $${TOP_SRC_DIR}/chromium-extension/crxmake.sh $${OUT_PWD}/$${EXTENSION_NAME} $${pemfile.target}
47extension.depends = pemfile static_files_stamp
48
49QMAKE_EXTRA_TARGETS += \
50 extension \
51 pemfile \
52 static_files \
53 static_files_stamp
54
55PRE_TARGETDEPS = $${extension.target}
56
57manifest.files = \
58 $${OUT_PWD}/res/*.json
59manifest.path = $${INSTALL_PREFIX}/share/chromium/extensions/
60manifest.CONFIG = no_check_exist
61INSTALLS += manifest
62
63crx.files = res/$${EXTENSION_NAME}.crx
64crx.path = $${EXTENSION_DIR}
65crx.CONFIG = no_check_exist
66INSTALLS += crx
670
=== removed file 'chromium-extension/infobar.css'
--- chromium-extension/infobar.css 2012-05-16 18:19:03 +0000
+++ chromium-extension/infobar.css 1970-01-01 00:00:00 +0000
@@ -1,20 +0,0 @@
1body {
2 background: -webkit-linear-gradient(#E9E9E9, #DADADA);
3 font-family: Tahoma, Geneva, sans-serif;
4 font-size: 13px;
5 height: 36px; /* Infobars are limited to 36-72px */
6 margin: 0;
7 overflow: hidden;
8 padding-left: 6px;
9 padding-right: 6px;
10 padding-top: 5px;
11}
12
13img {
14 padding-right: 6px;
15}
16
17button {
18 padding-right: 10px;
19}
20
210
=== removed file 'chromium-extension/infobar.html'
--- chromium-extension/infobar.html 2012-10-12 01:18:07 +0000
+++ chromium-extension/infobar.html 1970-01-01 00:00:00 +0000
@@ -1,20 +0,0 @@
1<html>
2
3<head>
4</head>
5
6<link rel="stylesheet" type="text/css" href="infobar.css"></link>
7<script src="infobar.js"></script>
8
9<body>
10
11<div id="content" style="display:none">
12 <span id="message"></span>
13 <input type="button" id="notintegrate" value="Never for this site" />
14 <input type="button" id="integrate" value="Yes" onclick="doIntegrate(true)"/>
15</div>
16
17</body>
18
19
20</html>
210
=== removed file 'chromium-extension/infobar.js'
--- chromium-extension/infobar.js 2014-11-18 07:07:15 +0000
+++ chromium-extension/infobar.js 1970-01-01 00:00:00 +0000
@@ -1,33 +0,0 @@
1var doIntegrate = function (integrate) {
2 chrome.tabs.query({currentWindow: true, active: true}, function (tabs) {
3 chrome.runtime.sendMessage({tabId: tabs[0].id, method: "on_user_infobar_request_result", integrate: integrate}
4 , function (response) {});
5 window.close();
6 });
7};
8
9window.onload = function () {
10 chrome.runtime.getBackgroundPage(function (bg) {
11 document.getElementById('notintegrate').onclick = function () { doIntegrate(false); };
12 document.getElementById('integrate').onclick = function () { doIntegrate(true); };
13
14 chrome.tabs.query({currentWindow: true, active: true}, function (tabs) {
15 if (tabs.length === 0) {
16 window.close();
17 return;
18 }
19 if (!bg || !bg.background_page) {
20 window.close();
21 return;
22 }
23 var msg = bg.background_page.getMessageForTabId(tabs[0].id);
24 if (msg == null) {
25 window.close();
26 return;
27 }
28 document.getElementById ('content').style.display = "block";
29 document.getElementById ('message').innerHTML = msg || "";
30 });
31 });
32};
33
340
=== modified file 'chromium-extension/manifest.json.in'
--- chromium-extension/manifest.json.in 2014-05-21 12:22:21 +0000
+++ chromium-extension/manifest.json.in 2015-10-07 04:25:10 +0000
@@ -1,42 +1,48 @@
1{1{
2 '"name": "Unity WebApps Chromium extension"',2 "name": "Unity WebApps Chromium extension",
3 '"manifest_version"': 2,3 "manifest_version": 2,
4 '"minimum_chrome_version": "34.0"',4 "minimum_chrome_version": "34.0",
5 '"content_security_policy"': '"script-src \'self\' chrome-extension://infobar.js \'unsafe-eval\'; object-src \'self\'"',5 "content_security_policy": "script-src \'self\' chrome-extension://infobar.js \'unsafe-eval\'; object-src \'self\'",
66
7 '"version": "$${PROJECT_VERSION}"',7 "version": "${PROJECT_VERSION}",
88
9 '"description": "Unity Webapps Chromium integration"',9 "description": "Unity Webapps Chromium integration",
1010
11 '"web_accessible_resources"': [11 "web_accessible_resources": [
12 '"browser.js"',12 "browser.js",
13 '"unity-api-page-proxy-builder-gen.js"',13 "unity-api-page-proxy-builder-gen.js",
14 '"unity-api-page-proxy.js"',14 "unity-api-page-proxy.js",
15 '"infobar.js"',15 "options.js"
16 '"options.js"'
17 ],16 ],
1817
19 '"icons"': {18 "icons": {
20 '"16": "skin/cof-16.png"',19 "16": "skin/cof-16.png",
21 '"48": "skin/cof-48.png"'20 "48": "skin/cof-48.png"
22 }, 21 },
2322
24 '"default_locale": "en"',23 "default_locale": "en",
2524
26 '"background"': {25 "background": {
27 '"page"': '"background-page.html"'26 "page": "background-page.html"
28 }, 27 },
2928
30 '"permissions": ["tabs", "http://*/*", "infobars", "nativeMessaging"]',29 "permissions": ["tabs", "http://*/*", "nativeMessaging"],
31 '"options_page": "options.html"',30 "page_action": {
32 31 "default_icon": {
33 '"content_scripts"': [32 "19": "skin/cof-16.png",
33 "38": "skin/cof-48.png"
34 },
35 "default_title": "Unity Webapps",
36 "default_popup": "popup.html"
37 },
38 "options_page": "options.html",
39
40 "content_scripts": [
34 {41 {
35 '"all_frames"': true,42 "all_frames": true,
36 '"matches": [ "<all_urls>" ]',43 "matches": [ "<all_urls>" ],
37 '"js": ["base-content-script.js"]',44 "js": ["base-content-script.js"],
38 '"run_at": "document_end"'45 "run_at": "document_end"
39 }46 }
40 ]47 ]
41}48}
42
4349
=== modified file 'chromium-extension/options.html'
--- chromium-extension/options.html 2012-11-08 18:15:19 +0000
+++ chromium-extension/options.html 2015-10-07 04:25:10 +0000
@@ -8,23 +8,23 @@
8 width: 600px;8 width: 600px;
9 font-size: 13px;9 font-size: 13px;
10 }10 }
11 11
12 body {12 body {
13 background-color: "#ebeff9";13 background-color: "#ebeff9";
14 font-family: Arial, sans-serif;14 font-family: Arial, sans-serif;
15 }15 }
16 16
17 #logo {17 #logo {
18 font-size: 20px;18 font-size: 20px;
19 text-align: center;19 text-align: center;
20 }20 }
21 21
22 #extensionName {22 #extensionName {
23 color: #444;23 color: #444;
24 font-size: 16px;24 font-size: 16px;
25 font-weight: 500;25 font-weight: 500;
26 }26 }
27 27
28 .setting {28 .setting {
29 pagging-left: 20px;29 pagging-left: 20px;
30 }30 }
@@ -48,5 +48,3 @@
4848
49</body>49</body>
50</html>50</html>
51
52
5351
=== modified file 'chromium-extension/options.js'
--- chromium-extension/options.js 2012-11-08 18:15:19 +0000
+++ chromium-extension/options.js 2015-10-07 04:25:10 +0000
@@ -1,6 +1,6 @@
1function save_options() {1function save_options() {
2 var logging = document.getElementById("logging");2 var logging = document.getElementById("logging");
3 localStorage["logging"] = logging.checked;3 localStorage.logging = logging.checked;
4}4}
55
6function restore_options() {6function restore_options() {
@@ -9,8 +9,8 @@
9 document.getElementById('logging').disabled = true;9 document.getElementById('logging').disabled = true;
10 return;10 return;
11 }11 }
12 12
13 var logging = localStorage["logging"];13 var logging = localStorage.logging;
14 var loggingElt = document.getElementById("logging");14 var loggingElt = document.getElementById("logging");
15 if (loggingElt) {15 if (loggingElt) {
16 loggingElt.checked = (logging == "true");16 loggingElt.checked = (logging == "true");
1717
=== added file 'chromium-extension/popup.css'
--- chromium-extension/popup.css 1970-01-01 00:00:00 +0000
+++ chromium-extension/popup.css 2015-10-07 04:25:10 +0000
@@ -0,0 +1,21 @@
1body {
2 background: -webkit-linear-gradient(#E9E9E9, #DADADA);
3 font-family: Tahoma, Geneva, sans-serif;
4 font-size: 13px;
5 height: 36px;
6 width: 300px;
7 margin: 0;
8 overflow: hidden;
9 padding-left: 6px;
10 padding-right: 6px;
11 padding-top: 5px;
12}
13
14img {
15 padding-right: 6px;
16}
17
18button {
19 padding-right: 10px;
20}
21
022
=== added file 'chromium-extension/popup.html'
--- chromium-extension/popup.html 1970-01-01 00:00:00 +0000
+++ chromium-extension/popup.html 2015-10-07 04:25:10 +0000
@@ -0,0 +1,20 @@
1<html>
2
3<head>
4</head>
5
6<link rel="stylesheet" type="text/css" href="popup.css"></link>
7<script src="popup.js"></script>
8
9<body>
10
11<div id="content" style="display:none">
12 <span id="message"></span>
13 <input type="button" id="notintegrate" value="Never for this site" />
14 <input type="button" id="integrate" value="Yes" onclick="doIntegrate(true)"/>
15</div>
16
17</body>
18
19
20</html>
021
=== added file 'chromium-extension/popup.js'
--- chromium-extension/popup.js 1970-01-01 00:00:00 +0000
+++ chromium-extension/popup.js 2015-10-07 04:25:10 +0000
@@ -0,0 +1,36 @@
1var doIntegrate = function (integrate) {
2 chrome.tabs.query({currentWindow: true, active: true}, function (tabs) {
3 chrome.runtime.sendMessage({
4 tabId: tabs[0].id,
5 method: "on_user_popup_request_result",
6 integrate: integrate
7 },
8 function (response) {});
9 window.close();
10 });
11};
12
13window.onload = function () {
14 chrome.runtime.getBackgroundPage(function (bg) {
15 document.getElementById('notintegrate').onclick = function () { doIntegrate(false); };
16 document.getElementById('integrate').onclick = function () { doIntegrate(true); };
17
18 chrome.tabs.query({currentWindow: true, active: true}, function (tabs) {
19 if (tabs.length === 0) {
20 window.close();
21 return;
22 }
23 if (!bg || !bg.background_page) {
24 window.close();
25 return;
26 }
27 var msg = bg.background_page.getMessageForTabId(tabs[0].id);
28 if (msg === null) {
29 window.close();
30 return;
31 }
32 document.getElementById ('content').style.display = "block";
33 document.getElementById ('message').innerHTML = msg || "";
34 });
35 });
36};
037
=== modified file 'chromium-extension/unity-api-page-proxy.js'
--- chromium-extension/unity-api-page-proxy.js 2014-05-20 13:40:09 +0000
+++ chromium-extension/unity-api-page-proxy.js 2015-10-07 04:25:10 +0000
@@ -1,5 +1,5 @@
1/**1/**
2 * 2 *
3 * 3 *
4 */4 */
5setTimeout (5setTimeout (
66
=== modified file 'chromium-extension/unity-webapps.json.in'
--- chromium-extension/unity-webapps.json.in 2014-05-21 09:03:42 +0000
+++ chromium-extension/unity-webapps.json.in 2015-10-07 04:25:10 +0000
@@ -1,4 +1,4 @@
1{1{
2 '"external_crx": "$${EXTENSION_DIR}/$${EXTENSION_FILE}"',2 "external_crx": "${EXTENSION_DIR}/${EXTENSION_FILE}",
3 '"external_version": "$${PROJECT_VERSION}"'3 "external_version": "${PROJECT_VERSION}"
4}4}
55
=== removed file 'common-project-config.pri'
--- common-project-config.pri 2014-05-19 14:04:19 +0000
+++ common-project-config.pri 1970-01-01 00:00:00 +0000
@@ -1,41 +0,0 @@
1#-----------------------------------------------------------------------------
2# Common configuration for all projects.
3#-----------------------------------------------------------------------------
4
5# we don't like warnings...
6QMAKE_CXXFLAGS += -Werror
7# Disable RTTI
8QMAKE_CXXFLAGS += -fno-exceptions -fno-rtti
9
10TOP_SRC_DIR = $$PWD
11TOP_BUILD_DIR = $${TOP_SRC_DIR}/$(BUILD_DIR)
12
13include(coverage.pri)
14
15#-----------------------------------------------------------------------------
16# setup the installation prefix
17#-----------------------------------------------------------------------------
18INSTALL_PREFIX = /usr # default installation prefix
19
20# default prefix can be overriden by defining PREFIX when running qmake
21isEmpty(PREFIX) {
22 message("====")
23 message("==== NOTE: To override the installation path run: `qmake PREFIX=/custom/path'")
24 message("==== (current installation path is `$${INSTALL_PREFIX}')")
25} else {
26 INSTALL_PREFIX = $${PREFIX}
27 message("====")
28 message("==== install prefix set to `$${INSTALL_PREFIX}'")
29}
30
31INSTALL_LIBDIR = $${INSTALL_PREFIX}/lib
32
33isEmpty(LIBDIR) {
34 message("====")
35 message("==== NOTE: To override the library installation path run: `qmake LIBDIR=/custom/path'")
36 message("==== (current installation path is `$${INSTALL_LIBDIR}')")
37} else {
38 INSTALL_LIBDIR = $${LIBDIR}
39 message("====")
40 message("==== install prefix set to `$${INSTALL_LIBDIR}'")
41}
420
=== removed file 'common-vars.pri'
--- common-vars.pri 2014-06-02 06:53:38 +0000
+++ common-vars.pri 1970-01-01 00:00:00 +0000
@@ -1,6 +0,0 @@
1#-----------------------------------------------------------------------------
2# Common variables for all projects.
3#-----------------------------------------------------------------------------
4
5PROJECT_NAME = unity_webapps_chromium
6PROJECT_VERSION = 3.2
70
=== removed file 'coverage.pri'
--- coverage.pri 2014-05-19 14:04:19 +0000
+++ coverage.pri 1970-01-01 00:00:00 +0000
@@ -1,49 +0,0 @@
1# Coverage
2CONFIG(coverage) {
3 OBJECTS_DIR =
4 MOC_DIR =
5 TOP_SRC_DIR = $$PWD
6
7 LIBS += -lgcov
8 QMAKE_CXXFLAGS += --coverage
9 QMAKE_LDFLAGS += --coverage
10
11 QMAKE_EXTRA_TARGETS += coverage cov
12 QMAKE_EXTRA_TARGETS += clean-gcno clean-gcda coverage-html \
13 generate-coverage-html clean-coverage-html coverage-gcovr \
14 generate-gcovr generate-coverage-gcovr clean-coverage-gcovr
15
16 clean-gcno.commands = \
17 "@echo Removing old coverage instrumentation"; \
18 "find -name '*.gcno' -print | xargs -r rm"
19
20 clean-gcda.commands = \
21 "@echo Removing old coverage results"; \
22 "find -name '*.gcda' -print | xargs -r rm"
23
24 coverage-html.depends = clean-gcda check generate-coverage-html
25
26 generate-coverage-html.commands = \
27 "@echo Collecting coverage data"; \
28 "lcov --directory $${TOP_SRC_DIR} --capture --output-file coverage.info --no-checksum --compat-libtool"; \
29 "lcov --extract coverage.info \"*/messaging-host/*.cpp\" -o coverage.info"; \
30 "lcov --remove coverage.info \"moc_*.cpp\" --remove coverage.info \"tests/*.cpp\" -o coverage.info"; \
31 "LANG=C genhtml --prefix $${TOP_SRC_DIR} --output-directory coverage-html --title \"Code Coverage\" --legend --show-details coverage.info"
32
33 clean-coverage-html.depends = clean-gcda
34 clean-coverage-html.commands = \
35 "lcov --directory $${TOP_SRC_DIR} -z"; \
36 "rm -rf coverage.info coverage-html"
37
38 coverage-gcovr.depends = clean-gcda check generate-coverage-gcovr
39
40 generate-coverage-gcovr.commands = \
41 "@echo Generating coverage GCOVR report"; \
42 "gcovr -x -r $${TOP_SRC_DIR} -o $${TOP_SRC_DIR}/coverage.xml -e \".*/moc_.*\" -e \"tests/.*\" -e \".*\\.h\""
43
44 clean-coverage-gcovr.depends = clean-gcda
45 clean-coverage-gcovr.commands = \
46 "rm -rf $${TOP_SRC_DIR}/coverage.xml"
47
48 QMAKE_CLEAN += *.gcda *.gcno coverage.info coverage.xml
49}
500
=== modified file 'debian/changelog'
--- debian/changelog 2015-01-19 16:49:41 +0000
+++ debian/changelog 2015-10-07 04:25:10 +0000
@@ -1,3 +1,10 @@
1unity-chromium-extension (3.2.1+15.04.20150119-0ubuntu1) vivid; urgency=medium
2
3 * Fixes: 1469601, by changing the notification method to use the pageAction
4 facility for display.
5
6 -- Justin McPherson <justin.mcpherson@canonical.com> Tue, 30 Jun 2015 13:18:59 +1000
7
1unity-chromium-extension (3.2.0+15.04.20150119-0ubuntu1) vivid; urgency=medium8unity-chromium-extension (3.2.0+15.04.20150119-0ubuntu1) vivid; urgency=medium
29
3 [ Justin McPherson ]10 [ Justin McPherson ]
411
=== modified file 'debian/control'
--- debian/control 2014-12-17 14:18:53 +0000
+++ debian/control 2015-10-07 04:25:10 +0000
@@ -1,17 +1,19 @@
1Source: unity-chromium-extension1Source: unity-chromium-extension
2Priority: optional2Priority: optional
3Maintainer: Ubuntu Desktop Team <ubuntu-desktop@lists.ubuntu.com>3Maintainer: Ubuntu Webapps Team <webapps@lists.ubuntu.com>
4Build-Depends: chromium-browser (>= 34.0.1847.116-0ubuntu2),4Build-Depends: debhelper (>= 9),
5 debhelper (>= 9),
6 dh-autoreconf,5 dh-autoreconf,
7 libglib2.0-dev,6 libglib2.0-dev,
8 libunity-webapps-dev (>= 1.8.0),7 libunity-webapps-dev (>= 1.8.0) [!armhf],
8 libjson-glib-dev,
9 libclick-0.4-dev,
10 libubuntu-app-launch2-dev,
9 openssl,11 openssl,
10 pkg-config,12 pkg-config,
11 vim-common,13 vim-common,
12 zip,14 zip,
13 qt5-default,15 qt5-default,
14 qt5-qmake,16 cmake,
15 xvfb,17 xvfb,
16Standards-Version: 3.9.518Standards-Version: 3.9.5
17Section: gnome19Section: gnome
@@ -25,9 +27,15 @@
25Architecture: any27Architecture: any
26Depends: chromium-browser (>= 34.0.1847.116-0ubuntu2),28Depends: chromium-browser (>= 34.0.1847.116-0ubuntu2),
27 unity-webapps-service,29 unity-webapps-service,
30 unity-webapps-extension-process,
28 webbrowser-app,31 webbrowser-app,
29 ${misc:Depends},32 ${misc:Depends},
30Breaks: libunity-webapps-chromium,33Breaks: libunity-webapps-chromium,
31Replaces: libunity-webapps-chromium,34Replaces: libunity-webapps-chromium,
32Description: Unity WebApp extension for the chromium browser35Description: Unity WebApp extension for the chromium browser
33 Chromium browser extension for Unity WebApp integration36 Chromium browser extension for Unity WebApp integration
37
38Package: unity-webapps-extension-process
39Architecture: any
40Depends: ${misc:Depends},
41Description: Unity WebApp extension for installing or activating local web apps.
3442
=== modified file 'debian/unity-chromium-extension.install'
--- debian/unity-chromium-extension.install 2014-05-22 07:11:49 +0000
+++ debian/unity-chromium-extension.install 2015-10-07 04:25:10 +0000
@@ -1,4 +1,3 @@
1etc/chromium/native-messaging-hosts/com.canonical.webapp.installer.json1etc/chromium/native-messaging-hosts/com.canonical.webapp.extension.json
2usr/lib/libunity-chromium/unity-webapps.crx2usr/lib/*/libunity-chromium/unity-webapps.crx
3usr/share/chromium/extensions/*.json3usr/share/chromium/extensions/*.json
4usr/share/unity-webapps/bin/unity-webapps-messaging-host
54
=== added file 'debian/unity-webapps-extension-process.install'
--- debian/unity-webapps-extension-process.install 1970-01-01 00:00:00 +0000
+++ debian/unity-webapps-extension-process.install 2015-10-07 04:25:10 +0000
@@ -0,0 +1,1 @@
1usr/share/unity-webapps/bin/*
02
=== added file 'messaging-host/CMakeLists.txt'
--- messaging-host/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ messaging-host/CMakeLists.txt 2015-10-07 04:25:10 +0000
@@ -0,0 +1,101 @@
1# vim:expandtab:shiftwidth=2:tabstop=2:
2
3# Copyright (C) 2015 Canonical Ltd.
4
5# This library is free software; you can redistribute it and/or
6# modify it under the terms of the GNU Lesser General Public
7# License as published by the Free Software Foundation; either
8# version 2.1 of the License, or (at your option) any later version.
9
10# This library is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13# Lesser General Public License for more details.
14
15# You should have received a copy of the GNU Lesser GeneraGl Public
16# License along with this library; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
19cmake_minimum_required(VERSION 2.8.11)
20
21project(messaging-host)
22
23set(EXTENSION_NAME webapps-extension)
24set(EXTENSION_MANIFEST com.canonical.webapp.extension.json)
25set(WEBAPPS_BINDIR ${CMAKE_INSTALL_FULL_DATADIR}/unity-webapps/bin)
26
27set(CMAKE_INCLUDE_CURRENT_DIR ON)
28set(CMAKE_AUTOMOC ON)
29set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
30set(SRC)
31
32find_package(PkgConfig)
33find_package(Qt5Core)
34
35pkg_check_modules(GLIB glib-2.0 REQUIRED)
36pkg_check_modules(GOBJECT gobject-2.0 REQUIRED)
37pkg_check_modules(JSON_GLIB json-glib-1.0 REQUIRED)
38pkg_check_modules(CLICK click-0.4 REQUIRED)
39pkg_check_modules(UBUNTU_APP_LAUNCH ubuntu-app-launch-2 REQUIRED)
40pkg_check_modules(WEBAPPS libunity_webapps-0.2)
41pkg_check_modules(WEBAPPS_REPO libunity-webapps-repository)
42
43# Build and install chromium's extension manifest
44configure_file(
45 ${EXTENSION_MANIFEST}.in
46 ${CMAKE_CURRENT_BINARY_DIR}/${EXTENSION_MANIFEST}
47)
48
49install(
50 FILES ${CMAKE_CURRENT_BINARY_DIR}/${EXTENSION_MANIFEST}
51 DESTINATION /etc/chromium/native-messaging-hosts
52)
53
54list(
55 APPEND SRC
56 main.cpp
57 connection.cpp
58 inactivity-timer.cpp
59 service.cpp
60 service-handler.cpp
61 click-handler.cpp
62)
63add_definitions(-DHAVE_CLICK_SUPPORT=1)
64
65if(DEFINED WEBAPPS_FOUND AND WEBAPPS_FOUND EQUAL 1)
66 if(DEFINED WEBAPPS_REPO_FOUND AND WEBAPPS_REPO_FOUND EQUAL 1)
67 list(APPEND SRC webapps-handler.cpp webapps-process.cpp)
68 add_definitions(-DHAVE_UNITY_WEBAPPS=1)
69 endif()
70endif()
71
72include_directories(
73 ${GLIB_INCLUDE_DIRS}
74 ${JSON_GLIB_INCLUDE_DIRS}
75 ${UBUNTU_APP_LAUNCH_INCLUDE_DIRS}
76 ${WEBAPPS_INCLUDE_DIRS}
77 ${WEBAPPS_REPO_INCLUDE_DIRS}
78)
79
80add_executable(
81 ${EXTENSION_NAME}
82
83 ${SRC}
84)
85
86target_link_libraries(
87 ${EXTENSION_NAME}
88
89 Qt5::Core
90 ${GLIB_LIBRARIES}
91 ${WEBAPPS_LIBRARIES}
92 ${WEBAPPS_REPO_LIBRARIES}
93 ${JSON_GLIB_LIBRARIES}
94 ${CLICK_LIBRARIES}
95 ${UBUNTU_APP_LAUNCH_LIBRARIES}
96)
97
98install(
99 TARGETS ${EXTENSION_NAME}
100 RUNTIME DESTINATION ${WEBAPPS_BINDIR}
101)
0102
=== removed file 'messaging-host/Makefile.am'
--- messaging-host/Makefile.am 2014-05-14 07:59:30 +0000
+++ messaging-host/Makefile.am 1970-01-01 00:00:00 +0000
@@ -1,2 +0,0 @@
1EXTRA_DIST += \
2 installation-host
30
=== added file 'messaging-host/click-handler.cpp'
--- messaging-host/click-handler.cpp 1970-01-01 00:00:00 +0000
+++ messaging-host/click-handler.cpp 2015-10-07 04:25:10 +0000
@@ -0,0 +1,386 @@
1/*
2 * Copyright (C) 2015 Canonical Ltd.
3 *
4 * This file is part of webapps-extension
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Justin McPherson <justin.mcpherson@canonical.com>
19 *
20 */
21
22#if defined(HAVE_UNITY_WEBAPPS)
23extern "C" {
24#include <unity-webapps-permissions.h>
25}
26#endif
27
28#include <click-0.4/click.h>
29#include <ubuntu-app-launch.h>
30
31#include "click-handler.h"
32
33#include <QUrl>
34#include <QDebug>
35
36namespace UnityWebapps {
37
38namespace {
39static const gchar* maintainer_key = "maintainer";
40static const gchar* title_key = "title";
41static const gchar* name_key = "name";
42static const gchar* version_key = "version";
43static const gchar* maintainer_name = "Webapps Team <webapps@lists.launchpad.net>";
44static const gchar* directory_key = "_directory";
45static const gchar* hooks_key = "hooks";
46static const gchar* urls_key = "urls";
47static const gchar* desktop_key = "desktop";
48static const gchar* domain_suffix_key = "domain-suffix";
49static const gchar* launch_method = "launch_click";
50static const gchar* available_method = "click_available";
51
52gchar* dispatcherFilenameFromManifest(JsonObject *manifest)
53{
54 const gchar* directory = json_object_get_string_member(manifest, directory_key);
55 JsonObject* hooks = json_object_get_object_member(manifest, hooks_key);
56 if (directory == nullptr || hooks == nullptr) {
57 return nullptr;
58 }
59
60 const gchar* dispatcher_filename = nullptr;
61
62 // Search objects in hooks for urls key
63 json_object_foreach_member(hooks, [](JsonObject* object, const gchar* member_name, JsonNode* member_node, gpointer user_data) {
64 const gchar** df = static_cast<const gchar**>(user_data);
65 if (*df != nullptr)
66 return;
67 if (json_node_get_node_type(member_node) != JSON_NODE_OBJECT)
68 return;
69
70 JsonObject *member_object = json_node_get_object(member_node);
71 json_object_foreach_member(member_object, [](JsonObject* object, const gchar* member_name, JsonNode* member_node, gpointer user_data) {
72 if (g_ascii_strncasecmp(urls_key, member_name, strlen(urls_key)) == 0) {
73 const gchar** df = static_cast<const gchar**>(user_data);
74 *df = json_object_get_string_member(object, urls_key);
75 }
76 }, user_data);
77 }, &dispatcher_filename);
78
79 if (dispatcher_filename == nullptr) {
80 return nullptr;
81 }
82
83 return g_strjoin("/", directory, dispatcher_filename, nullptr);
84}
85
86gchar* appLaunchAppIdFromManifest(JsonObject *manifest)
87{
88 JsonObject* hooks = json_object_get_object_member(manifest, hooks_key);
89 if (hooks == nullptr) {
90 return nullptr;
91 }
92
93 // Find hook used in creation of desktop file
94 gchar* hook_name = nullptr;
95 json_object_foreach_member(hooks, [](JsonObject* object, const gchar* member_name, JsonNode* member_node, gpointer user_data) {
96 gchar** hn = static_cast<gchar**>(user_data);
97 if (*hn != nullptr)
98 return;
99 if (json_node_get_node_type(member_node) != JSON_NODE_OBJECT)
100 return;
101
102 JsonObject *member_object = json_node_get_object(member_node);
103 if (json_object_has_member(member_object, desktop_key)) {
104 *hn = g_strdup(member_name);
105 }
106 }, &hook_name);
107
108 if (hook_name == nullptr) {
109 return nullptr;
110 }
111
112 const gchar* app_name = json_object_get_string_member(manifest, name_key);
113 const gchar* app_version = json_object_get_string_member(manifest, version_key);
114 if (app_name == nullptr || app_version == nullptr) {
115 g_free(hook_name);
116 return nullptr;
117 }
118
119 gchar *result = g_strjoin("_", app_name, hook_name, app_version, nullptr);
120 g_free(hook_name);
121 return result;
122}
123
124GList* domainsFromDispatcherFile(const gchar* dispatcher_filename)
125{
126 GList *domains = nullptr;
127 JsonParser* parser = json_parser_new();
128 GError* error = nullptr;
129 if (!json_parser_load_from_file(parser, dispatcher_filename, &error)) {
130 qDebug() << "Error parsing URL dispatched JSON" << error->message;
131 return nullptr;
132 }
133
134 JsonNode* root = json_parser_get_root(parser);
135 if (json_node_get_node_type(root) != JSON_NODE_ARRAY) {
136 qDebug() << "Unexpected contents of URL dispatcher JSON file";
137 return nullptr;
138 }
139
140 JsonArray* domains_array = json_node_get_array(root);
141 json_array_foreach_element(domains_array, [](JsonArray*, guint index, JsonNode* element_node, gpointer user_data) {
142 if (json_node_get_node_type(element_node) == JSON_NODE_OBJECT) {
143 JsonObject *object = json_node_get_object(element_node);
144 const gchar *domain_suffix = json_object_get_string_member(object, domain_suffix_key);
145 if (domain_suffix != nullptr) {
146 GList** domains = static_cast<GList**>(user_data);
147 *domains = g_list_append(*domains, g_strdup(domain_suffix));
148 }
149 }
150 }, &domains);
151
152 g_object_unref(parser);
153
154 return domains;
155}
156
157}
158
159class ClickHandlerPrivate
160{
161 Q_DECLARE_PUBLIC(ClickHandler)
162
163public:
164 inline ClickHandlerPrivate(ClickHandler *service);
165 inline ~ClickHandlerPrivate();
166
167 GList* findMatchingApplications(const QUrl& url);
168
169private:
170 ClickDB* getDatabase();
171
172 ClickHandler *q_ptr;
173 ClickDB *clickDb;
174};
175
176
177ClickHandlerPrivate::ClickHandlerPrivate(ClickHandler *service)
178 : q_ptr(service)
179 , clickDb(nullptr)
180{
181}
182
183ClickHandlerPrivate::~ClickHandlerPrivate()
184{
185 if (clickDb != nullptr) {
186 g_object_unref(G_OBJECT(clickDb));
187 }
188}
189
190GList* ClickHandlerPrivate::findMatchingApplications(const QUrl& url)
191{
192 GError *error = nullptr;
193 JsonArray *manifests = click_db_get_manifests(getDatabase(), true, &error);
194 if (error != nullptr) {
195 qDebug() << __func__ << "error: " << error->message;
196 g_error_free(error);
197 return nullptr;
198 }
199
200 struct _context {
201 GList *matching_apps;
202 const QUrl& visited_url;
203 } context{nullptr, url};
204
205 json_array_foreach_element(manifests, [](JsonArray*, guint index, JsonNode* element_node, gpointer user_data) {
206 _context* context = static_cast<_context*>(user_data);
207
208 if (json_node_get_node_type(element_node) != JSON_NODE_OBJECT) {
209 return;
210 }
211 JsonObject *manifest = json_node_get_object(element_node);
212
213 // Look for maintainer == Webapps Team <webapps@lists.launchpad.net>
214 if (qgetenv("UNITY_WEBAPPS_IGNORE_MAINTAINER") != QByteArrayLiteral("1")) {
215 const gchar *maintainer = json_object_get_string_member(manifest, maintainer_key);
216 if (maintainer == nullptr ||
217 g_ascii_strncasecmp(maintainer, maintainer_name, strlen(maintainer_name)) != 0) {
218 return;
219 }
220 }
221
222 // Look at url dispatcher
223 gchar* dispatcher_filename = dispatcherFilenameFromManifest(manifest);
224 if (dispatcher_filename == nullptr) {
225 return;
226 }
227
228 GList* domains = domainsFromDispatcherFile(dispatcher_filename);
229 if (domains == nullptr) {
230 g_free(dispatcher_filename);
231 return;
232 }
233
234 for (GList *item = domains; item->next != nullptr; item = item->next) {
235 QStringList visited_url_parts = context->visited_url.host().split(".");
236 QStringList test_url_parts = QString::fromLatin1((gchar*)item->data).split(".");
237 int visited_length = visited_url_parts.length();
238 int test_length = test_url_parts.length();
239 if (visited_length == test_length) {
240 if (visited_url_parts == test_url_parts) {
241 json_object_ref(manifest);
242 context->matching_apps = g_list_append(context->matching_apps, manifest);
243 }
244 } else {
245 // Every part of test url must match
246 if (visited_length >= test_length) {
247 bool match = true;
248 for (int i = 1; i < test_length + 1; ++i) {
249 if (test_url_parts.at(test_length - i) != visited_url_parts.at(visited_length - i)) {
250 match = false;
251 break;
252 }
253 }
254 if (match) {
255 json_object_ref(manifest);
256 context->matching_apps = g_list_append(context->matching_apps, manifest);
257 }
258 }
259 }
260 }
261 g_list_free_full(domains, g_free);
262 g_free(dispatcher_filename);
263 }, &context);
264
265 return context.matching_apps;
266}
267
268
269
270ClickDB* ClickHandlerPrivate::getDatabase()
271{
272 if (clickDb == nullptr) {
273 GError *error = nullptr;
274 clickDb = click_db_new();
275 click_db_read(clickDb, nullptr, &error);
276 if (error != nullptr) {
277 qDebug() << __func__ << "error: " << error->message;
278 g_error_free(error);
279 g_object_unref(clickDb);
280 clickDb = nullptr;
281 }
282 }
283
284 return clickDb;
285}
286
287
288ClickHandler::ClickHandler(QObject *parent)
289 : QObject(parent)
290 , d_ptr(new ClickHandlerPrivate(this))
291{
292}
293
294ClickHandler::~ClickHandler()
295{
296 delete d_ptr;
297}
298
299QVariantMap ClickHandler::click_available(const QVariantMap &message)
300{
301 Q_D(ClickHandler);
302
303 QVariantMap reply;
304 reply.insert("method", available_method);
305 if (!message.contains("url")) {
306 reply.insert("error", QStringLiteral("malformed request"));
307 return reply;
308 }
309
310 QString url = message.value("url").toString();
311
312 GList *matching_apps = d->findMatchingApplications(QUrl(url));
313
314 if (matching_apps == nullptr) {
315 reply.insert("available", false);
316 return reply;
317 }
318
319 // First element is OK
320 JsonObject* package_object = static_cast<JsonObject*>(matching_apps->data);
321
322 const gchar *appName = json_object_get_string_member(package_object, title_key);
323 const gchar *appDomain = nullptr; /* something from url dispatcher?*/
324 const gchar *appVersion = json_object_get_string_member(package_object, version_key);
325
326#if defined(HAVE_UNITY_WEBAPPS)
327 if (unity_webapps_permissions_get_domain_dontask(appDomain) ||
328 unity_webapps_permissions_get_domain_allowed(appDomain)) {
329 reply.insert("available", false);
330 for (GList *item = matching_apps; item->next != nullptr; item = item->next) {
331 json_object_unref(static_cast<JsonObject*>(item->data));
332 }
333 return reply;
334 }
335#endif
336 reply.insert("available", true);
337 reply.insert("appName", QString::fromUtf8(appName));
338 reply.insert("appDomain", QString::fromUtf8(appDomain));
339 reply.insert("appVersion", QString::fromUtf8(appVersion));
340
341 for (GList *item = matching_apps; item->next != nullptr; item = item->next) {
342 json_object_unref(static_cast<JsonObject*>(item->data));
343 }
344
345 return reply;
346}
347
348QVariantMap ClickHandler::launch_click(const QVariantMap& message)
349{
350 Q_D(ClickHandler);
351
352 QVariantMap reply;
353 reply.insert("method", launch_method);
354
355 if (!message.contains("url")) {
356 reply.insert("error", QLatin1String("malformed request"));
357 return reply;
358 }
359
360 QString url = message.value("url").toString();
361 reply.insert("url", url);
362
363 GList *matching_apps = d->findMatchingApplications(QUrl(url));
364 if (matching_apps == nullptr) {
365 reply.insert("launched", false);
366 reply.insert("available", false);
367 return reply;
368 }
369
370 // Grab first, convert to an "app id"
371 JsonObject* manifest = (JsonObject*)matching_apps->data;
372
373 gchar* app_id = appLaunchAppIdFromManifest(manifest);
374 if (app_id == nullptr) {
375 reply.insert("launched", false);
376 return reply;
377 }
378
379 gboolean app_launched = ubuntu_app_launch_start_application(app_id, nullptr);
380 g_free(app_id);
381
382 reply.insert("launched", bool(app_launched));
383 return reply;
384}
385
386} // namespace
0387
=== added file 'messaging-host/click-handler.h'
--- messaging-host/click-handler.h 1970-01-01 00:00:00 +0000
+++ messaging-host/click-handler.h 2015-10-07 04:25:10 +0000
@@ -0,0 +1,55 @@
1/*
2 * Copyright (C) 2015 Canonical Ltd.
3 *
4 * This file is part of unity-chromium-extension
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Justin McPherson <justin.mcpherson@canonical.com>
19 *
20 */
21
22#ifndef UNITY_WEBAPPS_CLICK_HANDLER
23#define UNITY_WEBAPPS_CLICK_HANDLER
24
25#include <QObject>
26#include <QVariantMap>
27
28namespace UnityWebapps {
29
30class ClickHandlerPrivate;
31class ClickHandler : public QObject
32{
33 Q_OBJECT
34
35public:
36 explicit ClickHandler(QObject *parent = 0);
37 ~ClickHandler();
38
39public Q_SLOTS:
40 QVariantMap click_available(const QVariantMap& message);
41 QVariantMap launch_click(const QVariantMap& message);
42
43#if defined(UCX_UNDER_TEST)
44public:
45#else
46private:
47#endif
48
49 ClickHandlerPrivate *d_ptr;
50 Q_DECLARE_PRIVATE(ClickHandler)
51};
52
53} // namespace
54
55#endif // UNITY_WEBAPPS_CLICK_HANDLER
056
=== added file 'messaging-host/com.canonical.webapp.extension.json.in'
--- messaging-host/com.canonical.webapp.extension.json.in 1970-01-01 00:00:00 +0000
+++ messaging-host/com.canonical.webapp.extension.json.in 2015-10-07 04:25:10 +0000
@@ -0,0 +1,9 @@
1{
2 "name": "com.canonical.webapp.extension",
3 "description": "Canonical WebApp Extension Host",
4 "path": "${WEBAPPS_BINDIR}/${EXTENSION_NAME}",
5 "type": "stdio",
6 "allowed_origins": [
7 "chrome-extension://pmoflmbbcfgacopiikdcpmbiellfihdg/"
8 ]
9}
010
=== removed file 'messaging-host/com.canonical.webapp.installer.json.in'
--- messaging-host/com.canonical.webapp.installer.json.in 2014-05-21 12:32:50 +0000
+++ messaging-host/com.canonical.webapp.installer.json.in 1970-01-01 00:00:00 +0000
@@ -1,9 +0,0 @@
1{
2 '"name": "com.canonical.webapp.installer"',
3 '"description": "Canonical WebApp Installation Host"',
4 '"path": "$${target.path}/$${TARGET}"',
5 '"type": "stdio"',
6 '"allowed_origins"': [
7 '"chrome-extension://pmoflmbbcfgacopiikdcpmbiellfihdg/"'
8 ]
9}
100
=== modified file 'messaging-host/main.cpp'
--- messaging-host/main.cpp 2014-06-20 06:16:48 +0000
+++ messaging-host/main.cpp 2015-10-07 04:25:10 +0000
@@ -21,12 +21,22 @@
21#include "connection.h"21#include "connection.h"
22#include "inactivity-timer.h"22#include "inactivity-timer.h"
23#include "service.h"23#include "service.h"
24#include "service-handler.h"
25#if defined(HAVE_UNITY_WEBAPPS)
26#include "webapps-process.h"
24#include "webapps-handler.h"27#include "webapps-handler.h"
25#include "webapps-process.h"28#endif
29#if defined(HAVE_CLICK_SUPPORT)
30#include "click-handler.h"
31#endif
2632
27#include <QCoreApplication>33#include <QCoreApplication>
28#include <QDebug>34#include <QDebug>
2935
36namespace {
37// Time in milliseconds before process exits from timeout.
38const int INACTIVE_TIMEOUT = 2 * 60 * 1000;
39}
3040
31void syslogOutputHandler(QtMsgType type, const QMessageLogContext &, const QString &msg)41void syslogOutputHandler(QtMsgType type, const QMessageLogContext &, const QString &msg)
32{42{
@@ -61,13 +71,24 @@
6171
62 QCoreApplication app(argc, argv);72 QCoreApplication app(argc, argv);
6373
74 UnityWebapps::Service service;
75
76 // Handle service wide messages
77 UnityWebapps::ServiceHandler service_handler;
78 service.addHandler(&service_handler);
79
80#if defined(HAVE_UNITY_WEBAPPS)
64 UnityWebapps::Process process;81 UnityWebapps::Process process;
6582 UnityWebapps::WebappsHandler apt_handler;
66 UnityWebapps::Service service;83 service.addHandler(&apt_handler);
67 UnityWebapps::WebappsHandler handler;84#endif
68 service.addHandler(&handler);85
6986#if defined(HAVE_CLICK_SUPPORT)
70 UnityWebapps::InactivityTimer inactivityTimer(2 * 60 * 1000);87 UnityWebapps::ClickHandler click_handler;
88 service.addHandler(&click_handler);
89#endif
90
91 UnityWebapps::InactivityTimer inactivityTimer(INACTIVE_TIMEOUT);
71 QObject::connect(&inactivityTimer, SIGNAL(timeout()), &app, SLOT(quit()));92 QObject::connect(&inactivityTimer, SIGNAL(timeout()), &app, SLOT(quit()));
72 inactivityTimer.watchObject(&service);93 inactivityTimer.watchObject(&service);
7394
@@ -88,4 +109,3 @@
88109
89 return r;110 return r;
90}111}
91
92112
=== removed file 'messaging-host/messaging-host.pro'
--- messaging-host/messaging-host.pro 2014-06-20 06:16:48 +0000
+++ messaging-host/messaging-host.pro 1970-01-01 00:00:00 +0000
@@ -1,42 +0,0 @@
1include(../common-project-config.pri)
2
3TEMPLATE = app
4TARGET = unity-webapps-messaging-host
5
6CONFIG += \
7 link_pkgconfig \
8 qt
9
10QT += \
11 core
12
13PKGCONFIG += \
14 glib-2.0 \
15 gobject-2.0 \
16 libunity_webapps-0.2 \
17 libunity-webapps-repository \
18
19SOURCES = \
20 connection.cpp \
21 inactivity-timer.cpp \
22 main.cpp \
23 service.cpp \
24 webapps-handler.cpp \
25 webapps-process.cpp \
26
27HEADERS = \
28 connection.h \
29 inactivity-timer.h \
30 service.h \
31 webapps-handler.h \
32 webapps-process.h \
33
34target.path = $${INSTALL_PREFIX}/share/unity-webapps/bin
35INSTALLS += target
36
37QMAKE_SUBSTITUTES += \
38 com.canonical.webapp.installer.json.in
39
40manifest.path = "/etc/chromium/native-messaging-hosts"
41manifest.files = com.canonical.webapp.installer.json
42INSTALLS += manifest
430
=== added file 'messaging-host/service-handler.cpp'
--- messaging-host/service-handler.cpp 1970-01-01 00:00:00 +0000
+++ messaging-host/service-handler.cpp 2015-10-07 04:25:10 +0000
@@ -0,0 +1,75 @@
1/*
2 * Copyright (C) 2015 Canonical Ltd.
3 *
4 * This file is part of webapps-extension
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Justin McPherson <justin.mcpherson@canonical.com>
19 *
20 */
21
22#include "service-handler.h"
23
24#include <QDebug>
25#include <QRegularExpression>
26
27
28namespace UnityWebapps {
29
30class ServiceHandlerPrivate
31{
32 Q_DECLARE_PUBLIC(ServiceHandler)
33
34public:
35 ServiceHandlerPrivate(ServiceHandler *service);
36 ~ServiceHandlerPrivate();
37
38private:
39 mutable ServiceHandler *q_ptr;
40};
41
42
43ServiceHandlerPrivate::ServiceHandlerPrivate(ServiceHandler *service)
44 : q_ptr(service)
45{
46}
47
48ServiceHandlerPrivate::~ServiceHandlerPrivate()
49{
50}
51
52
53ServiceHandler::ServiceHandler(QObject *parent)
54 : QObject(parent)
55 , d_ptr(new ServiceHandlerPrivate(this))
56{
57}
58
59ServiceHandler::~ServiceHandler()
60{
61 delete d_ptr;
62}
63
64QVariantMap ServiceHandler::ping(const QVariantMap &message)
65{
66 Q_UNUSED(message);
67
68 QVariantMap reply;
69
70 reply.insert("pong", QLatin1String("alive"));
71
72 return reply;
73}
74
75} // namespace
076
=== added file 'messaging-host/service-handler.h'
--- messaging-host/service-handler.h 1970-01-01 00:00:00 +0000
+++ messaging-host/service-handler.h 2015-10-07 04:25:10 +0000
@@ -0,0 +1,54 @@
1/*
2 * Copyright (C) 2015 Canonical Ltd.
3 *
4 * This file is part of unity-chromium-extension
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Justin McPherson <justin.mcpherson@canonical.com>
19 *
20 */
21
22#ifndef UNITY_WEBAPPS_SERVICE_HANDLER
23#define UNITY_WEBAPPS_SERVICE_HANDLER
24
25#include <QObject>
26#include <QVariantMap>
27
28namespace UnityWebapps {
29
30class ServiceHandlerPrivate;
31class ServiceHandler : public QObject
32{
33 Q_OBJECT
34
35public:
36 explicit ServiceHandler(QObject *parent = 0);
37 ~ServiceHandler();
38
39public Q_SLOTS:
40 QVariantMap ping(const QVariantMap &message);
41
42#if defined(UCX_UNDER_TEST)
43public:
44#else
45private:
46#endif
47 ServiceHandlerPrivate *d_ptr;
48 Q_DECLARE_PRIVATE(ServiceHandler)
49};
50
51} // namespace
52
53#endif // UNITY_WEBAPPS_SERVICE_HANDLER
54
055
=== modified file 'messaging-host/service.cpp'
--- messaging-host/service.cpp 2014-05-21 08:18:12 +0000
+++ messaging-host/service.cpp 2015-10-07 04:25:10 +0000
@@ -45,9 +45,9 @@
4545
46} // namespace46} // namespace
4747
48ServicePrivate::ServicePrivate(Service *service):48ServicePrivate::ServicePrivate(Service *service)
49 m_isIdle(true),49 : m_isIdle(true)
50 q_ptr(service)50 , q_ptr(service)
51{51{
52}52}
5353
@@ -59,14 +59,16 @@
59{59{
60 Q_Q(Service);60 Q_Q(Service);
6161
62 if (m_isIdle == isIdle) return;62 if (m_isIdle == isIdle) {
63 return;
64 }
63 m_isIdle = isIdle;65 m_isIdle = isIdle;
64 Q_EMIT q->isIdleChanged();66 Q_EMIT q->isIdleChanged();
65}67}
6668
67Service::Service(QObject *parent):69Service::Service(QObject *parent)
68 QObject(parent),70 : QObject(parent)
69 d_ptr(new ServicePrivate(this))71 , d_ptr(new ServicePrivate(this))
70{72{
71}73}
7274
@@ -83,7 +85,6 @@
83void Service::addHandler(QObject *handler)85void Service::addHandler(QObject *handler)
84{86{
85 Q_D(Service);87 Q_D(Service);
86
87 d->m_handlers.append(handler);88 d->m_handlers.append(handler);
88}89}
8990
@@ -92,7 +93,9 @@
92 Q_D(Service);93 Q_D(Service);
9394
94 QByteArray method = message.value(QStringLiteral("method")).toString().toLatin1();95 QByteArray method = message.value(QStringLiteral("method")).toString().toLatin1();
95 if (Q_UNLIKELY(method.isEmpty())) return;96 if (Q_UNLIKELY(method.isEmpty())) {
97 return;
98 }
9699
97 QByteArray methodSignature = method + "(QVariantMap)";100 QByteArray methodSignature = method + "(QVariantMap)";
98101
@@ -103,13 +106,17 @@
103 Q_FOREACH(QObject *handler, d->m_handlers) {106 Q_FOREACH(QObject *handler, d->m_handlers) {
104 const QMetaObject *metaObject = handler->metaObject();107 const QMetaObject *metaObject = handler->metaObject();
105 int index = metaObject->indexOfMethod(methodSignature);108 int index = metaObject->indexOfMethod(methodSignature);
106 if (index == -1) continue;109 if (index == -1) {
110 continue;
111 }
107112
108 QMetaMethod metaMethod = metaObject->method(index);113 QMetaMethod metaMethod = metaObject->method(index);
109 ok = metaMethod.invoke(handler,114 ok = metaMethod.invoke(handler,
110 Q_RETURN_ARG(QVariantMap, reply),115 Q_RETURN_ARG(QVariantMap, reply),
111 Q_ARG(QVariantMap, message));116 Q_ARG(QVariantMap, message));
112 if (ok) break;117 if (ok) {
118 break;
119 }
113 }120 }
114121
115 if (ok) {122 if (ok) {
116123
=== modified file 'messaging-host/webapps-handler.cpp'
--- messaging-host/webapps-handler.cpp 2014-06-23 06:49:03 +0000
+++ messaging-host/webapps-handler.cpp 2015-10-07 04:25:10 +0000
@@ -48,24 +48,30 @@
48 UnityWebappsApplicationStatus status,48 UnityWebappsApplicationStatus status,
49 gpointer user_data);49 gpointer user_data);
5050
51 mutable WebappsHandler *q_ptr;51 WebappsHandler *q_ptr;
52 UnityWebappsService *service;
52 UnityWebappsApplicationRepository *applicationRepository;53 UnityWebappsApplicationRepository *applicationRepository;
53};54};
5455
55} // namespace56} // namespace
5657
5758
58WebappsHandlerPrivate::WebappsHandlerPrivate(WebappsHandler *service):59WebappsHandlerPrivate::WebappsHandlerPrivate(WebappsHandler *handler)
59 q_ptr(service),60 : q_ptr(handler)
60 applicationRepository(0)61 , service(nullptr)
62 , applicationRepository(nullptr)
61{63{
64 service = unity_webapps_service_new();
62}65}
6366
64WebappsHandlerPrivate::~WebappsHandlerPrivate()67WebappsHandlerPrivate::~WebappsHandlerPrivate()
65{68{
66 if (applicationRepository != 0) {69 if (applicationRepository != nullptr) {
67 g_object_unref(G_OBJECT(applicationRepository));70 g_object_unref(G_OBJECT(applicationRepository));
68 }71 }
72 if (service != nullptr) {
73 g_object_unref(service);
74 }
69}75}
7076
71UnityWebappsApplicationRepository *WebappsHandlerPrivate::getRepository()77UnityWebappsApplicationRepository *WebappsHandlerPrivate::getRepository()
@@ -285,17 +291,6 @@
285 return reply;291 return reply;
286}292}
287293
288QVariantMap WebappsHandler::ping(const QVariantMap &message)
289{
290 Q_UNUSED(message);
291
292 QVariantMap reply;
293
294 reply.insert("pong", QLatin1String("alive"));
295
296 return reply;
297}
298
299/*294/*
300 \fn createApplicationDesktopName(QString, QString)295 \fn createApplicationDesktopName(QString, QString)
301296
@@ -321,4 +316,3 @@
321316
322 return QStringLiteral("application://%1.desktop").arg(basename);317 return QStringLiteral("application://%1.desktop").arg(basename);
323}318}
324
325319
=== modified file 'messaging-host/webapps-handler.h'
--- messaging-host/webapps-handler.h 2014-06-23 07:32:13 +0000
+++ messaging-host/webapps-handler.h 2015-10-07 04:25:10 +0000
@@ -38,7 +38,6 @@
38 QVariantMap url_loaded(const QVariantMap &message);38 QVariantMap url_loaded(const QVariantMap &message);
39 QVariantMap dont_ask(const QVariantMap &message);39 QVariantMap dont_ask(const QVariantMap &message);
40 QVariantMap install(const QVariantMap &message);40 QVariantMap install(const QVariantMap &message);
41 QVariantMap ping(const QVariantMap &message);
4241
43#if defined(UCX_UNDER_TEST)42#if defined(UCX_UNDER_TEST)
44public:43public:
4544
=== added file 'tests/CMakeLists.txt'
--- tests/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ tests/CMakeLists.txt 2015-10-07 04:25:10 +0000
@@ -0,0 +1,1 @@
1add_subdirectory(unit)
02
=== removed file 'tests/tests.pro'
--- tests/tests.pro 2014-05-19 14:04:19 +0000
+++ tests/tests.pro 1970-01-01 00:00:00 +0000
@@ -1,3 +0,0 @@
1TEMPLATE = subdirs
2SUBDIRS = \
3 unit
40
=== added file 'tests/unit/CMakeLists.txt'
--- tests/unit/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ tests/unit/CMakeLists.txt 2015-10-07 04:25:10 +0000
@@ -0,0 +1,1 @@
1add_subdirectory(messaging-host)
02
=== added file 'tests/unit/messaging-host/CMakeLists.txt'
--- tests/unit/messaging-host/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ tests/unit/messaging-host/CMakeLists.txt 2015-10-07 04:25:10 +0000
@@ -0,0 +1,5 @@
1add_subdirectory(connection)
2add_subdirectory(inactivity-timer)
3add_subdirectory(webapps-handler)
4add_subdirectory(click-handler)
5add_subdirectory(service)
06
=== added directory 'tests/unit/messaging-host/click-handler'
=== added file 'tests/unit/messaging-host/click-handler/CMakeLists.txt'
--- tests/unit/messaging-host/click-handler/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ tests/unit/messaging-host/click-handler/CMakeLists.txt 2015-10-07 04:25:10 +0000
@@ -0,0 +1,38 @@
1set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
2set(CMAKE_INCLUDE_CURRENT_DIR ON)
3set(CMAKE_AUTOMOC ON)
4
5find_package(PkgConfig)
6find_package(Qt5Core REQUIRED)
7find_package(Qt5Test REQUIRED)
8
9pkg_check_modules(GLIB glib-2.0 REQUIRED)
10pkg_check_modules(GOBJECT gobject-2.0 REQUIRED)
11pkg_check_modules(JSON_GLIB json-glib-1.0 REQUIRED)
12pkg_check_modules(CLICK click-0.4 REQUIRED)
13pkg_check_modules(UBUNTU_APP_LAUNCH ubuntu-app-launch-2 REQUIRED)
14
15
16set(TEST tst_ClickHandler)
17set(SOURCES
18 ${messaging-host_SOURCE_DIR}/click-handler.cpp
19 tst_click-handler.cpp
20)
21
22include_directories(
23 ${messaging-host_SOURCE_DIR}
24 ${GLIB_INCLUDE_DIRS}
25 ${JSON_GLIB_INCLUDE_DIRS}
26 ${UBUNTU_APP_LAUNCH_INCLUDE_DIRS}
27)
28
29add_executable(${TEST} ${SOURCES})
30
31target_link_libraries(${TEST}
32 Qt5::Core
33 Qt5::Test
34 ${GLIB_LIBRARIES}
35 ${JSON_GLIB_LIBRARIES}
36)
37
38add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
039
=== added file 'tests/unit/messaging-host/click-handler/tst_click-handler.cpp'
--- tests/unit/messaging-host/click-handler/tst_click-handler.cpp 1970-01-01 00:00:00 +0000
+++ tests/unit/messaging-host/click-handler/tst_click-handler.cpp 2015-10-07 04:25:10 +0000
@@ -0,0 +1,291 @@
1/*
2 * Copyright (C) 2015 Canonical Ltd.
3 *
4 * This file is part of unity-chromium-extension
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <click-0.4/click.h>
20#include <ubuntu-app-launch.h>
21
22#include "click-handler.h"
23
24#include <QDebug>
25#include <QSignalSpy>
26#include <QTest>
27
28
29// {{{ mock implementations
30ClickDB* click_db_new(void)
31{
32 return (ClickDB*)g_object_new(G_TYPE_OBJECT, 0);
33}
34
35void click_db_read(ClickDB* self, const gchar* db_dir, GError** error)
36{
37}
38
39JsonArray* click_db_get_manifests(ClickDB* self, gboolean all_versions, GError** error)
40{
41 const gchar* example_json =
42"["
43"{"
44" \"_directory\": \"/custom/click/.click/users/@all/com.ubuntu.developer.webapps.webapp-gmail\","
45" \"_removable\": 1,"
46" \"architecture\": \"all\","
47" \"description\": \"Gmail (webapp version)\","
48" \"framework\": \"ubuntu-sdk-14.10-dev2\","
49" \"hooks\": {"
50" \"webapp-gmail\": {"
51" \"account-application\": \"webapp-gmail.application\","
52" \"account-service\": \"webapp-gmail.service\","
53" \"apparmor\": \"webapp-gmail.json\","
54" \"desktop\": \"webapp-gmail.desktop\","
55" \"urls\": \"gmail.url-dispatcher\""
56" },"
57" \"webapp-gmail-helper\": {"
58" \"apparmor\": \"gmail-helper-apparmor.json\","
59" \"push-helper\": \"gmail-helper.json\""
60" }"
61" },"
62" \"installed-size\": \"22\","
63" \"maintainer\": \"Webapps Team <webapps@lists.launchpad.net>\","
64" \"name\": \"com.ubuntu.developer.webapps.webapp-gmail\","
65" \"title\": \"webapp-gmail\","
66" \"version\": \"1.0.25\""
67"},"
68"{"
69" \"_directory\": \"/custom/click/.click/users/@all/com.ubuntu.developer.webapps.webapp-facebook\","
70" \"_removable\": 1,"
71" \"architecture\": \"all\","
72" \"description\": \"Facebook (webapp version)\","
73" \"framework\": \"ubuntu-sdk-14.10\","
74" \"hooks\": {"
75" \"webapp-facebook\": {"
76" \"account-application\": \"webapp-facebook.application\","
77" \"account-service\": \"webapp-facebook.service\","
78" \"apparmor\": \"webapp-facebook.json\","
79" \"content-hub\": \"content-hub/webapp-facebook.json\","
80" \"desktop\": \"webapp-facebook.desktop\","
81" \"urls\": \"facebook.url-dispatcher\""
82" },"
83" \"webapp-facebook-helper\": {"
84" \"apparmor\": \"facebook-helper-apparmor.json\","
85" \"push-helper\": \"facebook-helper.json\""
86" }"
87" },"
88" \"installed-size\": \"887\","
89" \"maintainer\": \"Webapps Team <webapps@lists.launchpad.net>\","
90" \"name\": \"com.ubuntu.developer.webapps.webapp-facebook\","
91" \"title\": \"Facebook\","
92" \"version\": \"1.2\""
93"}"
94"]";
95
96 JsonParser* parser = json_parser_new();
97 if (!json_parser_load_from_data(parser, example_json, strlen(example_json), error)) {
98 qDebug() << "Error parsing URL dispatched JSON" << (*error)->message;
99 return nullptr;
100 }
101
102 JsonNode *root_node = json_parser_get_root(parser);
103 if (json_node_get_node_type(root_node) != JSON_NODE_ARRAY) {
104 return nullptr;
105 }
106
107 return json_node_get_array(root_node);
108}
109
110gboolean json_parser_load_from_file(JsonParser *parser, const gchar* filename, GError **error)
111{
112 const gchar* dispatcher_template =
113"["
114" {"
115" \"protocol\": \"http\","
116" \"domain-suffix\": \"%s.com\""
117" },"
118" {"
119" \"protocol\": \"https\","
120" \"domain-suffix\": \"%s.com\""
121" }"
122"]";
123
124 gchar *dispatcher_json = nullptr;
125 if (g_strrstr(filename, "gmail") != NULL) {
126 dispatcher_json = g_strdup_printf(dispatcher_template, "google");
127 } else if (g_strrstr(filename, "facebook") != NULL) {
128 dispatcher_json = g_strdup_printf(dispatcher_template, "facebook");
129 }
130
131 if (!json_parser_load_from_data(parser, dispatcher_json, strlen(dispatcher_json), error)) {
132 qDebug() << "Error parsing URL dispatched JSON" << (*error)->message;
133 g_free(dispatcher_json);
134 return false;
135 }
136
137 g_free(dispatcher_json);
138
139 return true;
140}
141
142gboolean ubuntu_app_launch_start_application(const gchar* appid, const gchar* const* uris)
143{
144 return true;
145}
146// }}}
147
148class ClickHandlerTest : public QObject
149{
150 Q_OBJECT
151
152public:
153 ClickHandlerTest();
154
155private Q_SLOTS:
156 void testClickAvailableReturnsMethodName();
157 void testClickAvailableUrlMustBeValid();
158 void testClickAvailableApps_data();
159 void testClickAvailableApps();
160 void testLaunchClickReturnsMethodName();
161 void testLaunchClickUrlMustBeValid();
162 void testLaunchClick_data();
163 void testLaunchClick();
164};
165
166ClickHandlerTest::ClickHandlerTest():
167 QObject(nullptr)
168{
169}
170
171void ClickHandlerTest::testClickAvailableReturnsMethodName()
172{
173 UnityWebapps::ClickHandler handler;
174
175 QVariantMap message;
176 message.insert("method", "click_available");
177
178 QVariantMap reply = handler.click_available(message);
179
180 QVERIFY(!reply.empty());
181 QCOMPARE(reply.value("method").toString(), QStringLiteral("click_available"));
182}
183
184void ClickHandlerTest::testClickAvailableUrlMustBeValid()
185{
186 UnityWebapps::ClickHandler handler;
187
188 QVariantMap message;
189 message.insert("method", "click_available");
190
191 QVariantMap reply = handler.click_available(message);
192
193 QVERIFY(!reply.empty());
194 QCOMPARE(reply.value("error").toString(), QStringLiteral("malformed request"));
195}
196
197void ClickHandlerTest::testClickAvailableApps_data()
198{
199 QTest::addColumn<QString>("url");
200 QTest::addColumn<bool>("available");
201 QTest::addColumn<QString>("appName");
202 QTest::addColumn<QString>("appDomain");
203 QTest::addColumn<QString>("appVersion");
204
205 QTest::newRow("available") << "https://mail.google.com/" << true << "webapp-gmail" << "mail.google.com" << "1.0.25";
206 QTest::newRow("available") << "https://m.facebook.com/" << true << "Facebook" << "m.facebook.com" << "1.2";
207 QTest::newRow("not_available") << "http://www.example.com/" << false << "None" << "None" << "0.0.0";
208}
209
210void ClickHandlerTest::testClickAvailableApps()
211{
212 QFETCH(QString, url);
213 QFETCH(bool, available);
214 QFETCH(QString, appName);
215 QFETCH(QString, appDomain);
216 QFETCH(QString, appVersion);
217
218 UnityWebapps::ClickHandler handler;
219
220 QVariantMap message;
221 message.insert("method", "click_available");
222 message.insert("url", url);
223
224 QVariantMap reply = handler.click_available(message);
225
226 QVERIFY(!reply.empty());
227 QCOMPARE(reply.value("available").toBool(), available);
228 if (available) {
229 QCOMPARE(appName, reply.value("appName").toString());
230 // QCOMPARE(appDomain, reply.value("appDomain").toString()); // Not currently available
231 QCOMPARE(appVersion, reply.value("appVersion").toString());
232 }
233}
234
235void ClickHandlerTest::testLaunchClickReturnsMethodName()
236{
237 UnityWebapps::ClickHandler handler;
238
239 QVariantMap message;
240 message.insert("method", "launch_click");
241
242 QVariantMap reply = handler.launch_click(message);
243
244 QVERIFY(!reply.empty());
245 QCOMPARE(reply.value("method").toString(), QStringLiteral("launch_click"));
246}
247
248void ClickHandlerTest::testLaunchClickUrlMustBeValid()
249{
250 UnityWebapps::ClickHandler handler;
251
252 QVariantMap message;
253 message.insert("method", "launch_click");
254
255 QVariantMap reply = handler.click_available(message);
256
257 QVERIFY(!reply.empty());
258 QCOMPARE(reply.value("error").toString(), QStringLiteral("malformed request"));
259}
260
261void ClickHandlerTest::testLaunchClick_data()
262{
263 QTest::addColumn<QString>("url");
264 QTest::addColumn<bool>("success");
265
266 QTest::newRow("launchable") << "https://mail.google.com/" << true;
267 QTest::newRow("launchable") << "https://m.facebook.com/" << true;
268 QTest::newRow("not_launchable") << "http://www.example.com/" << false;
269}
270
271void ClickHandlerTest::testLaunchClick()
272{
273 QFETCH(QString, url);
274 QFETCH(bool, success);
275
276 UnityWebapps::ClickHandler handler;
277
278 QVariantMap message;
279 message.insert("method", "launch_click");
280 message.insert("url", url);
281
282 QVariantMap reply = handler.launch_click(message);
283
284 QVERIFY(!reply.empty());
285 QCOMPARE(reply.value("launched").toBool(), success);
286}
287
288
289QTEST_MAIN(ClickHandlerTest);
290
291#include "tst_click-handler.moc"
0292
=== added directory 'tests/unit/messaging-host/connection'
=== removed file 'tests/unit/messaging-host/connection-host.cpp'
--- tests/unit/messaging-host/connection-host.cpp 2014-05-20 12:21:50 +0000
+++ tests/unit/messaging-host/connection-host.cpp 1970-01-01 00:00:00 +0000
@@ -1,71 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical Ltd.
3 *
4 * This file is part of unity-chromium-extension
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <QCoreApplication>
20#include <QDebug>
21#include "connection.h"
22
23class Handler: public QObject
24{
25 Q_OBJECT
26
27public:
28 Handler(): QObject() {}
29
30 bool openConnection();
31
32public Q_SLOTS:
33 void onMessageReceived(const QVariantMap &message);
34
35private:
36 UnityWebapps::Connection m_connection;
37};
38
39bool Handler::openConnection()
40{
41 QObject::connect(&m_connection,
42 SIGNAL(messageReceived(const QVariantMap &)),
43 this,
44 SLOT(onMessageReceived(const QVariantMap &)));
45 return m_connection.open();
46}
47
48void Handler::onMessageReceived(const QVariantMap &message)
49{
50 // Generate a predictable reply
51 QVariantMap reply;
52 reply.insert("count", message.count());
53 QStringList keys = message.uniqueKeys();
54 reply.insert("keys", keys);
55 m_connection.postMessage(reply);
56}
57
58int main(int argc, char **argv)
59{
60 QCoreApplication app(argc, argv);
61 Handler handler;
62
63 if (!handler.openConnection()) {
64 qCritical() << "Connection::open() failed!";
65 return EXIT_FAILURE;
66 }
67
68 return app.exec();
69}
70
71#include "connection-host.moc"
720
=== added file 'tests/unit/messaging-host/connection/CMakeLists.txt'
--- tests/unit/messaging-host/connection/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ tests/unit/messaging-host/connection/CMakeLists.txt 2015-10-07 04:25:10 +0000
@@ -0,0 +1,40 @@
1set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
2set(CMAKE_INCLUDE_CURRENT_DIR ON)
3set(CMAKE_AUTOMOC ON)
4
5find_package(Qt5Core REQUIRED)
6find_package(Qt5Test REQUIRED)
7
8# Test server process
9add_executable(
10 connection-host
11
12 ${messaging-host_SOURCE_DIR}/connection.cpp
13 connection-host.cpp
14)
15
16target_link_libraries(
17 connection-host
18
19 Qt5::Core
20)
21
22# Test proper
23set(TEST tst_Connection)
24set(SOURCES
25 tst_connection.cpp
26)
27
28add_executable(${TEST} ${SOURCES})
29add_dependencies(${TEST} connection-host)
30
31include_directories(${messaging-host_SOURCE_DIR})
32
33target_link_libraries(
34 ${TEST}
35
36 Qt5::Core
37 Qt5::Test
38)
39
40add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
041
=== added file 'tests/unit/messaging-host/connection/connection-host.cpp'
--- tests/unit/messaging-host/connection/connection-host.cpp 1970-01-01 00:00:00 +0000
+++ tests/unit/messaging-host/connection/connection-host.cpp 2015-10-07 04:25:10 +0000
@@ -0,0 +1,71 @@
1/*
2 * Copyright (C) 2014 Canonical Ltd.
3 *
4 * This file is part of unity-chromium-extension
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <QCoreApplication>
20#include <QDebug>
21#include "connection.h"
22
23class Handler: public QObject
24{
25 Q_OBJECT
26
27public:
28 Handler(): QObject() {}
29
30 bool openConnection();
31
32public Q_SLOTS:
33 void onMessageReceived(const QVariantMap &message);
34
35private:
36 UnityWebapps::Connection m_connection;
37};
38
39bool Handler::openConnection()
40{
41 QObject::connect(&m_connection,
42 SIGNAL(messageReceived(const QVariantMap &)),
43 this,
44 SLOT(onMessageReceived(const QVariantMap &)));
45 return m_connection.open();
46}
47
48void Handler::onMessageReceived(const QVariantMap &message)
49{
50 // Generate a predictable reply
51 QVariantMap reply;
52 reply.insert("count", message.count());
53 QStringList keys = message.uniqueKeys();
54 reply.insert("keys", keys);
55 m_connection.postMessage(reply);
56}
57
58int main(int argc, char **argv)
59{
60 QCoreApplication app(argc, argv);
61 Handler handler;
62
63 if (!handler.openConnection()) {
64 qCritical() << "Connection::open() failed!";
65 return EXIT_FAILURE;
66 }
67
68 return app.exec();
69}
70
71#include "connection-host.moc"
072
=== added file 'tests/unit/messaging-host/connection/tst_connection.cpp'
--- tests/unit/messaging-host/connection/tst_connection.cpp 1970-01-01 00:00:00 +0000
+++ tests/unit/messaging-host/connection/tst_connection.cpp 2015-10-07 04:25:10 +0000
@@ -0,0 +1,112 @@
1/*
2 * Copyright (C) 2014 Canonical Ltd.
3 *
4 * This file is part of unity-chromium-extension
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <QByteArray>
20#include <QDebug>
21#include <QJsonDocument>
22#include <QProcess>
23#include <QSet>
24#include <QSignalSpy>
25#include <QTest>
26
27class ConnectionTest: public QObject
28{
29 Q_OBJECT
30
31public:
32 ConnectionTest();
33
34 void postMessage(const QByteArray &message);
35 QByteArray readReply();
36 QVariantMap jsonToMap(const QByteArray &json);
37
38private Q_SLOTS:
39 void init();
40 void cleanup();
41 void testMessaging();
42
43private:
44 QProcess m_process;
45};
46
47ConnectionTest::ConnectionTest():
48 QObject(0)
49{
50 m_process.setProgram("./connection-host");
51 m_process.setProcessChannelMode(QProcess::ForwardedErrorChannel);
52 m_process.setReadChannel(QProcess::StandardOutput);
53}
54
55void ConnectionTest::postMessage(const QByteArray &message)
56{
57 quint32 length = message.length();
58
59 m_process.write((char *)&length, sizeof(length));
60 m_process.write(message);
61}
62
63QByteArray ConnectionTest::readReply()
64{
65 quint32 length;
66 m_process.waitForReadyRead();
67 m_process.read((char *)&length, sizeof(length));
68 return m_process.read(length);
69}
70
71QVariantMap ConnectionTest::jsonToMap(const QByteArray &json)
72{
73 QJsonDocument doc = QJsonDocument::fromJson(json);
74 return doc.toVariant().toMap();
75}
76
77void ConnectionTest::init()
78{
79 m_process.start();
80 m_process.waitForStarted();
81}
82
83void ConnectionTest::cleanup()
84{
85 m_process.kill();
86 m_process.waitForFinished();
87}
88
89void ConnectionTest::testMessaging()
90{
91 postMessage("{\"msg\":\"hi\"}");
92 QVariantMap reply = jsonToMap(readReply());
93 QCOMPARE(reply.count(), 2);
94 QCOMPARE(reply.value("count").toInt(), 1);
95 QCOMPARE(reply.value("keys").toStringList(), QStringList() << "msg");
96
97 postMessage("{\"list\": [\"one\", \"two\"],"
98 "\"name\": \"Tom\","
99 "\"number\": 23}");
100 reply = jsonToMap(readReply());
101 QCOMPARE(reply.count(), 2);
102 QCOMPARE(reply.value("count").toInt(), 3);
103 QSet<QString> expectedKeys;
104 expectedKeys << "list" << "name" << "number";
105 QCOMPARE(reply.value("keys").toStringList().toSet(), expectedKeys);
106
107 m_process.terminate();
108}
109
110QTEST_MAIN(ConnectionTest);
111
112#include "tst_connection.moc"
0113
=== added directory 'tests/unit/messaging-host/inactivity-timer'
=== added file 'tests/unit/messaging-host/inactivity-timer/CMakeLists.txt'
--- tests/unit/messaging-host/inactivity-timer/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ tests/unit/messaging-host/inactivity-timer/CMakeLists.txt 2015-10-07 04:25:10 +0000
@@ -0,0 +1,23 @@
1set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
2set(CMAKE_INCLUDE_CURRENT_DIR ON)
3set(CMAKE_AUTOMOC ON)
4
5find_package(Qt5Core REQUIRED)
6find_package(Qt5Test REQUIRED)
7
8set(TEST tst_InactivityTimer)
9set(SOURCES
10 ${messaging-host_SOURCE_DIR}/inactivity-timer.cpp
11 tst_inactivity_timer.cpp
12)
13
14add_executable(${TEST} ${SOURCES})
15
16include_directories(${messaging-host_SOURCE_DIR})
17
18target_link_libraries(${TEST}
19 Qt5::Core
20 Qt5::Test
21)
22
23add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
024
=== added file 'tests/unit/messaging-host/inactivity-timer/tst_inactivity_timer.cpp'
--- tests/unit/messaging-host/inactivity-timer/tst_inactivity_timer.cpp 1970-01-01 00:00:00 +0000
+++ tests/unit/messaging-host/inactivity-timer/tst_inactivity_timer.cpp 2015-10-07 04:25:10 +0000
@@ -0,0 +1,125 @@
1/*
2 * Copyright (C) 2014 Canonical Ltd.
3 *
4 * This file is part of unity-chromium-extension
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "inactivity-timer.h"
20
21#include <QDebug>
22#include <QSignalSpy>
23#include <QTest>
24
25using namespace UnityWebapps;
26
27class Service: public QObject
28{
29 Q_OBJECT
30 Q_PROPERTY(bool isIdle READ isIdle NOTIFY isIdleChanged)
31
32public:
33 Service(): QObject(), m_isIdle(true) {}
34
35 bool isIdle() const { return m_isIdle; }
36
37 void setIdle(bool idle) {
38 if (idle == m_isIdle) return;
39 m_isIdle = idle;
40 Q_EMIT isIdleChanged();
41 }
42
43Q_SIGNALS:
44 void isIdleChanged();
45
46private:
47 bool m_isIdle;
48};
49
50class InactivityTimerTest: public QObject
51{
52 Q_OBJECT
53
54public:
55 InactivityTimerTest();
56
57private Q_SLOTS:
58 void testAlwaysIdle();
59 void testBecomeIdle();
60 void testManyServices();
61};
62
63InactivityTimerTest::InactivityTimerTest():
64 QObject(0)
65{
66}
67
68void InactivityTimerTest::testAlwaysIdle()
69{
70 InactivityTimer timer(10);
71 QSignalSpy timeout(&timer, SIGNAL(timeout()));
72
73 Service service;
74 timer.watchObject(&service);
75
76 QVERIFY(timeout.wait(100));
77}
78
79void InactivityTimerTest::testBecomeIdle()
80{
81 InactivityTimer timer(10);
82 QSignalSpy timeout(&timer, SIGNAL(timeout()));
83
84 Service service;
85 service.setIdle(false);
86 timer.watchObject(&service);
87
88 /* No signal should be emitted, as the service is not idle */
89 QVERIFY(!timeout.wait(100));
90
91 service.setIdle(true);
92 QVERIFY(timeout.wait(100));
93}
94
95void InactivityTimerTest::testManyServices()
96{
97 InactivityTimer timer(50);
98 QSignalSpy timeout(&timer, SIGNAL(timeout()));
99
100 Service service1;
101 timer.watchObject(&service1);
102
103 Service service2;
104 timer.watchObject(&service2);
105
106 Service service3;
107 service3.setIdle(false);
108 timer.watchObject(&service3);
109
110 /* No signal should be emitted, as service3 is not idle */
111 QVERIFY(!timeout.wait(100));
112
113 /* Now set it is as idle, but soon afterwards set service1 as busy */
114 service3.setIdle(true);
115 QTest::qWait(10);
116 service1.setIdle(false);
117 QVERIFY(!timeout.wait(100));
118
119 service1.setIdle(true);
120 QVERIFY(timeout.wait(100));
121}
122
123QTEST_MAIN(InactivityTimerTest);
124
125#include "tst_inactivity_timer.moc"
0126
=== removed file 'tests/unit/messaging-host/messaging-host.pri'
--- tests/unit/messaging-host/messaging-host.pri 2014-05-21 08:18:12 +0000
+++ tests/unit/messaging-host/messaging-host.pri 1970-01-01 00:00:00 +0000
@@ -1,9 +0,0 @@
1include(../../../common-project-config.pri)
2
3CONFIG += \
4 debug
5
6SRC_DIR = $${TOP_SRC_DIR}/messaging-host
7
8INCLUDEPATH += \
9 $${SRC_DIR}
100
=== removed file 'tests/unit/messaging-host/messaging-host.pro'
--- tests/unit/messaging-host/messaging-host.pro 2014-05-23 10:16:49 +0000
+++ tests/unit/messaging-host/messaging-host.pro 1970-01-01 00:00:00 +0000
@@ -1,12 +0,0 @@
1TEMPLATE = subdirs
2SUBDIRS = \
3 tst_connection \
4 tst_connection_host \
5 tst_inactivity_timer.pro \
6 tst_service.pro \
7 tst_webapps-handler.pro \
8
9tst_connection.file = tst_connection.pro
10tst_connection_host.file = tst_connection_host.pro
11
12tst_connection.depends = tst_connection_host
130
=== added directory 'tests/unit/messaging-host/service'
=== added file 'tests/unit/messaging-host/service/CMakeLists.txt'
--- tests/unit/messaging-host/service/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ tests/unit/messaging-host/service/CMakeLists.txt 2015-10-07 04:25:10 +0000
@@ -0,0 +1,23 @@
1set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
2set(CMAKE_INCLUDE_CURRENT_DIR ON)
3set(CMAKE_AUTOMOC ON)
4
5find_package(Qt5Core REQUIRED)
6find_package(Qt5Test REQUIRED)
7
8set(TEST tst_Service)
9set(SOURCES
10 ${messaging-host_SOURCE_DIR}/service.cpp
11 tst_service.cpp
12)
13
14add_executable(${TEST} ${SOURCES})
15
16include_directories(${messaging-host_SOURCE_DIR})
17
18target_link_libraries(${TEST}
19 Qt5::Core
20 Qt5::Test
21)
22
23add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
024
=== added file 'tests/unit/messaging-host/service/tst_service.cpp'
--- tests/unit/messaging-host/service/tst_service.cpp 1970-01-01 00:00:00 +0000
+++ tests/unit/messaging-host/service/tst_service.cpp 2015-10-07 04:25:10 +0000
@@ -0,0 +1,189 @@
1/*
2 * Copyright (C) 2014 Canonical Ltd.
3 *
4 * This file is part of unity-chromium-extension
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "service.h"
20
21#include <QDebug>
22#include <QSignalSpy>
23#include <QTest>
24
25class Handler1: public QObject
26{
27 Q_OBJECT
28
29public:
30 Handler1() {}
31
32public Q_SLOTS:
33 QVariantMap sayHello(const QVariantMap &params);
34 QVariantMap countArguments(const QVariantMap &params);
35};
36
37QVariantMap Handler1::sayHello(const QVariantMap &params)
38{
39 QVariantMap reply;
40 reply.insert("greeting",
41 QString("Hello %1").arg(params.value("name").toString()));
42 return reply;
43}
44
45QVariantMap Handler1::countArguments(const QVariantMap &params)
46{
47 QVariantMap reply;
48 // We subtract one, because that's the "method" field
49 reply.insert("count", params.count() - 1);
50 return reply;
51}
52
53class Handler2: public QObject
54{
55 Q_OBJECT
56
57public:
58 Handler2() {}
59
60public Q_SLOTS:
61 QVariantMap listArguments(const QVariantMap &params);
62};
63
64QVariantMap Handler2::listArguments(const QVariantMap &params)
65{
66 QVariantMap reply;
67 QStringList arguments = params.keys();
68 arguments.removeAll("method");
69 reply.insert("arguments", arguments);
70 return reply;
71}
72
73class ServiceTest: public QObject
74{
75 Q_OBJECT
76
77public:
78 ServiceTest();
79
80private Q_SLOTS:
81 void testNoHandlers();
82 void testNonExisting();
83 void testHandling();
84};
85
86ServiceTest::ServiceTest():
87 QObject(0)
88{
89}
90
91void ServiceTest::testNoHandlers()
92{
93 UnityWebapps::Service service;
94 QSignalSpy messageHandled(&service, SIGNAL(messageHandled(const QVariantMap &)));
95
96 QVariantMap message;
97 message.insert("method", QString("sayHello"));
98 message.insert("name", QString("Tom"));
99 service.handleMessage(message);
100
101 QCOMPARE(messageHandled.count(), 0);
102 QVERIFY(service.isIdle());
103}
104
105void ServiceTest::testNonExisting()
106{
107 UnityWebapps::Service service;
108 QSignalSpy messageHandled(&service, SIGNAL(messageHandled(const QVariantMap &)));
109
110 Handler1 handler1;
111 service.addHandler(&handler1);
112
113 QVariantMap message;
114 message.insert("method", QString("nonExistingMethod"));
115 service.handleMessage(message);
116
117 QCOMPARE(messageHandled.count(), 0);
118 QVERIFY(service.isIdle());
119
120 // Add the second service (it still should fail)
121 Handler2 handler2;
122 service.addHandler(&handler2);
123
124 service.handleMessage(message);
125
126 QCOMPARE(messageHandled.count(), 0);
127 QVERIFY(service.isIdle());
128}
129
130void ServiceTest::testHandling()
131{
132 UnityWebapps::Service service;
133 QSignalSpy messageHandled(&service, SIGNAL(messageHandled(const QVariantMap &)));
134 QSignalSpy isIdleChanged(&service, SIGNAL(isIdleChanged()));
135 QVERIFY(service.isIdle());
136
137 Handler1 handler1;
138 service.addHandler(&handler1);
139
140 QVariantMap message;
141 message.insert("method", QString("sayHello"));
142 message.insert("name", QString("Tom"));
143 service.handleMessage(message);
144
145 QCOMPARE(messageHandled.count(), 1);
146 QVariantMap reply = messageHandled.at(0).at(0).toMap();
147 QCOMPARE(reply.value("greeting").toString(), QString("Hello Tom"));
148 messageHandled.clear();
149 QCOMPARE(isIdleChanged.count(), 2);
150 isIdleChanged.clear();
151 QVERIFY(service.isIdle());
152
153 // Make sure it continues to work when we add a second handler
154 Handler2 handler2;
155 service.addHandler(&handler2);
156 service.handleMessage(message);
157
158 QCOMPARE(messageHandled.count(), 1);
159 reply = messageHandled.at(0).at(0).toMap();
160 QCOMPARE(reply.value("greeting").toString(), QString("Hello Tom"));
161 messageHandled.clear();
162 QCOMPARE(isIdleChanged.count(), 2);
163 isIdleChanged.clear();
164 QVERIFY(service.isIdle());
165
166 // Test a method from the second handler
167 message.clear();
168 message.insert("method", QString("listArguments"));
169 message.insert("number", 1);
170 message.insert("string", QString("Hello"));
171 message.insert("boolean", false);
172 service.handleMessage(message);
173
174 QCOMPARE(messageHandled.count(), 1);
175 reply = messageHandled.at(0).at(0).toMap();
176 QVERIFY(reply.contains("arguments"));
177 QStringList expectedArguments;
178 expectedArguments << "number" << "string" << "boolean";
179 QCOMPARE(reply.value("arguments").toStringList().toSet(),
180 expectedArguments.toSet());
181 messageHandled.clear();
182 QCOMPARE(isIdleChanged.count(), 2);
183 isIdleChanged.clear();
184 QVERIFY(service.isIdle());
185}
186
187QTEST_MAIN(ServiceTest);
188
189#include "tst_service.moc"
0190
=== removed file 'tests/unit/messaging-host/tst_connection.cpp'
--- tests/unit/messaging-host/tst_connection.cpp 2014-05-20 12:21:50 +0000
+++ tests/unit/messaging-host/tst_connection.cpp 1970-01-01 00:00:00 +0000
@@ -1,112 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical Ltd.
3 *
4 * This file is part of unity-chromium-extension
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include <QByteArray>
20#include <QDebug>
21#include <QJsonDocument>
22#include <QProcess>
23#include <QSet>
24#include <QSignalSpy>
25#include <QTest>
26
27class ConnectionTest: public QObject
28{
29 Q_OBJECT
30
31public:
32 ConnectionTest();
33
34 void postMessage(const QByteArray &message);
35 QByteArray readReply();
36 QVariantMap jsonToMap(const QByteArray &json);
37
38private Q_SLOTS:
39 void init();
40 void cleanup();
41 void testMessaging();
42
43private:
44 QProcess m_process;
45};
46
47ConnectionTest::ConnectionTest():
48 QObject(0)
49{
50 m_process.setProgram("./connection-host");
51 m_process.setProcessChannelMode(QProcess::ForwardedErrorChannel);
52 m_process.setReadChannel(QProcess::StandardOutput);
53}
54
55void ConnectionTest::postMessage(const QByteArray &message)
56{
57 quint32 length = message.length();
58
59 m_process.write((char *)&length, sizeof(length));
60 m_process.write(message);
61}
62
63QByteArray ConnectionTest::readReply()
64{
65 quint32 length;
66 m_process.waitForReadyRead();
67 m_process.read((char *)&length, sizeof(length));
68 return m_process.read(length);
69}
70
71QVariantMap ConnectionTest::jsonToMap(const QByteArray &json)
72{
73 QJsonDocument doc = QJsonDocument::fromJson(json);
74 return doc.toVariant().toMap();
75}
76
77void ConnectionTest::init()
78{
79 m_process.start();
80 m_process.waitForStarted();
81}
82
83void ConnectionTest::cleanup()
84{
85 m_process.kill();
86 m_process.waitForFinished();
87}
88
89void ConnectionTest::testMessaging()
90{
91 postMessage("{\"msg\":\"hi\"}");
92 QVariantMap reply = jsonToMap(readReply());
93 QCOMPARE(reply.count(), 2);
94 QCOMPARE(reply.value("count").toInt(), 1);
95 QCOMPARE(reply.value("keys").toStringList(), QStringList() << "msg");
96
97 postMessage("{\"list\": [\"one\", \"two\"],"
98 "\"name\": \"Tom\","
99 "\"number\": 23}");
100 reply = jsonToMap(readReply());
101 QCOMPARE(reply.count(), 2);
102 QCOMPARE(reply.value("count").toInt(), 3);
103 QSet<QString> expectedKeys;
104 expectedKeys << "list" << "name" << "number";
105 QCOMPARE(reply.value("keys").toStringList().toSet(), expectedKeys);
106
107 m_process.terminate();
108}
109
110QTEST_MAIN(ConnectionTest);
111
112#include "tst_connection.moc"
1130
=== removed file 'tests/unit/messaging-host/tst_connection.pro'
--- tests/unit/messaging-host/tst_connection.pro 2014-05-21 08:18:12 +0000
+++ tests/unit/messaging-host/tst_connection.pro 1970-01-01 00:00:00 +0000
@@ -1,14 +0,0 @@
1include(messaging-host.pri)
2
3TARGET = tst_connection
4
5QT += \
6 core \
7 testlib
8
9SOURCES += \
10 tst_connection.cpp
11
12check.commands = "xvfb-run -s '-screen 0 640x480x24' -a ./$${TARGET}"
13check.depends = $${TARGET}
14QMAKE_EXTRA_TARGETS += check
150
=== removed file 'tests/unit/messaging-host/tst_connection_host.pro'
--- tests/unit/messaging-host/tst_connection_host.pro 2014-05-21 08:18:12 +0000
+++ tests/unit/messaging-host/tst_connection_host.pro 1970-01-01 00:00:00 +0000
@@ -1,14 +0,0 @@
1include(messaging-host.pri)
2
3TEMPLATE = app
4TARGET = connection-host
5
6QT += \
7 core
8
9SOURCES = \
10 $${SRC_DIR}/connection.cpp \
11 connection-host.cpp
12
13HEADERS = \
14 $${SRC_DIR}/connection.h \
150
=== removed file 'tests/unit/messaging-host/tst_inactivity_timer.cpp'
--- tests/unit/messaging-host/tst_inactivity_timer.cpp 2014-05-21 08:18:12 +0000
+++ tests/unit/messaging-host/tst_inactivity_timer.cpp 1970-01-01 00:00:00 +0000
@@ -1,125 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical Ltd.
3 *
4 * This file is part of unity-chromium-extension
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "inactivity-timer.h"
20
21#include <QDebug>
22#include <QSignalSpy>
23#include <QTest>
24
25using namespace UnityWebapps;
26
27class Service: public QObject
28{
29 Q_OBJECT
30 Q_PROPERTY(bool isIdle READ isIdle NOTIFY isIdleChanged)
31
32public:
33 Service(): QObject(), m_isIdle(true) {}
34
35 bool isIdle() const { return m_isIdle; }
36
37 void setIdle(bool idle) {
38 if (idle == m_isIdle) return;
39 m_isIdle = idle;
40 Q_EMIT isIdleChanged();
41 }
42
43Q_SIGNALS:
44 void isIdleChanged();
45
46private:
47 bool m_isIdle;
48};
49
50class InactivityTimerTest: public QObject
51{
52 Q_OBJECT
53
54public:
55 InactivityTimerTest();
56
57private Q_SLOTS:
58 void testAlwaysIdle();
59 void testBecomeIdle();
60 void testManyServices();
61};
62
63InactivityTimerTest::InactivityTimerTest():
64 QObject(0)
65{
66}
67
68void InactivityTimerTest::testAlwaysIdle()
69{
70 InactivityTimer timer(10);
71 QSignalSpy timeout(&timer, SIGNAL(timeout()));
72
73 Service service;
74 timer.watchObject(&service);
75
76 QVERIFY(timeout.wait(100));
77}
78
79void InactivityTimerTest::testBecomeIdle()
80{
81 InactivityTimer timer(10);
82 QSignalSpy timeout(&timer, SIGNAL(timeout()));
83
84 Service service;
85 service.setIdle(false);
86 timer.watchObject(&service);
87
88 /* No signal should be emitted, as the service is not idle */
89 QVERIFY(!timeout.wait(100));
90
91 service.setIdle(true);
92 QVERIFY(timeout.wait(100));
93}
94
95void InactivityTimerTest::testManyServices()
96{
97 InactivityTimer timer(50);
98 QSignalSpy timeout(&timer, SIGNAL(timeout()));
99
100 Service service1;
101 timer.watchObject(&service1);
102
103 Service service2;
104 timer.watchObject(&service2);
105
106 Service service3;
107 service3.setIdle(false);
108 timer.watchObject(&service3);
109
110 /* No signal should be emitted, as service3 is not idle */
111 QVERIFY(!timeout.wait(100));
112
113 /* Now set it is as idle, but soon afterwards set service1 as busy */
114 service3.setIdle(true);
115 QTest::qWait(10);
116 service1.setIdle(false);
117 QVERIFY(!timeout.wait(100));
118
119 service1.setIdle(true);
120 QVERIFY(timeout.wait(100));
121}
122
123QTEST_MAIN(InactivityTimerTest);
124
125#include "tst_inactivity_timer.moc"
1260
=== removed file 'tests/unit/messaging-host/tst_inactivity_timer.pro'
--- tests/unit/messaging-host/tst_inactivity_timer.pro 2014-05-21 08:18:12 +0000
+++ tests/unit/messaging-host/tst_inactivity_timer.pro 1970-01-01 00:00:00 +0000
@@ -1,18 +0,0 @@
1include(messaging-host.pri)
2
3TARGET = tst_inactivity_timer
4
5QT += \
6 core \
7 testlib
8
9SOURCES += \
10 $${SRC_DIR}/inactivity-timer.cpp \
11 tst_inactivity_timer.cpp
12
13HEADERS += \
14 $${SRC_DIR}/inactivity-timer.h
15
16check.commands = "xvfb-run -s '-screen 0 640x480x24' -a ./$${TARGET}"
17check.depends = $${TARGET}
18QMAKE_EXTRA_TARGETS += check
190
=== removed file 'tests/unit/messaging-host/tst_service.cpp'
--- tests/unit/messaging-host/tst_service.cpp 2014-05-21 08:18:12 +0000
+++ tests/unit/messaging-host/tst_service.cpp 1970-01-01 00:00:00 +0000
@@ -1,189 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical Ltd.
3 *
4 * This file is part of unity-chromium-extension
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "service.h"
20
21#include <QDebug>
22#include <QSignalSpy>
23#include <QTest>
24
25class Handler1: public QObject
26{
27 Q_OBJECT
28
29public:
30 Handler1() {}
31
32public Q_SLOTS:
33 QVariantMap sayHello(const QVariantMap &params);
34 QVariantMap countArguments(const QVariantMap &params);
35};
36
37QVariantMap Handler1::sayHello(const QVariantMap &params)
38{
39 QVariantMap reply;
40 reply.insert("greeting",
41 QString("Hello %1").arg(params.value("name").toString()));
42 return reply;
43}
44
45QVariantMap Handler1::countArguments(const QVariantMap &params)
46{
47 QVariantMap reply;
48 // We subtract one, because that's the "method" field
49 reply.insert("count", params.count() - 1);
50 return reply;
51}
52
53class Handler2: public QObject
54{
55 Q_OBJECT
56
57public:
58 Handler2() {}
59
60public Q_SLOTS:
61 QVariantMap listArguments(const QVariantMap &params);
62};
63
64QVariantMap Handler2::listArguments(const QVariantMap &params)
65{
66 QVariantMap reply;
67 QStringList arguments = params.keys();
68 arguments.removeAll("method");
69 reply.insert("arguments", arguments);
70 return reply;
71}
72
73class ServiceTest: public QObject
74{
75 Q_OBJECT
76
77public:
78 ServiceTest();
79
80private Q_SLOTS:
81 void testNoHandlers();
82 void testNonExisting();
83 void testHandling();
84};
85
86ServiceTest::ServiceTest():
87 QObject(0)
88{
89}
90
91void ServiceTest::testNoHandlers()
92{
93 UnityWebapps::Service service;
94 QSignalSpy messageHandled(&service, SIGNAL(messageHandled(const QVariantMap &)));
95
96 QVariantMap message;
97 message.insert("method", QString("sayHello"));
98 message.insert("name", QString("Tom"));
99 service.handleMessage(message);
100
101 QCOMPARE(messageHandled.count(), 0);
102 QVERIFY(service.isIdle());
103}
104
105void ServiceTest::testNonExisting()
106{
107 UnityWebapps::Service service;
108 QSignalSpy messageHandled(&service, SIGNAL(messageHandled(const QVariantMap &)));
109
110 Handler1 handler1;
111 service.addHandler(&handler1);
112
113 QVariantMap message;
114 message.insert("method", QString("nonExistingMethod"));
115 service.handleMessage(message);
116
117 QCOMPARE(messageHandled.count(), 0);
118 QVERIFY(service.isIdle());
119
120 // Add the second service (it still should fail)
121 Handler2 handler2;
122 service.addHandler(&handler2);
123
124 service.handleMessage(message);
125
126 QCOMPARE(messageHandled.count(), 0);
127 QVERIFY(service.isIdle());
128}
129
130void ServiceTest::testHandling()
131{
132 UnityWebapps::Service service;
133 QSignalSpy messageHandled(&service, SIGNAL(messageHandled(const QVariantMap &)));
134 QSignalSpy isIdleChanged(&service, SIGNAL(isIdleChanged()));
135 QVERIFY(service.isIdle());
136
137 Handler1 handler1;
138 service.addHandler(&handler1);
139
140 QVariantMap message;
141 message.insert("method", QString("sayHello"));
142 message.insert("name", QString("Tom"));
143 service.handleMessage(message);
144
145 QCOMPARE(messageHandled.count(), 1);
146 QVariantMap reply = messageHandled.at(0).at(0).toMap();
147 QCOMPARE(reply.value("greeting").toString(), QString("Hello Tom"));
148 messageHandled.clear();
149 QCOMPARE(isIdleChanged.count(), 2);
150 isIdleChanged.clear();
151 QVERIFY(service.isIdle());
152
153 // Make sure it continues to work when we add a second handler
154 Handler2 handler2;
155 service.addHandler(&handler2);
156 service.handleMessage(message);
157
158 QCOMPARE(messageHandled.count(), 1);
159 reply = messageHandled.at(0).at(0).toMap();
160 QCOMPARE(reply.value("greeting").toString(), QString("Hello Tom"));
161 messageHandled.clear();
162 QCOMPARE(isIdleChanged.count(), 2);
163 isIdleChanged.clear();
164 QVERIFY(service.isIdle());
165
166 // Test a method from the second handler
167 message.clear();
168 message.insert("method", QString("listArguments"));
169 message.insert("number", 1);
170 message.insert("string", QString("Hello"));
171 message.insert("boolean", false);
172 service.handleMessage(message);
173
174 QCOMPARE(messageHandled.count(), 1);
175 reply = messageHandled.at(0).at(0).toMap();
176 QVERIFY(reply.contains("arguments"));
177 QStringList expectedArguments;
178 expectedArguments << "number" << "string" << "boolean";
179 QCOMPARE(reply.value("arguments").toStringList().toSet(),
180 expectedArguments.toSet());
181 messageHandled.clear();
182 QCOMPARE(isIdleChanged.count(), 2);
183 isIdleChanged.clear();
184 QVERIFY(service.isIdle());
185}
186
187QTEST_MAIN(ServiceTest);
188
189#include "tst_service.moc"
1900
=== removed file 'tests/unit/messaging-host/tst_service.pro'
--- tests/unit/messaging-host/tst_service.pro 2014-05-21 08:18:12 +0000
+++ tests/unit/messaging-host/tst_service.pro 1970-01-01 00:00:00 +0000
@@ -1,18 +0,0 @@
1include(messaging-host.pri)
2
3TARGET = tst_service
4
5QT += \
6 core \
7 testlib
8
9SOURCES += \
10 $${SRC_DIR}/service.cpp \
11 tst_service.cpp
12
13HEADERS += \
14 $${SRC_DIR}/service.h
15
16check.commands = "xvfb-run -s '-screen 0 640x480x24' -a ./$${TARGET}"
17check.depends = $${TARGET}
18QMAKE_EXTRA_TARGETS += check
190
=== removed file 'tests/unit/messaging-host/tst_webapps-handler.cpp'
--- tests/unit/messaging-host/tst_webapps-handler.cpp 2014-06-23 07:32:13 +0000
+++ tests/unit/messaging-host/tst_webapps-handler.cpp 1970-01-01 00:00:00 +0000
@@ -1,354 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical Ltd.
3 *
4 * This file is part of unity-chromium-extension
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19extern "C" {
20#include <unity-webapps-permissions.h>
21#include <unity-webapps-application-repository.h>
22}
23
24#include "webapps-handler.h"
25
26#include <QDebug>
27#include <QSignalSpy>
28#include <QTest>
29
30
31// {{{ mock implementations
32struct AppInfo {
33 bool install;
34 bool allowed;
35 bool dontask;
36 UnityWebappsApplicationStatus status;
37 QString name;
38 QString domain;
39};
40
41QMap<QString, AppInfo> _mock_app_info;
42
43UnityWebappsApplicationRepository *unity_webapps_application_repository_new_default()
44{
45 return (UnityWebappsApplicationRepository*)g_object_new(G_TYPE_OBJECT, 0);
46}
47
48gboolean unity_webapps_application_repository_prepare(UnityWebappsApplicationRepository *repository)
49{
50 Q_UNUSED(repository);
51
52 return true;
53}
54
55GList * unity_webapps_application_repository_resolve_url(UnityWebappsApplicationRepository *repository, const gchar *url)
56{
57 Q_UNUSED(repository);
58
59 if (!_mock_app_info.contains(QString::fromUtf8(url))) {
60 return 0;
61 }
62
63 return g_list_append((GList*)0, (gpointer)g_strdup(url));
64}
65
66UnityWebappsApplicationStatus
67unity_webapps_application_repository_get_resolved_application_status(
68 UnityWebappsApplicationRepository *repository,
69 const gchar *application
70)
71{
72 Q_UNUSED(repository);
73
74 if (!_mock_app_info.contains(QString::fromUtf8(application))) {
75 return UNITY_WEBAPPS_APPLICATION_STATUS_UNRESOLVED;
76 }
77
78 return _mock_app_info.value(QString::fromUtf8(application)).status;
79}
80
81const gchar *
82unity_webapps_application_repository_get_resolved_application_name(UnityWebappsApplicationRepository *repository,
83 const gchar *application)
84{
85 Q_UNUSED(repository);
86
87 if (!_mock_app_info.contains(QString::fromUtf8(application))) {
88 return 0;
89 }
90
91 return g_strdup(_mock_app_info.value(QString::fromUtf8(application)).name.toLocal8Bit().constData());
92}
93
94const gchar *
95unity_webapps_application_repository_get_resolved_application_domain(UnityWebappsApplicationRepository *repository,
96 const gchar *application)
97{
98 Q_UNUSED(repository);
99
100 if (!_mock_app_info.contains(QString::fromUtf8(application))) {
101 return 0;
102 }
103
104 return g_strdup(_mock_app_info.value(QString::fromUtf8(application)).domain.toLocal8Bit().constData());
105}
106
107
108gboolean unity_webapps_permissions_get_domain_allowed(const gchar *domain)
109{
110 Q_FOREACH(const QString &key, _mock_app_info.keys()) {
111 AppInfo appInfo = _mock_app_info.value(key);
112 if (appInfo.domain == QLatin1String(domain)) {
113 return appInfo.allowed;
114 }
115 }
116
117 return false;
118}
119
120gboolean unity_webapps_permissions_get_domain_dontask(const gchar *domain)
121{
122 Q_FOREACH(const QString &key, _mock_app_info.keys()) {
123 AppInfo appInfo = _mock_app_info.value(key);
124 if (appInfo.domain == QLatin1String(domain)) {
125 return appInfo.dontask;
126 }
127 }
128
129 return false;
130}
131
132void unity_webapps_permissions_dontask_domain(const gchar *domain)
133{
134 Q_UNUSED(domain);
135}
136
137void
138unity_webapps_application_repository_install_application(UnityWebappsApplicationRepository *repository, const gchar *name,
139 UnityWebappsApplicationRepositoryInstallCallback callback, gpointer user_data)
140{
141 Q_UNUSED(repository);
142 Q_UNUSED(name);
143 Q_UNUSED(callback);
144 Q_UNUSED(user_data);
145}
146
147// }}}
148
149
150class WebappsHandlerTest : public QObject
151{
152 Q_OBJECT
153
154public:
155 WebappsHandlerTest();
156
157private Q_SLOTS:
158 void initTestCase();
159 void cleanupTestCase();
160 void testUrlLoadedMalformedRequest();
161 void testUrlLoaded_data();
162 void testUrlLoaded();
163 void testDontAskMalformedRequest();
164 void testDontAsk_data();
165 void testDontAsk();
166 void testInstallMalformedRequest();
167 void testInstall_data();
168 void testInstall();
169 void testCreateApplicationDesktopName_data();
170 void testCreateApplicationDesktopName();
171};
172
173WebappsHandlerTest::WebappsHandlerTest():
174 QObject(0)
175{
176}
177
178
179void WebappsHandlerTest::initTestCase()
180{
181 _mock_app_info.insert("https://mail.google.com/", { true, false, false, UNITY_WEBAPPS_APPLICATION_STATUS_AVAILABLE, "Gmail", "mail.google.com" });
182 _mock_app_info.insert("http://www.tumblr.com/", { false, true, true, UNITY_WEBAPPS_APPLICATION_STATUS_AVAILABLE, "Tumblr", "www.tumblr.com" });
183}
184
185void WebappsHandlerTest::cleanupTestCase()
186{
187}
188
189void WebappsHandlerTest::testUrlLoadedMalformedRequest()
190{
191 UnityWebapps::WebappsHandler handler;
192
193 QVariantMap message;
194 message.insert("method", QString("url_loaded"));
195
196 QVariantMap reply = handler.url_loaded(message);
197
198 QVERIFY(!reply.empty());
199 QCOMPARE(reply.value("error").toString(), QStringLiteral("malformed request"));
200}
201
202void WebappsHandlerTest::testUrlLoaded_data()
203{
204 QTest::addColumn<QString>("url");
205 QTest::addColumn<bool>("available");
206 QTest::addColumn<QString>("appName");
207 QTest::addColumn<QString>("appDomain");
208
209 QTest::newRow("available") << "https://mail.google.com/" << true << "Gmail" << "mail.google.com";
210 QTest::newRow("not_available") << "http://www.example.com/" << false << "None" << "None";
211}
212
213void WebappsHandlerTest::testUrlLoaded()
214{
215 QFETCH(QString, url);
216 QFETCH(bool, available);
217 QFETCH(QString, appName);
218 QFETCH(QString, appDomain);
219
220 QVariantMap message;
221 message.insert("method", QString("url_loaded"));
222 message.insert("url", url);
223
224 UnityWebapps::WebappsHandler handler;
225 QVariantMap reply = handler.url_loaded(message);
226
227 QVERIFY(!reply.empty());
228 QCOMPARE(reply.value("available").toBool(), available);
229 if (available) {
230 QCOMPARE(appName, reply.value("appName").toString());
231 QCOMPARE(appDomain, reply.value("appDomain").toString());
232 }
233}
234
235void WebappsHandlerTest::testDontAskMalformedRequest()
236{
237 UnityWebapps::WebappsHandler handler;
238
239 QVariantMap message;
240 message.insert("method", QString("dont_ask"));
241
242 QVariantMap reply = handler.url_loaded(message);
243
244 QVERIFY(!reply.empty());
245 QCOMPARE(reply.value("error").toString(), QStringLiteral("malformed request"));
246}
247
248void WebappsHandlerTest::testDontAsk_data()
249{
250 QTest::addColumn<QString>("url");
251 QTest::addColumn<bool>("available");
252
253 QTest::newRow("ask") << "https://mail.google.com/" << true;
254 QTest::newRow("dont_ask") << "http://www.tumblr.com/" << true;
255 QTest::newRow("no app") << "http://www.example.com/" << false;
256}
257
258void WebappsHandlerTest::testDontAsk()
259{
260 QFETCH(QString, url);
261 QFETCH(bool, available);
262
263 UnityWebapps::WebappsHandler handler;
264
265 QVariantMap message;
266 message.insert("method", QString("dont_ask"));
267 message.insert("url", url);
268
269 QVariantMap reply = handler.dont_ask(message);
270
271 QVERIFY(!reply.empty());
272 if (available) {
273 QCOMPARE(reply.value("dont_ask").toBool(), true);
274 } else {
275 QCOMPARE(reply.value("dont_ask").toBool(), false);
276 QCOMPARE(reply.value("available").toBool(), false);
277 }
278}
279
280void WebappsHandlerTest::testInstallMalformedRequest()
281{
282 UnityWebapps::WebappsHandler handler;
283
284 QVariantMap message;
285 message.insert("method", QString("install"));
286
287 QVariantMap reply = handler.url_loaded(message);
288
289 QVERIFY(!reply.empty());
290 QCOMPARE(reply.value("error").toString(), QStringLiteral("malformed request"));
291}
292
293void WebappsHandlerTest::testInstall_data()
294{
295 QTest::addColumn<QString>("url");
296 QTest::addColumn<bool>("available");
297 QTest::addColumn<bool>("installed");
298
299 QTest::newRow("installs") << "https://mail.google.com/" << true << true;
300 QTest::newRow("wont install") << "http://www.tumblr.com/" << true << false;
301 QTest::newRow("no app") << "http://www.example.com/" << false << false;
302}
303
304void WebappsHandlerTest::testInstall()
305{
306 QFETCH(QString, url);
307 QFETCH(bool, available);
308 QFETCH(bool, installed);
309
310 QVariantMap message;
311 message.insert("method", QString("install"));
312 message.insert("url", url);
313
314 UnityWebapps::WebappsHandler handler;
315 QVariantMap reply = handler.install(message);
316
317 QVERIFY(!reply.empty());
318 QCOMPARE(reply.value("installed").toBool(), installed);
319 if (!available) {
320 QCOMPARE(reply.value("available").toBool(), false);
321 }
322}
323
324void WebappsHandlerTest::testCreateApplicationDesktopName_data()
325{
326 QTest::addColumn<QString>("appName");
327 QTest::addColumn<QString>("appDomain");
328 QTest::addColumn<QString>("expected_uri");
329
330 // Behaviour
331 QTest::newRow("strip whitespace") << "White Space Name" << "example.com" << "application://WhiteSpaceNameexamplecom.desktop";
332 QTest::newRow("strip special chars") << "%$special%^" << "example.com" << "application://specialexamplecom.desktop";
333 QTest::newRow("numbers allowed") << "13monkeys" << "example.com" << "application://13monkeysexamplecom.desktop";
334 QTest::newRow("combined") << "##12combined test$%67" << "example.com" << "application://12combinedtest67examplecom.desktop";
335
336 // Examples
337 QTest::newRow("live example 1") << "FacebookMessanger" << "facebook.com" << "application://FacebookMessangerfacebookcom.desktop";
338 QTest::newRow("live example 2") << "Gmail" << "mail.google.com" << "application://Gmailmailgooglecom.desktop";
339 QTest::newRow("live example 3") << "GooglePlus" << "plus.google.com" << "application://GooglePlusplusgooglecom.desktop";
340}
341
342void WebappsHandlerTest::testCreateApplicationDesktopName()
343{
344 QFETCH(QString, appName);
345 QFETCH(QString, appDomain);
346 QFETCH(QString, expected_uri);
347
348 UnityWebapps::WebappsHandler handler;
349 QCOMPARE(handler.createApplicationDesktopName(appName, appDomain), expected_uri);
350}
351
352QTEST_MAIN(WebappsHandlerTest);
353
354#include "tst_webapps-handler.moc"
3550
=== removed file 'tests/unit/messaging-host/tst_webapps-handler.pro'
--- tests/unit/messaging-host/tst_webapps-handler.pro 2014-06-23 07:32:13 +0000
+++ tests/unit/messaging-host/tst_webapps-handler.pro 1970-01-01 00:00:00 +0000
@@ -1,32 +0,0 @@
1include(messaging-host.pri)
2
3TARGET = tst_webapps-handler
4
5QMAKE_CXXFLAGS += -std=c++11
6
7CONFIG += \
8 link_pkgconfig \
9 qt
10
11QT += \
12 core \
13 testlib
14
15PKGCONFIG += \
16 glib-2.0 \
17 gobject-2.0 \
18 libunity_webapps-0.2 \
19 libunity-webapps-repository \
20
21DEFINES += UCX_UNDER_TEST
22
23SOURCES += \
24 $${SRC_DIR}/webapps-handler.cpp \
25 tst_webapps-handler.cpp
26
27HEADERS += \
28 $${SRC_DIR}/webapps-handler.h
29
30check.commands = "xvfb-run -s '-screen 0 640x480x24' -a ./$${TARGET}"
31check.depends = $${TARGET}
32QMAKE_EXTRA_TARGETS += check
330
=== added directory 'tests/unit/messaging-host/webapps-handler'
=== added file 'tests/unit/messaging-host/webapps-handler/CMakeLists.txt'
--- tests/unit/messaging-host/webapps-handler/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ tests/unit/messaging-host/webapps-handler/CMakeLists.txt 2015-10-07 04:25:10 +0000
@@ -0,0 +1,47 @@
1set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
2set(CMAKE_INCLUDE_CURRENT_DIR ON)
3set(CMAKE_AUTOMOC ON)
4
5find_package(PkgConfig)
6find_package(Qt5Core REQUIRED)
7find_package(Qt5Test REQUIRED)
8
9pkg_check_modules(GLIB glib-2.0 REQUIRED)
10pkg_check_modules(GOBJECT gobject-2.0 REQUIRED)
11pkg_check_modules(WEBAPPS libunity_webapps-0.2)
12pkg_check_modules(WEBAPPS_REPO libunity-webapps-repository)
13
14set(TEST tst_WebappsHandler)
15set(SOURCES
16 ${messaging-host_SOURCE_DIR}/webapps-handler.cpp
17 tst_webapps-handler.cpp
18)
19
20
21include_directories(
22 ${messaging-host_SOURCE_DIR}
23 ${GLIB_INCLUDE_DIRS}
24 ${WEBAPPS_INCLUDE_DIRS}
25 ${WEBAPPS_REPO_INCLUDE_DIRS}
26)
27
28if(DEFINED WEBAPPS_FOUND AND WEBAPPS_FOUND EQUAL 1)
29 if(DEFINED WEBAPPS_REPO_FOUND AND WEBAPPS_REPO_FOUND EQUAL 1)
30 add_definitions(
31 -DHAVE_UNITY_WEBAPPS=1
32 -DUCX_UNDER_TEST=1
33 )
34 add_executable(${TEST} ${SOURCES})
35 target_link_libraries(
36 ${TEST}
37
38 Qt5::Core
39 Qt5::Test
40 ${GLIB_LIBRARIES}
41 ${GOBJECT_LIBRARIES}
42 ${WEBAPPS_LIBRARIES}
43 ${WEBAPPS_REPO_LIBRARIES}
44 )
45 add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
46 endif()
47endif()
048
=== added file 'tests/unit/messaging-host/webapps-handler/tst_webapps-handler.cpp'
--- tests/unit/messaging-host/webapps-handler/tst_webapps-handler.cpp 1970-01-01 00:00:00 +0000
+++ tests/unit/messaging-host/webapps-handler/tst_webapps-handler.cpp 2015-10-07 04:25:10 +0000
@@ -0,0 +1,354 @@
1/*
2 * Copyright (C) 2014 Canonical Ltd.
3 *
4 * This file is part of unity-chromium-extension
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 3, as published
8 * by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranties of
12 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
13 * PURPOSE. See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19extern "C" {
20#include <unity-webapps-permissions.h>
21#include <unity-webapps-application-repository.h>
22}
23
24#include "webapps-handler.h"
25
26#include <QDebug>
27#include <QSignalSpy>
28#include <QTest>
29
30
31// {{{ mock implementations
32struct AppInfo {
33 bool install;
34 bool allowed;
35 bool dontask;
36 UnityWebappsApplicationStatus status;
37 QString name;
38 QString domain;
39};
40
41QMap<QString, AppInfo> _mock_app_info;
42
43UnityWebappsApplicationRepository *unity_webapps_application_repository_new_default()
44{
45 return (UnityWebappsApplicationRepository*)g_object_new(G_TYPE_OBJECT, 0);
46}
47
48gboolean unity_webapps_application_repository_prepare(UnityWebappsApplicationRepository *repository)
49{
50 Q_UNUSED(repository);
51
52 return true;
53}
54
55GList * unity_webapps_application_repository_resolve_url(UnityWebappsApplicationRepository *repository, const gchar *url)
56{
57 Q_UNUSED(repository);
58
59 if (!_mock_app_info.contains(QString::fromUtf8(url))) {
60 return 0;
61 }
62
63 return g_list_append((GList*)0, (gpointer)g_strdup(url));
64}
65
66UnityWebappsApplicationStatus
67unity_webapps_application_repository_get_resolved_application_status(
68 UnityWebappsApplicationRepository *repository,
69 const gchar *application
70)
71{
72 Q_UNUSED(repository);
73
74 if (!_mock_app_info.contains(QString::fromUtf8(application))) {
75 return UNITY_WEBAPPS_APPLICATION_STATUS_UNRESOLVED;
76 }
77
78 return _mock_app_info.value(QString::fromUtf8(application)).status;
79}
80
81const gchar *
82unity_webapps_application_repository_get_resolved_application_name(UnityWebappsApplicationRepository *repository,
83 const gchar *application)
84{
85 Q_UNUSED(repository);
86
87 if (!_mock_app_info.contains(QString::fromUtf8(application))) {
88 return 0;
89 }
90
91 return g_strdup(_mock_app_info.value(QString::fromUtf8(application)).name.toLocal8Bit().constData());
92}
93
94const gchar *
95unity_webapps_application_repository_get_resolved_application_domain(UnityWebappsApplicationRepository *repository,
96 const gchar *application)
97{
98 Q_UNUSED(repository);
99
100 if (!_mock_app_info.contains(QString::fromUtf8(application))) {
101 return 0;
102 }
103
104 return g_strdup(_mock_app_info.value(QString::fromUtf8(application)).domain.toLocal8Bit().constData());
105}
106
107
108gboolean unity_webapps_permissions_get_domain_allowed(const gchar *domain)
109{
110 Q_FOREACH(const QString &key, _mock_app_info.keys()) {
111 AppInfo appInfo = _mock_app_info.value(key);
112 if (appInfo.domain == QLatin1String(domain)) {
113 return appInfo.allowed;
114 }
115 }
116
117 return false;
118}
119
120gboolean unity_webapps_permissions_get_domain_dontask(const gchar *domain)
121{
122 Q_FOREACH(const QString &key, _mock_app_info.keys()) {
123 AppInfo appInfo = _mock_app_info.value(key);
124 if (appInfo.domain == QLatin1String(domain)) {
125 return appInfo.dontask;
126 }
127 }
128
129 return false;
130}
131
132void unity_webapps_permissions_dontask_domain(const gchar *domain)
133{
134 Q_UNUSED(domain);
135}
136
137void
138unity_webapps_application_repository_install_application(UnityWebappsApplicationRepository *repository, const gchar *name,
139 UnityWebappsApplicationRepositoryInstallCallback callback, gpointer user_data)
140{
141 Q_UNUSED(repository);
142 Q_UNUSED(name);
143 Q_UNUSED(callback);
144 Q_UNUSED(user_data);
145}
146
147// }}}
148
149
150class WebappsHandlerTest : public QObject
151{
152 Q_OBJECT
153
154public:
155 WebappsHandlerTest();
156
157private Q_SLOTS:
158 void initTestCase();
159 void cleanupTestCase();
160 void testUrlLoadedMalformedRequest();
161 void testUrlLoaded_data();
162 void testUrlLoaded();
163 void testDontAskMalformedRequest();
164 void testDontAsk_data();
165 void testDontAsk();
166 void testInstallMalformedRequest();
167 void testInstall_data();
168 void testInstall();
169 void testCreateApplicationDesktopName_data();
170 void testCreateApplicationDesktopName();
171};
172
173WebappsHandlerTest::WebappsHandlerTest():
174 QObject(0)
175{
176}
177
178
179void WebappsHandlerTest::initTestCase()
180{
181 _mock_app_info.insert("https://mail.google.com/", { true, false, false, UNITY_WEBAPPS_APPLICATION_STATUS_AVAILABLE, "Gmail", "mail.google.com" });
182 _mock_app_info.insert("http://www.tumblr.com/", { false, true, true, UNITY_WEBAPPS_APPLICATION_STATUS_AVAILABLE, "Tumblr", "www.tumblr.com" });
183}
184
185void WebappsHandlerTest::cleanupTestCase()
186{
187}
188
189void WebappsHandlerTest::testUrlLoadedMalformedRequest()
190{
191 UnityWebapps::WebappsHandler handler;
192
193 QVariantMap message;
194 message.insert("method", QString("url_loaded"));
195
196 QVariantMap reply = handler.url_loaded(message);
197
198 QVERIFY(!reply.empty());
199 QCOMPARE(reply.value("error").toString(), QStringLiteral("malformed request"));
200}
201
202void WebappsHandlerTest::testUrlLoaded_data()
203{
204 QTest::addColumn<QString>("url");
205 QTest::addColumn<bool>("available");
206 QTest::addColumn<QString>("appName");
207 QTest::addColumn<QString>("appDomain");
208
209 QTest::newRow("available") << "https://mail.google.com/" << true << "Gmail" << "mail.google.com";
210 QTest::newRow("not_available") << "http://www.example.com/" << false << "None" << "None";
211}
212
213void WebappsHandlerTest::testUrlLoaded()
214{
215 QFETCH(QString, url);
216 QFETCH(bool, available);
217 QFETCH(QString, appName);
218 QFETCH(QString, appDomain);
219
220 QVariantMap message;
221 message.insert("method", QString("url_loaded"));
222 message.insert("url", url);
223
224 UnityWebapps::WebappsHandler handler;
225 QVariantMap reply = handler.url_loaded(message);
226
227 QVERIFY(!reply.empty());
228 QCOMPARE(reply.value("available").toBool(), available);
229 if (available) {
230 QCOMPARE(appName, reply.value("appName").toString());
231 QCOMPARE(appDomain, reply.value("appDomain").toString());
232 }
233}
234
235void WebappsHandlerTest::testDontAskMalformedRequest()
236{
237 UnityWebapps::WebappsHandler handler;
238
239 QVariantMap message;
240 message.insert("method", QString("dont_ask"));
241
242 QVariantMap reply = handler.url_loaded(message);
243
244 QVERIFY(!reply.empty());
245 QCOMPARE(reply.value("error").toString(), QStringLiteral("malformed request"));
246}
247
248void WebappsHandlerTest::testDontAsk_data()
249{
250 QTest::addColumn<QString>("url");
251 QTest::addColumn<bool>("available");
252
253 QTest::newRow("ask") << "https://mail.google.com/" << true;
254 QTest::newRow("dont_ask") << "http://www.tumblr.com/" << true;
255 QTest::newRow("no app") << "http://www.example.com/" << false;
256}
257
258void WebappsHandlerTest::testDontAsk()
259{
260 QFETCH(QString, url);
261 QFETCH(bool, available);
262
263 UnityWebapps::WebappsHandler handler;
264
265 QVariantMap message;
266 message.insert("method", QString("dont_ask"));
267 message.insert("url", url);
268
269 QVariantMap reply = handler.dont_ask(message);
270
271 QVERIFY(!reply.empty());
272 if (available) {
273 QCOMPARE(reply.value("dont_ask").toBool(), true);
274 } else {
275 QCOMPARE(reply.value("dont_ask").toBool(), false);
276 QCOMPARE(reply.value("available").toBool(), false);
277 }
278}
279
280void WebappsHandlerTest::testInstallMalformedRequest()
281{
282 UnityWebapps::WebappsHandler handler;
283
284 QVariantMap message;
285 message.insert("method", QString("install"));
286
287 QVariantMap reply = handler.url_loaded(message);
288
289 QVERIFY(!reply.empty());
290 QCOMPARE(reply.value("error").toString(), QStringLiteral("malformed request"));
291}
292
293void WebappsHandlerTest::testInstall_data()
294{
295 QTest::addColumn<QString>("url");
296 QTest::addColumn<bool>("available");
297 QTest::addColumn<bool>("installed");
298
299 QTest::newRow("installs") << "https://mail.google.com/" << true << true;
300 QTest::newRow("wont install") << "http://www.tumblr.com/" << true << false;
301 QTest::newRow("no app") << "http://www.example.com/" << false << false;
302}
303
304void WebappsHandlerTest::testInstall()
305{
306 QFETCH(QString, url);
307 QFETCH(bool, available);
308 QFETCH(bool, installed);
309
310 QVariantMap message;
311 message.insert("method", QString("install"));
312 message.insert("url", url);
313
314 UnityWebapps::WebappsHandler handler;
315 QVariantMap reply = handler.install(message);
316
317 QVERIFY(!reply.empty());
318 QCOMPARE(reply.value("installed").toBool(), installed);
319 if (!available) {
320 QCOMPARE(reply.value("available").toBool(), false);
321 }
322}
323
324void WebappsHandlerTest::testCreateApplicationDesktopName_data()
325{
326 QTest::addColumn<QString>("appName");
327 QTest::addColumn<QString>("appDomain");
328 QTest::addColumn<QString>("expected_uri");
329
330 // Behaviour
331 QTest::newRow("strip whitespace") << "White Space Name" << "example.com" << "application://WhiteSpaceNameexamplecom.desktop";
332 QTest::newRow("strip special chars") << "%$special%^" << "example.com" << "application://specialexamplecom.desktop";
333 QTest::newRow("numbers allowed") << "13monkeys" << "example.com" << "application://13monkeysexamplecom.desktop";
334 QTest::newRow("combined") << "##12combined test$%67" << "example.com" << "application://12combinedtest67examplecom.desktop";
335
336 // Examples
337 QTest::newRow("live example 1") << "FacebookMessanger" << "facebook.com" << "application://FacebookMessangerfacebookcom.desktop";
338 QTest::newRow("live example 2") << "Gmail" << "mail.google.com" << "application://Gmailmailgooglecom.desktop";
339 QTest::newRow("live example 3") << "GooglePlus" << "plus.google.com" << "application://GooglePlusplusgooglecom.desktop";
340}
341
342void WebappsHandlerTest::testCreateApplicationDesktopName()
343{
344 QFETCH(QString, appName);
345 QFETCH(QString, appDomain);
346 QFETCH(QString, expected_uri);
347
348 UnityWebapps::WebappsHandler handler;
349 QCOMPARE(handler.createApplicationDesktopName(appName, appDomain), expected_uri);
350}
351
352QTEST_MAIN(WebappsHandlerTest);
353
354#include "tst_webapps-handler.moc"
0355
=== removed file 'tests/unit/unit.pro'
--- tests/unit/unit.pro 2014-05-20 12:21:50 +0000
+++ tests/unit/unit.pro 1970-01-01 00:00:00 +0000
@@ -1,3 +0,0 @@
1TEMPLATE = subdirs
2SUBDIRS = \
3 messaging-host
40
=== removed file 'unity-chromium-extension.pro'
--- unity-chromium-extension.pro 2014-05-19 14:04:19 +0000
+++ unity-chromium-extension.pro 1970-01-01 00:00:00 +0000
@@ -1,14 +0,0 @@
1include(common-project-config.pri)
2include(common-vars.pri)
3
4TEMPLATE = subdirs
5SUBDIRS = \
6 chromium-extension \
7 messaging-host \
8 tests
9
10tests.depends = messaging-host
11
12DISTNAME = $${PROJECT_NAME}-$${PROJECT_VERSION}
13dist.commands = "bzr export $${DISTNAME}.tar.bz2"
14QMAKE_EXTRA_TARGETS += dist

Subscribers

People subscribed via source and target branches

to all changes: