0

Refactor audio API tests

Instead of using custom messages to send test reuslts from test
app to test runner for tests for API events, use standard
extensions::ResultCatcher to get results - it workss better with
chrome.test.assert methods and produces better failure messages.

Use chrome.test.listenOnce to register event listeners in tests.
Note that there is no need for chrome.test.succeed for test cases
using listenOnce - it will get called once listener is run (unless
listener function asserts, in which case test will fail).

Refactors audio/test.js - added helper methods for testing
relevant properties of devices returned by chrome.audio.getInfo to
make expectations a bit easier to specify/understand.
The refactored test are less dependent on exact order in which
audio devices are reported in device list (as the order is of no
relevance).

Review-Url: https://codereview.chromium.org/2462833002
Cr-Commit-Position: refs/heads/master@{#429678}
This commit is contained in:
tbarzic
2016-11-03 12:59:41 -07:00
committed by Commit bot
parent 664c9f34a3
commit 65dca4379e
7 changed files with 307 additions and 213 deletions
extensions
browser
test
data
api_test
audio
add_nodes
input_mute_change
output_mute_change
remove_nodes
test.js
volume_change

@ -9,13 +9,15 @@
#include "base/run_loop.h"
#include "build/build_config.h"
#include "extensions/shell/test/shell_apitest.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/result_catcher.h"
#if defined(OS_CHROMEOS)
#include "chromeos/audio/audio_devices_pref_handler_stub.h"
#include "chromeos/audio/cras_audio_handler.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/fake_cras_audio_client.h"
#endif
#include "extensions/test/extension_test_message_listener.h"
namespace extensions {
@ -149,9 +151,8 @@ IN_PROC_BROWSER_TEST_F(AudioApiTest, OnLevelChangedOutputDevice) {
EXPECT_EQ(device.id, kJabraSpeaker1.id);
// Loads background app.
ResultCatcher result_catcher;
ExtensionTestMessageListener load_listener("loaded", false);
ExtensionTestMessageListener result_listener("success", false);
result_listener.set_failure_message("failure");
ASSERT_TRUE(LoadApp("api_test/audio/volume_change"));
ASSERT_TRUE(load_listener.WaitUntilSatisfied());
@ -166,8 +167,7 @@ IN_PROC_BROWSER_TEST_F(AudioApiTest, OnLevelChangedOutputDevice) {
// Verify the background app got the OnOutputNodeVolumeChanged event
// with the expected node id and volume value.
ASSERT_TRUE(result_listener.WaitUntilSatisfied());
EXPECT_EQ("success", result_listener.message());
ASSERT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
}
IN_PROC_BROWSER_TEST_F(AudioApiTest, OnOutputMuteChanged) {
@ -186,9 +186,8 @@ IN_PROC_BROWSER_TEST_F(AudioApiTest, OnOutputMuteChanged) {
EXPECT_TRUE(cras_audio_handler_->IsOutputMuted());
// Loads background app.
ResultCatcher result_catcher;
ExtensionTestMessageListener load_listener("loaded", false);
ExtensionTestMessageListener result_listener("success", false);
result_listener.set_failure_message("failure");
ASSERT_TRUE(LoadApp("api_test/audio/output_mute_change"));
ASSERT_TRUE(load_listener.WaitUntilSatisfied());
@ -198,8 +197,7 @@ IN_PROC_BROWSER_TEST_F(AudioApiTest, OnOutputMuteChanged) {
// Verify the background app got the OnMuteChanged event
// with the expected output un-muted state.
ASSERT_TRUE(result_listener.WaitUntilSatisfied());
EXPECT_EQ("success", result_listener.message());
EXPECT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
}
IN_PROC_BROWSER_TEST_F(AudioApiTest, OnInputMuteChanged) {
@ -219,9 +217,8 @@ IN_PROC_BROWSER_TEST_F(AudioApiTest, OnInputMuteChanged) {
EXPECT_FALSE(cras_audio_handler_->IsInputMuted());
// Loads background app.
ResultCatcher result_catcher;
ExtensionTestMessageListener load_listener("loaded", false);
ExtensionTestMessageListener result_listener("success", false);
result_listener.set_failure_message("failure");
ASSERT_TRUE(LoadApp("api_test/audio/input_mute_change"));
ASSERT_TRUE(load_listener.WaitUntilSatisfied());
@ -231,8 +228,7 @@ IN_PROC_BROWSER_TEST_F(AudioApiTest, OnInputMuteChanged) {
// Verify the background app got the OnMuteChanged event
// with the expected input muted state.
ASSERT_TRUE(result_listener.WaitUntilSatisfied());
EXPECT_EQ("success", result_listener.message());
EXPECT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
}
IN_PROC_BROWSER_TEST_F(AudioApiTest, OnNodesChangedAddNodes) {
@ -247,9 +243,8 @@ IN_PROC_BROWSER_TEST_F(AudioApiTest, OnNodesChangedAddNodes) {
EXPECT_EQ(init_device_size, audio_devices.size());
// Load background app.
ResultCatcher result_catcher;
ExtensionTestMessageListener load_listener("loaded", false);
ExtensionTestMessageListener result_listener("success", false);
result_listener.set_failure_message("failure");
ASSERT_TRUE(LoadApp("api_test/audio/add_nodes"));
ASSERT_TRUE(load_listener.WaitUntilSatisfied());
@ -261,8 +256,7 @@ IN_PROC_BROWSER_TEST_F(AudioApiTest, OnNodesChangedAddNodes) {
// Verify the background app got the OnNodesChanged event
// with the new node added.
ASSERT_TRUE(result_listener.WaitUntilSatisfied());
EXPECT_EQ("success", result_listener.message());
EXPECT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
}
IN_PROC_BROWSER_TEST_F(AudioApiTest, OnNodesChangedRemoveNodes) {
@ -278,9 +272,8 @@ IN_PROC_BROWSER_TEST_F(AudioApiTest, OnNodesChangedRemoveNodes) {
EXPECT_EQ(init_device_size, audio_devices.size());
// Load background app.
ResultCatcher result_catcher;
ExtensionTestMessageListener load_listener("loaded", false);
ExtensionTestMessageListener result_listener("success", false);
result_listener.set_failure_message("failure");
ASSERT_TRUE(LoadApp("api_test/audio/remove_nodes"));
ASSERT_TRUE(load_listener.WaitUntilSatisfied());
@ -292,8 +285,7 @@ IN_PROC_BROWSER_TEST_F(AudioApiTest, OnNodesChangedRemoveNodes) {
// Verify the background app got the onNodesChanged event
// with the last node removed.
ASSERT_TRUE(result_listener.WaitUntilSatisfied());
EXPECT_EQ("success", result_listener.message());
EXPECT_TRUE(result_catcher.GetNextResult()) << result_catcher.message();
}
#endif // OS_CHROMEOS

@ -2,42 +2,46 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
chrome.audio.OnDevicesChanged.addListener(function (devices) {
if (devices.length === 3) {
if (devices[0].id != "30001" ||
devices[0].stableDeviceId != "80001" ||
devices[0].isInput != false ||
devices[0].deviceType != "USB" ||
devices[0].deviceName != "Jabra Speaker" ||
devices[0].displayName != "Jabra Speaker 1") {
console.error("Got wrong device property for device:" +
JSON.stringify(devices[0]));
chrome.test.sendMessage("failure");
}
if (devices[1].id != "30002" ||
devices[1].stableDeviceId != "80002" ||
devices[1].isInput != false ||
devices[1].deviceType != "USB" ||
devices[1].deviceName != "Jabra Speaker" ||
devices[1].displayName != "Jabra Speaker 2") {
console.error("Got wrong device property for device:" +
JSON.stringify(devices[1]));
chrome.test.sendMessage("failure");
}
if (devices[2].id != "30003" ||
devices[2].stableDeviceId != "80003" ||
devices[2].isInput != false ||
devices[2].deviceType != "HDMI" ||
devices[2].deviceName != "HDMI output" ||
devices[2].displayName != "HDA Intel MID") {
console.error("Got wrong device property for device:" +
JSON.stringify(devices[2]));
chrome.test.sendMessage("failure");
}
chrome.test.sendMessage("success");
} else {
console.error("Got unexpected OnNodesChanged event failed");
chrome.test.sendMessage("failure");
chrome.test.runTests([
function waitForDeviceChangedEventTests() {
chrome.test.listenOnce(chrome.audio.OnDevicesChanged, function(devices) {
var deviceList = devices.map(function(device) {
return {
id: device.id,
stableDeviceId: device.stableDeviceId,
isInput: device.isInput,
deviceType: device.deviceType,
deviceName: device.deviceName,
displayName: device.displayName
};
}).sort(function(lhs, rhs) {
return Number.parseInt(lhs.id) - Number.parseInt(rhs.id);
});
chrome.test.assertEq([{
id: '30001',
stableDeviceId: '80001',
isInput: false,
deviceType: 'USB',
deviceName: 'Jabra Speaker',
displayName: 'Jabra Speaker 1'
}, {
id: '30002',
stableDeviceId: '80002',
isInput: false,
deviceType: 'USB',
deviceName: 'Jabra Speaker',
displayName: 'Jabra Speaker 2'
}, {
id: '30003',
stableDeviceId: '80003',
isInput: false,
deviceType: 'HDMI',
deviceName: 'HDMI output',
displayName: 'HDA Intel MID'
}], deviceList);
});
}
});
chrome.test.sendMessage("loaded");
]);
chrome.test.sendMessage('loaded');

@ -2,13 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
chrome.audio.OnMuteChanged.addListener(function (is_input, is_muted) {
if (is_input === true && is_muted === true) {
chrome.test.sendMessage("success");
} else {
console.error("Got unexpected OnMuteChanged event is_input:" + is_input +
" is_muted:" + is_muted);
chrome.test.sendMessage("failure");
chrome.test.runTests([
function waitForMuteChangedEventTests() {
chrome.test.listenOnce(
chrome.audio.OnMuteChanged,
function(isInput, isMuted) {
chrome.test.assertTrue(isInput);
chrome.test.assertTrue(isMuted);
});
}
});
chrome.test.sendMessage("loaded");
]);
chrome.test.sendMessage('loaded');

@ -2,13 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
chrome.audio.OnMuteChanged.addListener(function (is_input, is_muted) {
if (is_input === false && is_muted === false) {
chrome.test.sendMessage("success");
} else {
console.error("Got unexpected OnMuteChanged event is_input:" + is_input +
" is_muted:" + is_muted);
chrome.test.sendMessage("failure");
chrome.test.runTests([
function waitForMuteChangedEventTests() {
chrome.test.listenOnce(
chrome.audio.OnMuteChanged,
function(isInput, isMuted) {
chrome.test.assertFalse(isInput);
chrome.test.assertFalse(isMuted);
});
}
});
chrome.test.sendMessage("loaded");
]);
chrome.test.sendMessage('loaded');

@ -2,32 +2,39 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
chrome.audio.OnDevicesChanged.addListener(function (devices) {
if (devices.length === 2) {
if (devices[0].id != "40001" ||
devices[0].stableDeviceId != "90001" ||
devices[0].isInput != true ||
devices[0].deviceType != "USB" ||
devices[0].deviceName != "Jabra Mic" ||
devices[0].displayName != "Jabra Mic 1") {
console.error("Got wrong device property for device:" +
JSON.stringify(devices[0]));
chrome.test.sendMessage("failure");
}
if (devices[1].id != "40002" ||
devices[1].stableDeviceId != "90002" ||
devices[1].isInput != true ||
devices[1].deviceType != "USB" ||
devices[1].deviceName != "Jabra Mic" ||
devices[1].displayName != "Jabra Mic 2") {
console.error("Got wrong device property for device:" +
JSON.stringify(devices[1]));
chrome.test.sendMessage("failure");
}
chrome.test.sendMessage("success");
} else {
console.error("Got unexpected OnNodesChanged event failed");
chrome.test.sendMessage("failure");
chrome.test.runTests([
function waitForDeviceChangedEventTests() {
chrome.test.listenOnce(chrome.audio.OnDevicesChanged, function (devices) {
var deviceList = devices.map(function(device) {
return {
id: device.id,
stableDeviceId: device.stableDeviceId,
isInput: device.isInput,
deviceType: device.deviceType,
deviceName: device.deviceName,
displayName: device.displayName
};
}).sort(function(lhs, rhs) {
return Number.parseInt(lhs.id) - Number.parseInt(rhs.id);
});
chrome.test.assertEq([{
id: '40001',
stableDeviceId: '90001',
isInput: true,
deviceType: 'USB',
deviceName: 'Jabra Mic',
displayName: 'Jabra Mic 1'
}, {
id: '40002',
stableDeviceId: '90002',
isInput: true,
deviceType: 'USB',
deviceName: 'Jabra Mic',
displayName: 'Jabra Mic 2'
}], deviceList);
});
}
});
chrome.test.sendMessage("loaded");
]);
chrome.test.sendMessage('loaded');

@ -2,123 +2,210 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
function verifyGetInfoOutput(outputs) {
chrome.test.assertEq("30001", outputs[0].id);
chrome.test.assertEq("Jabra Speaker: Jabra Speaker 1", outputs[0].name);
chrome.test.assertEq("30002", outputs[1].id);
chrome.test.assertEq("Jabra Speaker: Jabra Speaker 2", outputs[1].name);
chrome.test.assertEq("30003", outputs[2].id);
chrome.test.assertEq("HDMI output: HDA Intel MID", outputs[2].name);
/**
* Asserts that device property values match properties in |expectedProperties|.
* The method will *not* assert that the device contains *only* properties
* specified in expected properties.
* @param {Object} expectedProperties Expected device properties.
* @param {Object} device Device object to test.
*/
function assertDeviceMatches(expectedProperties, device) {
Object.keys(expectedProperties).forEach(function(key) {
chrome.test.assertEq(expectedProperties[key], device[key],
'Property ' + key + ' of device ' + device.id);
});
}
function verifyGetInfoInput(inputs) {
chrome.test.assertEq("40001", inputs[0].id);
chrome.test.assertEq("Jabra Mic: Jabra Mic 1", inputs[0].name);
/**
* Verifies that list of devices contains all and only devices from set of
* expected devices. If will fail the test if an unexpected device is found.
*
* @param {Object.<string, Object>} expectedDevices Expected set of test
* devices. Maps device ID to device properties.
* @param {Array.<Object>} devices List of input devices.
*/
function assertDevicesMatch(expectedDevices, devices) {
var deviceIds = {};
devices.forEach(function(device) {
chrome.test.assertFalse(!!deviceIds[device.id],
'Duplicated device id: \'' + device.id + '\'.');
deviceIds[device.id] = true;
});
chrome.test.assertEq("40002", inputs[1].id);
chrome.test.assertEq("Jabra Mic: Jabra Mic 2", inputs[1].name);
function sortedKeys(obj) {
return Object.keys(obj).sort();
}
chrome.test.assertEq(sortedKeys(expectedDevices), sortedKeys(deviceIds));
chrome.test.assertEq("40003", inputs[2].id);
chrome.test.assertEq("Webcam Mic: Logitech Webcam", inputs[2].name);
devices.forEach(function(device) {
assertDeviceMatches(expectedDevices[device.id], device);
});
}
function verifyActiveDevices(output_id, input_id) {
chrome.audio.getInfo(
chrome.test.callbackPass(function(outputInfo, inputInfo) {
var outputFound = false;
var inputFound = false;
for (var i = 0; i < outputInfo.length; ++i) {
if (outputInfo[i].isActive) {
chrome.test.assertTrue(outputInfo[i].id == output_id);
outputFound = true;
}
}
for (var i = 0; i < inputInfo.length; ++i) {
if (inputInfo[i].isActive) {
chrome.test.assertTrue(inputInfo[i].id == input_id);
inputFound = true;
}
}
chrome.test.assertTrue(outputFound);
chrome.test.assertTrue(inputFound);
}));
}
function verifyDeviceProperties(output_id, input_id,
output_props, input_props) {
chrome.audio.getInfo(
chrome.test.callbackPass(function(outputInfo, inputInfo) {
var outputFound = false;
var inputFound = false;
for (var i = 0; i < outputInfo.length; ++i) {
if (outputInfo[i].id == output_id) {
chrome.test.assertEq(output_props.volume, outputInfo[i].volume);
chrome.test.assertEq(output_props.isMuted, outputInfo[i].isMuted);
outputFound = true;
}
}
for (var i = 0; i < inputInfo.length; ++i) {
if (inputInfo[i].id == input_id) {
chrome.test.assertEq(input_props.gain, inputInfo[i].gain);
chrome.test.assertEq(input_props.isMuted, inputInfo[i].isMuted);
inputFound = true;
}
}
chrome.test.assertTrue(outputFound);
chrome.test.assertTrue(inputFound);
}));
}
function setActiveDevicesAndVerify(output_id, input_id) {
chrome.audio.setActiveDevices([output_id, input_id],
chrome.test.callbackPass(function() {
verifyActiveDevices(output_id, input_id);
}));
}
function setPropertiesAndVerify(outputInfo, inputInfo) {
var outputProps = new Object;
outputProps.isMuted = true;
outputProps.volume = 55;
chrome.audio.setProperties(outputInfo.id, outputProps,
chrome.test.callbackPass(function() {
// Once the output properties have been set, set input properties, then
// verify.
var inputProps = new Object;
inputProps.isMuted = true;
inputProps.gain = 35;
chrome.audio.setProperties(inputInfo.id, inputProps,
chrome.test.callbackPass(function() {
verifyDeviceProperties(outputInfo.id, inputInfo.id,
outputProps, inputProps);
}));
}));
/**
*
* @param {Array.<Object>} devices List of devices returned by getInfo
* @returns {Object.<string, Object>} List of devices formatted as map of
* expected devices used to assert devices match expectation.
*/
function deviceListToExpectedDevicesMap(devices) {
var expectedDevicesMap = {};
devices.forEach(function(device) {
expectedDevicesMap[device.id] = device;
});
return expectedDevicesMap;
}
chrome.test.runTests([
function getInfoTest() {
// Test output devices. Maps device ID -> tested device properties.
var kTestOutputDevices = {
'30001': {
id: '30001',
name: 'Jabra Speaker: Jabra Speaker 1'
},
'30002': {
id: '30002',
name: 'Jabra Speaker: Jabra Speaker 2'
},
'30003': {
id: '30003',
name: 'HDMI output: HDA Intel MID'
}
};
// Test input devices. Maps device ID -> tested device properties.
var kTestInputDevices = {
'40001': {
id: '40001',
name: 'Jabra Mic: Jabra Mic 1'
},
'40002': {
id: '40002',
name: 'Jabra Mic: Jabra Mic 2'
},
'40003': {
id: '40003',
name: 'Webcam Mic: Logitech Webcam'
}
};
chrome.audio.getInfo(
chrome.test.callbackPass(function(outputInfo, inputInfo) {
verifyGetInfoOutput(outputInfo);
verifyGetInfoInput(inputInfo);
}));
assertDevicesMatch(kTestOutputDevices, outputInfo);
assertDevicesMatch(kTestInputDevices, inputInfo);
}));
},
function setActiveDevicesTest() {
chrome.audio.getInfo(
chrome.test.callbackPass(function(outputInfo, inputInfo) {
setActiveDevicesAndVerify(outputInfo[2].id, inputInfo[1].id);
//Test output devices. Maps device ID -> tested device properties.
var kTestOutputDevices = {
'30001': {
id: '30001',
isActive: false
},
'30002': {
id: '30002',
isActive: false
},
'30003': {
id: '30003',
isActive: true
}
};
// Test input devices. Maps device ID -> tested device properties.
var kTestInputDevices = {
'40001': {
id: '40001',
isActive: false
},
'40002': {
id: '40002',
isActive: true
},
'40003': {
id: '40003',
isActive: false
}
};
chrome.audio.setActiveDevices([
'30003',
'40002'
], chrome.test.callbackPass(function() {
chrome.audio.getInfo(
chrome.test.callbackPass(function(outputInfo, inputInfo) {
assertDevicesMatch(kTestOutputDevices, outputInfo);
assertDevicesMatch(kTestInputDevices, inputInfo);
}));
}));
},
function setPropertiesTest() {
chrome.audio.getInfo(
chrome.test.callbackPass(function(outputInfo, inputInfo) {
setPropertiesAndVerify(outputInfo[0], inputInfo[1]);
}));
chrome.audio.getInfo(function(originalOutputInfo, originalInputInfo) {
chrome.test.assertNoLastError();
var expectedInput = deviceListToExpectedDevicesMap(originalInputInfo);
// Update expected input devices with values that should be changed in
// test.
var updatedInput = expectedInput['40002'];
chrome.test.assertFalse(updatedInput.isMuted);
chrome.test.assertFalse(updatedInput.gain === 55);
updatedInput.isMuted = true;
updatedInput.gain = 55;
var expectedOutput = deviceListToExpectedDevicesMap(originalOutputInfo);
// Update expected output devices with values that should be changed in
// test.
var updatedOutput = expectedOutput['30001'];
chrome.test.assertFalse(updatedOutput.isMuted);
chrome.test.assertFalse(updatedOutput.volume === 35);
updatedOutput.isMuted = true;
updatedOutput.volume = 35;
chrome.audio.setProperties('30001', {
isMuted: true,
volume: 35
}, chrome.test.callbackPass(function() {
chrome.audio.setProperties('40002', {
isMuted: true,
gain: 55
}, chrome.test.callbackPass(function() {
chrome.audio.getInfo(
chrome.test.callbackPass(function(outputInfo, inputInfo) {
assertDevicesMatch(expectedInput, inputInfo);
assertDevicesMatch(expectedOutput, outputInfo);
}));
}));
}));
});
},
function setPropertiesInvalidValuesTest() {
chrome.audio.getInfo(function(originalOutputInfo, originalInputInfo) {
chrome.test.assertNoLastError();
var expectedInput = deviceListToExpectedDevicesMap(originalInputInfo);
var expectedOutput = deviceListToExpectedDevicesMap(originalOutputInfo);
chrome.audio.setProperties('30001', {
isMuted: true,
// Output device - should have volume set.
gain: 55
}, chrome.test.callbackFail('Could not set properties', function() {
chrome.audio.setProperties('40002', {
isMuted: true,
// Input device - should have gain set.
volume:55
}, chrome.test.callbackFail('Could not set properties', function() {
// Assert that device properties haven't changed.
chrome.audio.getInfo(
chrome.test.callbackPass(function(outputInfo, inputInfo) {
assertDevicesMatch(expectedOutput, outputInfo);
assertDevicesMatch(expectedInput, inputInfo);
}));
}));
}));
});
}
]);

@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
chrome.audio.OnLevelChanged.addListener(function (id, level) {
if (id == 30001 && level == 60) {
chrome.test.sendMessage("success");
} else {
console.error("Got unexpected OnLevelChanged event id:" + id +
" level:" + level);
chrome.test.sendMessage("failure");
chrome.test.runTests([
function waitForLevelChangedEventTests() {
chrome.test.listenOnce(chrome.audio.OnLevelChanged, function (id, level) {
chrome.test.assertEq('30001', id);
chrome.test.assertEq(60, level);
});
}
});
chrome.test.sendMessage("loaded");
]);
chrome.test.sendMessage('loaded');