- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / test / data / extensions / hangout_services_test.js
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // JavaScript for invoking methods on APIs used by Hangouts via the
6 // Hangout Services extension, and a JavaScript-based end-to-end test
7 // of the extension.
8
9 // ID of the Hangout Services component extension.
10 var EXTENSION_ID = "nkeimhogjdpnpccoofpliimaahmaaome";
11
12 // Sends a message to the Hangout Services extension, expecting
13 // success, and unwraps the value returned.
14 function sendMessage(message, callback) {
15   function unwrapValue(result) {
16     if (callback)
17       callback(result.value);
18   }
19   window.top.chrome.runtime.sendMessage(EXTENSION_ID, message, unwrapValue);
20 }
21
22 // If connected, this port will receive events from the extension.
23 var callbackPort;
24
25 // Connects callbackPort to the extension, with a connectInfo.name that
26 // indicates we want to receive the onSinksChanged event, and sets its
27 // onMessage to |callback|.
28 function listenForSinksChangedEvent(callback) {
29   callbackPort = window.top.chrome.runtime.connect(
30       EXTENSION_ID, {'name': 'onSinksChangedListener'});
31   callbackPort.onMessage.addListener(callback);
32 }
33
34 //
35 // Helpers to invoke functions on the extension.
36 //
37
38 // Will call |callback({'cancelId': ..., 'streamId': ...})| on completion.
39 function chooseDesktopMedia(callback) {
40   sendMessage({'method': 'chooseDesktopMedia'}, callback);
41 }
42
43 // Will call |callback()| when API method has been called (it will
44 // complete later).
45 function cancelChooseDesktopMedia(cancelId, callback) {
46   sendMessage({'method': 'cancelChooseDesktopMedia', 'cancelId': cancelId},
47               callback);
48 }
49
50 // Will call |callback(cpuInfo)| on completion.
51 function cpuGetInfo(callback) {
52   sendMessage({'method': 'cpu.getInfo'}, callback);
53 }
54
55 // Will call |callback()| on completion.
56 function loggingSetMetadata(metaData, callback) {
57   sendMessage({'method': 'logging.setMetadata', 'metaData': metaData},
58               callback);
59 }
60
61 // Will call |callback()| on completion.
62 function loggingStart(callback) {
63   sendMessage({'method': 'logging.start'}, callback);
64 }
65
66 // Will call |callback()| when API method has been called (it will
67 // complete later).
68 function loggingUploadOnRenderClose() {
69   sendMessage({'method': 'logging.uploadOnRenderClose'});
70 }
71
72 // Will call |callback()| when API method has been called (it will
73 // complete later).
74 function loggingNoUploadOnRenderClose() {
75   sendMessage({'method': 'logging.noUploadOnRenderClose'});
76 }
77
78 // Will call |callback()| on completion.
79 function loggingStop(callback) {
80   sendMessage({'method': 'logging.stop'}, callback);
81 }
82
83 // Will call |callback(uploadResult)| on completion.
84 function loggingUpload(callback) {
85   sendMessage({'method': 'logging.upload'}, callback);
86 }
87
88 // Will call |callback()| on completion.
89 function loggingDiscard(callback) {
90   sendMessage({'method': 'logging.discard'}, callback);
91 }
92
93 // Will call |callback(sinkList)| on completion.
94 function getSinks(callback) {
95   sendMessage({'method': 'getSinks'}, callback);
96 }
97
98 // Will call |callback(activeSink)| on completion.
99 function getActiveSink(callback) {
100   sendMessage({'method': 'getActiveSink'}, callback);
101 }
102
103 // Will call |callback()| on completion.
104 function setActiveSink(sinkId, callback) {
105   sendMessage({'method': 'setActiveSink', 'sinkId': sinkId}, callback);
106 }
107
108 // Will call |callback(sinkId)| on completion.
109 function getAssociatedSink(sourceId, callback) {
110   sendMessage({'method': 'getAssociatedSink', 'sourceId': sourceId},
111               callback);
112 }
113
114 // Will call |callback()| on completion. If the extension you send to
115 // is not loaded, the extension system will still call |callback()|
116 // but will set lastError.
117 function isExtensionEnabled(callback) {
118   sendMessage({'method': 'isExtensionEnabled'}, callback);
119 }
120
121 //
122 // Manual tests.
123 //
124
125 function manualTestChooseDesktopMedia() {
126   chooseDesktopMedia(function(results) {
127       alert('Cancel ID: ' + results.cancelId +
128             ', stream ID: ' + results.streamId);
129     });
130 }
131
132 function manualTestListenForSinksChangedEvent() {
133   listenForSinksChangedEvent(function(msg) {
134       if (msg['eventName'] && msg['eventName'] == 'onSinksChanged')
135         alert('Got onSinksChanged event.');
136     });
137 }
138
139 //
140 // Automated tests.
141 //
142
143 // Very micro test framework. Add all tests to |TESTS|. Each test must
144 // call the passed-in callback eventually with a string indicating
145 // results. Empty results indicate success.
146 var TESTS = [
147   testCpuGetInfo,
148   testLogging,
149   testDisabledLogging,
150   testDisabledLoggingButUpload,
151   testEnabledLoggingButDiscard,
152   testGetSinks,
153   testGetActiveSink,
154   testSetActiveSink,
155   testGetAssociatedSink,
156   testIsExtensionEnabled,
157   testSendingToInvalidExtension,
158
159   // Uncomment to manually test timeout logic.
160   //testTimeout,
161 ];
162
163 function runAllTests(callback) {
164   var results = '';
165
166   // Run one test at a time, running the next only on completion.
167   // This makes it easier to deal with timing out tests that do not
168   // complete successfully.
169   //
170   // It also seems necessary (instead of starting all the tests in
171   // parallel) as the webrtcLoggingPrivate API does not seem to like
172   // certain sequences of interleaved requests (it may DCHECK in
173   // WebRtcLoggingHandlerHost::NotifyLoggingStarted() when firing the
174   // start callback.
175   //
176   // TODO(grunell): Fix webrtcLoggingPrivate to be stateless.
177
178   // Index of the test currently executing.
179   var testIndex = 0;
180
181   function startTest(test) {
182     console.log('Starting ' + test.name);
183
184     // Start the test function...
185     test(function(currentResults) {
186         nextTest(test.name, currentResults, false);
187       });
188
189     // ...and also start a timeout.
190     function onTimeout() {
191       nextTest(test.name, '', true);
192     }
193     setTimeout(onTimeout, 3000);
194   }
195
196   function nextTest(testName, currentResults, timedOut) {
197     // The check for testIndex is necessary for timeouts arriving
198     // after testIndex is already past the end of the TESTS array.
199     if (testIndex >= TESTS.length ||
200         testName != TESTS[testIndex].name) {
201       // Either a timeout of a function that already completed, or a
202       // function completing after a timeout. Either way we ignore.
203       console.log('Ignoring results for ' + testName +
204                   ' (timedout: ' + timedOut + ')');
205       return;
206     }
207
208     if (timedOut) {
209       console.log('Timed out: ' + testName);
210       results = results + 'Timed out: ' + testName + '\n';
211     } else {
212       console.log('Got results for ' + testName + ': ' + currentResults);
213       if (currentResults != '') {
214         results = results + 'Failure in ' + testName + ':\n';
215         results = results + currentResults;
216       }
217     }
218
219     ++testIndex;
220     if (testIndex == TESTS.length)
221       callback(results);
222     else
223       startTest(TESTS[testIndex]);
224   }
225
226   startTest(TESTS[testIndex]);
227 }
228
229 function testCpuGetInfo(callback) {
230   cpuGetInfo(function(info) {
231       if (info.numOfProcessors != 0 &&
232           info.archName != '' &&
233           info.modelName != '')
234         callback('');
235       else
236         callback('Missing information in CpuInfo');
237     });
238 }
239
240 // Tests setting metadata, turning on upload, starting and then
241 // stopping the log.
242 function testLogging(callback) {
243   loggingSetMetadata([{'bingo': 'bongo', 'smurf': 'geburf'}], function() {
244       loggingStart(function() {
245           loggingUploadOnRenderClose();
246           loggingStop(function() {
247               callback('');
248             });
249         });
250     });
251 }
252
253 // Starts and stops logging while auto-upload is disabled.
254 function testDisabledLogging(callback) {
255   loggingNoUploadOnRenderClose();
256   loggingStart(function() {
257       loggingStop(function() {
258           callback('');
259         });
260     });
261 }
262
263 // Starts and stops logging while auto-upload is disabled, but
264 // requests logs upload after stopping logging.
265 function testDisabledLoggingButUpload(callback) {
266   loggingNoUploadOnRenderClose();
267   loggingStart(function() {
268       loggingStop(function() {
269           loggingUpload(function(loggingResult) {
270               if (loggingResult != '')
271                 callback('');
272               else
273                 callback('Got empty upload result.');
274             });
275         });
276     });
277 }
278
279 // Starts and stops logging while auto-upload is enabled, but
280 // requests logs be discarded after stopping logging.
281 function testEnabledLoggingButDiscard(callback) {
282   loggingUploadOnRenderClose();
283   loggingStart(function() {
284       loggingStop(function() {
285           loggingDiscard(function() {
286               callback('');
287             });
288         });
289     });
290 }
291
292 function testGetSinks(callback) {
293   getSinks(function(sinks) {
294       if (sinks.length == 0)
295         callback('Got no sinks.');
296       else
297         callback('');
298     });
299 }
300
301 function testGetActiveSink(callback) {
302   getActiveSink(function(sinkId) {
303       if (sinkId == '')
304         callback('Got empty sink ID.');
305       else
306         callback('');
307     });
308 }
309
310 function testSetActiveSink(callback) {
311   getSinks(function(sinks) {
312       for (var i = 0; i < sinks.length; ++i) {
313         setActiveSink(sinks[i].sinkId);
314       }
315       callback('');
316     });
317 }
318
319 function testGetAssociatedSink(callback) {
320   getAssociatedSink('noSuchSourceId', function(sinkId) {
321       if (sinkId != '') {
322         callback('Got non-empty sink ID for nonexistent source ID.');
323       } else {
324         callback('');
325       }
326     });
327 }
328
329 function testIsExtensionEnabled(callback) {
330   isExtensionEnabled(function() {
331       callback('');
332     });
333 }
334
335 function testSendingToInvalidExtension(callback) {
336   // This test verifies that client code can always determine whether
337   // or not the component extension is available without resorting to
338   // timeouts, by sending it the 'isExtensionEnabled' message. If the
339   // extension is there, it will respond (see testIsExtensionEnabled)
340   // and if it's not, the extension framework will send a callback and
341   // set lastError.
342   var NON_EXISTENT_EXTENSION_ID = "aaaaaaagjdpnpccoofpliimaaeeeeeee";
343   window.top.chrome.runtime.sendMessage(
344       NON_EXISTENT_EXTENSION_ID, {'method': 'isExtensionEnabled'},
345       function() {
346           if (window.top.chrome.runtime.lastError.message.indexOf(
347                   'Could not establish connection') == -1) {
348             callback('lastError is not set correctly.');
349           } else {
350             callback('');
351           }
352         });
353 }
354
355 function testTimeout(callback) {
356   // Never call the callback. Used for manually testing that the
357   // timeout logic of the test framework is correct.
358 }