blob: dbd9460fc743a1aa202229d9d756ac38650634e3 [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <string>
#include <vector>
#include <brillo/errors/error.h>
#include <chromeos/dbus/service_constants.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "cras/dbus-proxy-mocks.h"
#include "diagnostics/cros_healthd/fetchers/audio_fetcher.h"
#include "diagnostics/cros_healthd/system/mock_context.h"
namespace diagnostics {
using ::chromeos::cros_healthd::mojom::ErrorType;
using ::testing::_;
using ::testing::DoAll;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::WithArg;
namespace {
const brillo::VariantDictionary kInactiveOutputDevice = {
{cras::kNameProperty, std::string("Inactive output device")},
{cras::kNodeVolumeProperty, static_cast<uint64_t>(10)},
{cras::kIsInputProperty, false},
{cras::kActiveProperty, false}};
const brillo::VariantDictionary kActiveOutputDevice = {
{cras::kNameProperty, std::string("Active output device")},
{cras::kNodeVolumeProperty, static_cast<uint64_t>(20)},
{cras::kIsInputProperty, false},
{cras::kActiveProperty, true},
{cras::kNumberOfUnderrunsProperty, static_cast<uint32_t>(13)},
{cras::kNumberOfSevereUnderrunsProperty, static_cast<uint32_t>(3)}};
const brillo::VariantDictionary kInactiveInputDevice = {
{cras::kNameProperty, std::string("Inactive input device")},
{cras::kNodeVolumeProperty, static_cast<uint64_t>(30)},
{cras::kIsInputProperty, true},
{cras::kActiveProperty, false}};
const brillo::VariantDictionary kActiveInputDevice = {
{cras::kNameProperty, std::string("Active input device")},
{cras::kNodeVolumeProperty, static_cast<uint64_t>(40)},
{cras::kInputNodeGainProperty, static_cast<uint32_t>(77)},
{cras::kIsInputProperty, true},
{cras::kActiveProperty, true}};
struct GetVolumeStateOutput {
bool output_mute;
bool input_mute;
bool output_user_mute;
};
} // namespace
class AudioFetcherTest : public ::testing::Test {
protected:
AudioFetcherTest() = default;
AudioFetcher* audio_fetcher() { return &audio_fetcher_; }
org::chromium::cras::ControlProxyMock* mock_cras_proxy() {
return mock_context_.mock_cras_proxy();
}
std::vector<brillo::VariantDictionary> get_node_infos_output() {
return get_node_infos_output_;
}
void append_node_infos_output(const brillo::VariantDictionary& data) {
get_node_infos_output_.push_back(data);
}
private:
MockContext mock_context_;
AudioFetcher audio_fetcher_{&mock_context_};
std::vector<brillo::VariantDictionary> get_node_infos_output_{
kInactiveOutputDevice, kInactiveInputDevice};
};
class AudioFetcherGetVolumeStateTest
: public AudioFetcherTest,
public testing::WithParamInterface<GetVolumeStateOutput> {
protected:
GetVolumeStateOutput params() const { return GetParam(); }
};
// Test that we can fetch all audio metrics correctly.
//
// This is a parameterized test, we test all possible combination of
// GetVolumeState() output.
TEST_P(AudioFetcherGetVolumeStateTest, FetchAudioInfo) {
// Add active input, output device to the mock output data
append_node_infos_output(kActiveOutputDevice);
append_node_infos_output(kActiveInputDevice);
std::string output_device_name =
brillo::GetVariantValueOrDefault<std::string>(kActiveOutputDevice,
cras::kNameProperty);
std::string input_device_name = brillo::GetVariantValueOrDefault<std::string>(
kActiveInputDevice, cras::kNameProperty);
uint64_t output_volume = brillo::GetVariantValueOrDefault<uint64_t>(
kActiveOutputDevice, cras::kNodeVolumeProperty);
uint32_t input_gain = brillo::GetVariantValueOrDefault<uint32_t>(
kActiveInputDevice, cras::kInputNodeGainProperty);
uint32_t underruns = brillo::GetVariantValueOrDefault<uint32_t>(
kActiveOutputDevice, cras::kNumberOfUnderrunsProperty);
uint32_t severe_underruns = brillo::GetVariantValueOrDefault<uint32_t>(
kActiveOutputDevice, cras::kNumberOfSevereUnderrunsProperty);
const bool output_mute = params().output_mute;
const bool input_mute = params().input_mute;
const bool output_user_mute = params().output_user_mute;
EXPECT_CALL(*mock_cras_proxy(), GetVolumeState(_, _, _, _, _, _))
.WillOnce(DoAll(SetArgPointee<1>(output_mute),
SetArgPointee<2>(input_mute),
SetArgPointee<3>(output_user_mute), Return(true)));
EXPECT_CALL(*mock_cras_proxy(), GetNodeInfos(_, _, _))
.WillOnce(DoAll(SetArgPointee<0>(get_node_infos_output()), Return(true)));
auto audio_result = audio_fetcher()->FetchAudioInfo();
ASSERT_TRUE(audio_result->is_audio_info());
const auto& audio = audio_result->get_audio_info();
EXPECT_EQ(output_mute | output_user_mute, audio->output_mute);
EXPECT_EQ(input_mute, audio->input_mute);
EXPECT_EQ(output_device_name, audio->output_device_name);
EXPECT_EQ(output_volume, audio->output_volume);
EXPECT_EQ(input_device_name, audio->input_device_name);
EXPECT_EQ(input_gain, audio->input_gain);
EXPECT_EQ(underruns, audio->underruns);
EXPECT_EQ(severe_underruns, audio->severe_underruns);
}
INSTANTIATE_TEST_SUITE_P(
,
AudioFetcherGetVolumeStateTest,
testing::Values(GetVolumeStateOutput{false, false, false},
GetVolumeStateOutput{false, false, true},
GetVolumeStateOutput{false, true, false},
GetVolumeStateOutput{false, true, true},
GetVolumeStateOutput{true, false, false},
GetVolumeStateOutput{true, false, true},
GetVolumeStateOutput{true, true, false},
GetVolumeStateOutput{true, true, true}));
// Test no active output device.
TEST_F(AudioFetcherTest, FetchAudioInfoWithoutActiveOutputDevice) {
EXPECT_CALL(*mock_cras_proxy(), GetVolumeState(_, _, _, _, _, _))
.WillOnce(DoAll(Return(true)));
EXPECT_CALL(*mock_cras_proxy(), GetNodeInfos(_, _, _))
.WillOnce(DoAll(SetArgPointee<0>(get_node_infos_output()), Return(true)));
auto audio_result = audio_fetcher()->FetchAudioInfo();
ASSERT_TRUE(audio_result->is_audio_info());
const auto& audio = audio_result->get_audio_info();
EXPECT_EQ("No active output device", audio->output_device_name);
}
// Test that when GetVolumeState fails.
TEST_F(AudioFetcherTest, FetchAudioInfoGetVolumeStateFail) {
EXPECT_CALL(*mock_cras_proxy(), GetVolumeState(_, _, _, _, _, _))
.WillOnce(DoAll(WithArg<4>(Invoke([](brillo::ErrorPtr* error) {
*error = brillo::Error::Create(FROM_HERE, "", "", "");
})),
Return(false)));
auto audio_result = audio_fetcher()->FetchAudioInfo();
ASSERT_TRUE(audio_result->is_error());
EXPECT_EQ(audio_result->get_error()->type, ErrorType::kSystemUtilityError);
}
// Test that when GetNodeInfos fails.
TEST_F(AudioFetcherTest, FetchAudioInfoGetNodeInfosFail) {
EXPECT_CALL(*mock_cras_proxy(), GetVolumeState(_, _, _, _, _, _))
.WillOnce(DoAll(Return(true)));
EXPECT_CALL(*mock_cras_proxy(), GetNodeInfos(_, _, _))
.WillOnce(DoAll(WithArg<1>(Invoke([](brillo::ErrorPtr* error) {
*error = brillo::Error::Create(FROM_HERE, "", "", "");
})),
Return(false)));
auto audio_result = audio_fetcher()->FetchAudioInfo();
ASSERT_TRUE(audio_result->is_error());
EXPECT_EQ(audio_result->get_error()->type, ErrorType::kSystemUtilityError);
}
} // namespace diagnostics