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.
5 // JavaScript for invoking methods on APIs used by Hangouts via the
6 // Hangout Services extension, and a JavaScript-based end-to-end test
9 // ID of the Hangout Services component extension.
10 var EXTENSION_ID
= "nkeimhogjdpnpccoofpliimaahmaaome";
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
) {
17 callback(result
.value
);
19 window
.top
.chrome
.runtime
.sendMessage(EXTENSION_ID
, message
, unwrapValue
);
22 // If connected, this port will receive events from the extension.
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
);
35 // Helpers to invoke functions on the extension.
38 // Will call |callback({'cancelId': ..., 'streamId': ...})| on completion.
39 function chooseDesktopMedia(callback
) {
40 sendMessage({'method': 'chooseDesktopMedia'}, callback
);
43 // Will call |callback()| when API method has been called (it will
45 function cancelChooseDesktopMedia(cancelId
, callback
) {
46 sendMessage({'method': 'cancelChooseDesktopMedia', 'cancelId': cancelId
},
50 // Will call |callback(cpuInfo)| on completion.
51 function cpuGetInfo(callback
) {
52 sendMessage({'method': 'cpu.getInfo'}, callback
);
55 // Will call |callback()| on completion.
56 function loggingSetMetadata(metaData
, callback
) {
57 sendMessage({'method': 'logging.setMetadata', 'metaData': metaData
},
61 // Will call |callback()| on completion.
62 function loggingStart(callback
) {
63 sendMessage({'method': 'logging.start'}, callback
);
66 // Will call |callback()| when API method has been called (it will
68 function loggingUploadOnRenderClose() {
69 sendMessage({'method': 'logging.uploadOnRenderClose'});
72 // Will call |callback()| when API method has been called (it will
74 function loggingNoUploadOnRenderClose() {
75 sendMessage({'method': 'logging.noUploadOnRenderClose'});
78 // Will call |callback()| on completion.
79 function loggingStop(callback
) {
80 sendMessage({'method': 'logging.stop'}, callback
);
83 // Will call |callback()| on completion.
84 function loggingStore(logId
, callback
) {
85 sendMessage({'method': 'logging.store', 'logId': logId
}, callback
);
88 // Will call |callback()| on completion.
89 function loggingUploadStored(logId
, callback
) {
90 sendMessage({'method': 'logging.uploadStored', 'logId': logId
}, callback
);
93 // Will call |callback(uploadResult)| on completion.
94 function loggingUpload(callback
) {
95 sendMessage({'method': 'logging.upload'}, callback
);
98 // Will call |callback(uploadResult)| on completion.
99 function loggingStopAndUpload(callback
) {
100 sendMessage({'method': 'logging.stopAndUpload'}, callback
);
103 // Will call |callback()| on completion.
104 function loggingDiscard(callback
) {
105 sendMessage({'method': 'logging.discard'}, callback
);
108 // Will call |callback(sinkList)| on completion.
109 function getSinks(callback
) {
110 sendMessage({'method': 'getSinks'}, callback
);
113 // Will call |callback(activeSink)| on completion.
114 function getActiveSink(callback
) {
115 sendMessage({'method': 'getActiveSink'}, callback
);
118 // Will call |callback()| on completion.
119 function setActiveSink(sinkId
, callback
) {
120 sendMessage({'method': 'setActiveSink', 'sinkId': sinkId
}, callback
);
123 // Will call |callback(sinkId)| on completion.
124 function getAssociatedSink(sourceId
, callback
) {
125 sendMessage({'method': 'getAssociatedSink', 'sourceId': sourceId
},
129 // Will call |callback()| on completion. If the extension you send to
130 // is not loaded, the extension system will still call |callback()|
131 // but will set lastError.
132 function isExtensionEnabled(callback
) {
133 sendMessage({'method': 'isExtensionEnabled'}, callback
);
140 // Very micro test framework. Add all tests to |TESTS|. Each test must
141 // call the passed-in callback eventually with a string indicating
142 // results. Empty results indicate success.
146 testLoggingSetMetaDataAfterStart
,
148 testDisabledLoggingButUpload
,
149 testDisabledLoggingWithStopAndUpload
,
150 testEnabledLoggingButDiscard
,
154 testGetAssociatedSink
,
155 testIsExtensionEnabled
,
156 testSendingToInvalidExtension
,
159 // Uncomment to manually test timeout logic.
163 var TEST_TIMEOUT_MS
= 3000;
165 function runAllTests(callback
) {
168 // Run one test at a time, running the next only on completion.
169 // This makes it easier to deal with timing out tests that do not
170 // complete successfully.
172 // It also seems necessary (instead of starting all the tests in
173 // parallel) as the webrtcLoggingPrivate API does not seem to like
174 // certain sequences of interleaved requests (it may DCHECK in
175 // WebRtcLoggingHandlerHost::NotifyLoggingStarted() when firing the
178 // TODO(grunell): Fix webrtcLoggingPrivate to be stateless.
180 // Index of the test currently executing.
183 function startTest(test
) {
184 console
.log('Starting ' + test
.name
);
186 // Start the test function...
187 test(function(currentResults
) {
188 nextTest(test
.name
, currentResults
, false);
191 // ...and also start a timeout.
192 function onTimeout() {
193 nextTest(test
.name
, '', true);
195 setTimeout(onTimeout
, TEST_TIMEOUT_MS
);
198 function nextTest(testName
, currentResults
, timedOut
) {
199 // The check for testIndex is necessary for timeouts arriving
200 // after testIndex is already past the end of the TESTS array.
201 if (testIndex
>= TESTS
.length
||
202 testName
!= TESTS
[testIndex
].name
) {
203 // Either a timeout of a function that already completed, or a
204 // function completing after a timeout. Either way we ignore.
205 console
.log('Ignoring results for ' + testName
+
206 ' (timedout: ' + timedOut
+ ')');
211 console
.log('Timed out: ' + testName
);
212 results
= results
+ 'Timed out: ' + testName
+ '\n';
214 console
.log('Got results for ' + testName
+ ': ' + currentResults
);
215 if (currentResults
!= '') {
216 results
= results
+ 'Failure in ' + testName
+ ':\n';
217 results
= results
+ currentResults
;
222 if (testIndex
== TESTS
.length
) {
225 startTest(TESTS
[testIndex
]);
229 startTest(TESTS
[testIndex
]);
232 function testCpuGetInfo(callback
) {
233 cpuGetInfo(function(info
) {
234 if (info
.numOfProcessors
!= 0 &&
235 info
.archName
!= '' &&
236 info
.modelName
!= '') {
239 callback('Missing information in CpuInfo');
244 // Tests setting metadata, turning on upload, starting and then
246 function testLogging(callback
) {
247 loggingSetMetadata([{'bingo': 'bongo', 'smurf': 'geburf'}], function() {
248 loggingStart(function() {
249 loggingUploadOnRenderClose();
250 loggingStop(function() {
257 // Tests starting the log, setting metadata, turning on upload, and then
259 function testLoggingSetMetaDataAfterStart(callback
) {
260 loggingStart(function() {
261 loggingSetMetadata([{'bingo': 'bongo', 'smurf': 'geburf'}], function() {
262 loggingUploadOnRenderClose();
263 loggingStop(function() {
270 // Starts and stops logging while auto-upload is disabled.
271 function testDisabledLogging(callback
) {
272 loggingNoUploadOnRenderClose();
273 loggingStart(function() {
274 loggingStop(function() {
280 // Starts and stops logging while auto-upload is disabled, but
281 // requests logs upload after stopping logging.
282 function testDisabledLoggingButUpload(callback
) {
283 loggingNoUploadOnRenderClose();
284 loggingStart(function() {
285 loggingStop(function() {
286 loggingUpload(function(loggingResult
) {
287 if (loggingResult
!= '') {
290 callback('Got empty upload result.');
297 // Starts logging while auto-upload is disabled. Uses the
298 // stopAndUpload function to stop, then upload, the results.
299 function testDisabledLoggingWithStopAndUpload(callback
) {
300 loggingNoUploadOnRenderClose();
301 loggingStart(function() {
302 loggingStopAndUpload(function(loggingResult
) {
303 if (loggingResult
!= '') {
306 callback('Got empty upload result.');
312 // Starts and stops logging while auto-upload is enabled, but
313 // requests logs be discarded after stopping logging.
314 function testEnabledLoggingButDiscard(callback
) {
315 loggingUploadOnRenderClose();
316 loggingStart(function() {
317 loggingStop(function() {
318 loggingDiscard(function() {
325 function testGetSinks(callback
) {
326 getSinks(function(sinks
) {
327 // Some bots may have no audio sinks installed, in which case we
328 // will get an empty list here.
333 function testGetActiveSink(callback
) {
334 getActiveSink(function(sinkId
) {
336 callback('Got empty sink ID.');
343 function testSetActiveSink(callback
) {
344 getSinks(function(sinks
) {
345 for (var i
= 0; i
< sinks
.length
; ++i
) {
346 setActiveSink(sinks
[i
].sinkId
);
352 function testGetAssociatedSink(callback
) {
353 getAssociatedSink('noSuchSourceId', function(sinkId
) {
355 callback('Got non-empty sink ID for nonexistent source ID.');
362 function testIsExtensionEnabled(callback
) {
363 isExtensionEnabled(function() {
368 function testSendingToInvalidExtension(callback
) {
369 // This test verifies that client code can always determine whether
370 // or not the component extension is available without resorting to
371 // timeouts, by sending it the 'isExtensionEnabled' message. If the
372 // extension is there, it will respond (see testIsExtensionEnabled)
373 // and if it's not, the extension framework will send a callback and
375 var NON_EXISTENT_EXTENSION_ID
= "aaaaaaagjdpnpccoofpliimaaeeeeeee";
376 window
.top
.chrome
.runtime
.sendMessage(
377 NON_EXISTENT_EXTENSION_ID
, {'method': 'isExtensionEnabled'},
379 if (window
.top
.chrome
.runtime
.lastError
.message
.indexOf(
380 'Could not establish connection') == -1) {
381 callback('lastError is not set correctly.');
388 function testStoreLog(callback
) {
389 var logId
= "mylog_id";
390 // Start by logging something.
391 loggingSetMetadata([{'bingos': 'bongos', 'smurfs': 'geburfs'}], function() {
392 loggingStart(function() {
393 loggingStop(function() {
394 loggingStore(logId
, function() {
395 loggingUploadStored(logId
, function(loggingResult
) {
396 if (loggingResult
!= '') {
399 callback('Got empty upload result.');
408 function testTimeout(callback
) {
409 // Never call the callback. Used for manually testing that the
410 // timeout logic of the test framework is correct.