// // Copyright (C) 2014 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // #include "shill/wifi/mac80211_monitor.h" #include #include #include #include #include #include "shill/mock_event_dispatcher.h" #include "shill/mock_log.h" #include "shill/mock_metrics.h" #include "shill/net/mock_time.h" using std::string; using std::vector; using ::testing::_; using ::testing::AnyNumber; using ::testing::DoAll; using ::testing::ElementsAre; using ::testing::HasSubstr; using ::testing::Return; using ::testing::SetArgumentPointee; using ::testing::StrictMock; namespace shill { namespace { const char kTestDeviceName[] = "test-dev"; const char kJunkData[] = "junk data"; } // namespace typedef Mac80211Monitor::QueueState QState; class Mac80211MonitorTest : public testing::Test { public: Mac80211MonitorTest() : metrics_(nullptr), mac80211_monitor_( &event_dispatcher_, kTestDeviceName, kQueueLengthLimit, base::Bind(&Mac80211MonitorTest::OnRepairHandler, base::Unretained(this)), &metrics_) { mac80211_monitor_.time_ = &time_; } virtual ~Mac80211MonitorTest() {} protected: static const size_t kQueueLengthLimit = 5; base::FilePath fake_queue_state_file_path_; // Call FakeUpSysfs() first. base::FilePath fake_wake_queues_file_path_; // Call FakeUpSysfs() first. // Getters for fixture fields. MockTime& time() { return time_; } MockEventDispatcher& event_dispatcher() { return event_dispatcher_; } MockMetrics& metrics() { return metrics_; } // Complex fixture methods. void AllowWakeQueuesIfNeededCommonCalls() { // Allow any number of these calls, as these aspects of // WakeQueuesIfNeeded interaction are tested elsewhere. EXPECT_CALL(event_dispatcher(), PostDelayedTask(_, _)) .Times(AnyNumber()); EXPECT_CALL(metrics(), SendEnumToUMA(_, _, _)) .Times(AnyNumber()); EXPECT_CALL(metrics(), SendToUMA(_, _, _, _, _)) .Times(AnyNumber()); } void FakeUpNotStuckState() { FakeUpQueueFiles("00: 0x00000000/10\n"); } void FakeUpStuckByDriverState() { FakeUpQueueFiles("00: 0x00000001/10\n"); } void FakeUpStuckByPowerSaveState() { FakeUpQueueFiles("00: 0x00000002/10\n"); } void FakeUpSysfs() { CHECK(fake_sysfs_tree_.CreateUniqueTempDir()); CHECK(base::CreateTemporaryFileInDir( fake_sysfs_tree_.path(), &fake_queue_state_file_path_)); CHECK(base::CreateTemporaryFileInDir( fake_sysfs_tree_.path(), &fake_wake_queues_file_path_)); PlumbFakeSysfs(); } void DeleteQueueStateFile() { fake_queue_state_file_path_.clear(); PlumbFakeSysfs(); } bool IsRunning() const { return mac80211_monitor_.is_running_ && !mac80211_monitor_.check_queues_callback_.IsCancelled(); } bool IsStopped() const { return !mac80211_monitor_.is_running_ && mac80211_monitor_.check_queues_callback_.IsCancelled(); } bool IsWakeQueuesFileModified() const { CHECK(fake_sysfs_tree_.IsValid()); // Keep tests hermetic. string wake_file_contents; base::ReadFileToString(fake_wake_queues_file_path_, &wake_file_contents); return wake_file_contents != kJunkData; } MOCK_METHOD0(OnRepairHandler, void()); // Getters for Mac80211Monitor state. bool GetIsDeviceConnected() const { return mac80211_monitor_.is_device_connected_; } time_t GetLastWokeQueuesMonotonicSeconds() const { return mac80211_monitor_.last_woke_queues_monotonic_seconds_; } const string& GetLinkName() const { return mac80211_monitor_.link_name_; } time_t GetMinimumTimeBetweenWakesSeconds() const { return Mac80211Monitor::kMinimumTimeBetweenWakesSeconds; } const string& GetPhyName() const { return mac80211_monitor_.phy_name_; } const base::FilePath& GetQueueStateFilePath() const { return mac80211_monitor_.queue_state_file_path_; } const base::FilePath& GetWakeQueuesFilePath() const { return mac80211_monitor_.wake_queues_file_path_; } // Pass-through methods to Mac80211Monitor methods. void StartMonitor(const string& phy_name) { EXPECT_CALL( event_dispatcher_, PostDelayedTask( _, Mac80211Monitor::kQueueStatePollIntervalSeconds * 1000)); mac80211_monitor_.Start(phy_name); if (fake_sysfs_tree_.IsValid()) { PlumbFakeSysfs(); // Re-plumb, since un-plumbed by Start(). } } void StopMonitor() { mac80211_monitor_.Stop(); } uint32_t CheckAreQueuesStuck(const vector& queue_states) { return mac80211_monitor_.CheckAreQueuesStuck(queue_states); } void UpdateConnectedState(bool new_state) { mac80211_monitor_.UpdateConnectedState(new_state); } void WakeQueuesIfNeeded() { CHECK(fake_sysfs_tree_.IsValid()); // Keep tests hermetic. mac80211_monitor_.WakeQueuesIfNeeded(); } private: base::ScopedTempDir fake_sysfs_tree_; // Call FakeUpSysfs() first. StrictMock event_dispatcher_; StrictMock metrics_; StrictMock time_; Mac80211Monitor mac80211_monitor_; void FakeUpQueueFiles(const string& queue_state_string) { CHECK(fake_sysfs_tree_.IsValid()); // Keep tests hermetic. base::WriteFile(fake_queue_state_file_path_, queue_state_string.c_str(), queue_state_string.length()); ASSERT_TRUE(base::WriteFile(fake_wake_queues_file_path_, kJunkData, strlen(kJunkData))); } void PlumbFakeSysfs() { mac80211_monitor_.queue_state_file_path_ = fake_queue_state_file_path_; mac80211_monitor_.wake_queues_file_path_ = fake_wake_queues_file_path_; } }; // Can't be in an anonymous namespace, due to ADL. // Instead, we use static to constain visibility to this unit. static bool operator==(const QState& a, const QState& b) { return a.queue_number == b.queue_number && a.stop_flags == b.stop_flags && a.queue_length == b.queue_length; } TEST_F(Mac80211MonitorTest, Ctor) { EXPECT_TRUE(IsStopped()); EXPECT_EQ(kTestDeviceName, GetLinkName()); } TEST_F(Mac80211MonitorTest, Start) { StartMonitor("test-phy"); EXPECT_TRUE(IsRunning()); EXPECT_EQ("test-phy", GetPhyName()); EXPECT_EQ("/sys/kernel/debug/ieee80211/test-phy/queues", GetQueueStateFilePath().value()); EXPECT_EQ("/sys/kernel/debug/ieee80211/test-phy/wake_queues", GetWakeQueuesFilePath().value()); EXPECT_EQ(0, GetLastWokeQueuesMonotonicSeconds()); } TEST_F(Mac80211MonitorTest, Stop) { StartMonitor("dont-care-phy"); EXPECT_TRUE(IsRunning()); StopMonitor(); EXPECT_TRUE(IsStopped()); } TEST_F(Mac80211MonitorTest, UpdateConnectedState) { UpdateConnectedState(false); EXPECT_FALSE(GetIsDeviceConnected()); UpdateConnectedState(true); EXPECT_TRUE(GetIsDeviceConnected()); // Initial state was unknown. Ensure that we can move from true to false. UpdateConnectedState(false); EXPECT_FALSE(GetIsDeviceConnected()); } TEST_F(Mac80211MonitorTest, WakeQueuesIfNeededFullMacDevice) { FakeUpSysfs(); StartMonitor("dont-care-phy"); UpdateConnectedState(false); EXPECT_CALL(event_dispatcher(), PostDelayedTask(_, _)); ScopedMockLog log; EXPECT_CALL(log, Log(_, _, HasSubstr(": incomplete read on "))).Times(0); // In case of using device with Full-Mac support, // there is no queue state file in debugfs. DeleteQueueStateFile(); WakeQueuesIfNeeded(); } TEST_F(Mac80211MonitorTest, WakeQueuesIfNeededRearmsTimerWhenDisconnected) { FakeUpSysfs(); StartMonitor("dont-care-phy"); UpdateConnectedState(false); EXPECT_CALL(event_dispatcher(), PostDelayedTask(_, _)); WakeQueuesIfNeeded(); } TEST_F(Mac80211MonitorTest, WakeQueuesIfNeededFailToReadQueueState) { FakeUpSysfs(); StartMonitor("dont-care-phy"); UpdateConnectedState(false); AllowWakeQueuesIfNeededCommonCalls(); WakeQueuesIfNeeded(); // In case we succeeded reading queue state before, but fail this time. ScopedMockLog log; EXPECT_CALL(log, Log(_, _, HasSubstr(": incomplete read on "))).Times(1); DeleteQueueStateFile(); WakeQueuesIfNeeded(); } TEST_F(Mac80211MonitorTest, WakeQueuesIfNeededRearmsTimerWhenConnected) { FakeUpSysfs(); StartMonitor("dont-care-phy"); UpdateConnectedState(true); EXPECT_CALL(event_dispatcher(), PostDelayedTask(_, _)); WakeQueuesIfNeeded(); } TEST_F(Mac80211MonitorTest, WakeQueuesIfNeededWakeNeeded) { FakeUpSysfs(); FakeUpStuckByPowerSaveState(); StartMonitor("dont-care-phy"); EXPECT_EQ(0, GetLastWokeQueuesMonotonicSeconds()); const time_t kNowMonotonicSeconds = GetMinimumTimeBetweenWakesSeconds(); EXPECT_CALL(time(), GetSecondsMonotonic(_)) .WillOnce(DoAll(SetArgumentPointee<0>(kNowMonotonicSeconds), Return(true))); EXPECT_CALL(*this, OnRepairHandler()); AllowWakeQueuesIfNeededCommonCalls(); WakeQueuesIfNeeded(); EXPECT_EQ(kNowMonotonicSeconds, GetLastWokeQueuesMonotonicSeconds()); EXPECT_TRUE(IsWakeQueuesFileModified()); } TEST_F(Mac80211MonitorTest, WakeQueuesIfNeededRateLimiting) { FakeUpSysfs(); FakeUpStuckByPowerSaveState(); StartMonitor("dont-care-phy"); EXPECT_EQ(0, GetLastWokeQueuesMonotonicSeconds()); EXPECT_CALL(time(), GetSecondsMonotonic(_)) .WillOnce(DoAll( SetArgumentPointee<0>(GetMinimumTimeBetweenWakesSeconds() - 1), Return(true))); EXPECT_CALL(*this, OnRepairHandler()).Times(0); AllowWakeQueuesIfNeededCommonCalls(); WakeQueuesIfNeeded(); EXPECT_EQ(0, GetLastWokeQueuesMonotonicSeconds()); EXPECT_FALSE(IsWakeQueuesFileModified()); } TEST_F(Mac80211MonitorTest, WakeQueuesIfNeededNotStuck) { FakeUpSysfs(); FakeUpNotStuckState(); StartMonitor("dont-care-phy"); EXPECT_EQ(0, GetLastWokeQueuesMonotonicSeconds()); EXPECT_CALL(*this, OnRepairHandler()).Times(0); AllowWakeQueuesIfNeededCommonCalls(); WakeQueuesIfNeeded(); EXPECT_EQ(0, GetLastWokeQueuesMonotonicSeconds()); EXPECT_FALSE(IsWakeQueuesFileModified()); } TEST_F(Mac80211MonitorTest, WakeQueuesIfNeededStuckByDriver) { FakeUpSysfs(); FakeUpStuckByDriverState(); StartMonitor("dont-care-phy"); EXPECT_EQ(0, GetLastWokeQueuesMonotonicSeconds()); EXPECT_CALL(*this, OnRepairHandler()).Times(0); AllowWakeQueuesIfNeededCommonCalls(); WakeQueuesIfNeeded(); EXPECT_EQ(0, GetLastWokeQueuesMonotonicSeconds()); EXPECT_FALSE(IsWakeQueuesFileModified()); } TEST_F(Mac80211MonitorTest, ParseQueueStateSimple) { // Single queue. EXPECT_THAT(Mac80211Monitor::ParseQueueState("00: 0x00000000/0\n"), ElementsAre(QState(0, 0, 0))); // Multiple queues, non-empty. EXPECT_THAT( Mac80211Monitor::ParseQueueState( "00: 0x00000000/10\n" "01: 0x00000000/20\n"), ElementsAre(QState(0, 0, 10), QState(1, 0, 20))); } TEST_F(Mac80211MonitorTest, ParseQueueStateStopped) { // Single queue, stopped for various reasons. EXPECT_THAT( Mac80211Monitor::ParseQueueState("00: 0x00000001/10\n"), ElementsAre(QState(0, Mac80211Monitor::kStopFlagDriver, 10))); EXPECT_THAT( Mac80211Monitor::ParseQueueState("00: 0x00000003/10\n"), ElementsAre(QState(0, Mac80211Monitor::kStopFlagDriver | Mac80211Monitor::kStopFlagPowerSave, 10))); EXPECT_THAT( Mac80211Monitor::ParseQueueState("00: 0x00000007/10\n"), ElementsAre(QState(0, Mac80211Monitor::kStopFlagDriver | Mac80211Monitor::kStopFlagPowerSave | Mac80211Monitor::kStopFlagChannelSwitch, 10))); EXPECT_THAT( Mac80211Monitor::ParseQueueState("00: 0x0000000f/10\n"), ElementsAre(QState(0, Mac80211Monitor::kStopFlagDriver | Mac80211Monitor::kStopFlagPowerSave | Mac80211Monitor::kStopFlagChannelSwitch | Mac80211Monitor::kStopFlagAggregation, 10))); EXPECT_THAT( Mac80211Monitor::ParseQueueState("00: 0x0000001f/10\n"), ElementsAre(QState(0, Mac80211Monitor::kStopFlagDriver | Mac80211Monitor::kStopFlagPowerSave | Mac80211Monitor::kStopFlagChannelSwitch | Mac80211Monitor::kStopFlagAggregation | Mac80211Monitor::kStopFlagSuspend, 10))); EXPECT_THAT( Mac80211Monitor::ParseQueueState("00: 0x0000003f/10\n"), ElementsAre(QState(0, Mac80211Monitor::kStopFlagDriver | Mac80211Monitor::kStopFlagPowerSave | Mac80211Monitor::kStopFlagChannelSwitch | Mac80211Monitor::kStopFlagAggregation | Mac80211Monitor::kStopFlagSuspend | Mac80211Monitor::kStopFlagBufferAdd, 10))); EXPECT_THAT( Mac80211Monitor::ParseQueueState("00: 0x0000007f/10\n"), ElementsAre(QState(0, Mac80211Monitor::kStopFlagDriver | Mac80211Monitor::kStopFlagPowerSave | Mac80211Monitor::kStopFlagChannelSwitch | Mac80211Monitor::kStopFlagAggregation | Mac80211Monitor::kStopFlagSuspend | Mac80211Monitor::kStopFlagBufferAdd | Mac80211Monitor::kStopFlagChannelTypeChange, 10))); } TEST_F(Mac80211MonitorTest, ParseQueueStateBadInput) { // Empty input -> Empty output. EXPECT_TRUE(Mac80211Monitor::ParseQueueState("").empty()); // Missing queue length for queue 0. EXPECT_THAT( Mac80211Monitor::ParseQueueState( "00: 0x00000000\n" "01: 0xffffffff/10\n"), ElementsAre(QState(1, 0xffffffff, 10))); // Missing flags for queue 0. EXPECT_THAT( Mac80211Monitor::ParseQueueState( "00: 0\n" "01: 0xffffffff/10\n"), ElementsAre(QState(1, 0xffffffff, 10))); // Bad number for queue 0. EXPECT_THAT( Mac80211Monitor::ParseQueueState( "aa: 0xabcdefgh/0\n" "01: 0xffffffff/10\n"), ElementsAre(QState(1, 0xffffffff, 10))); // Bad flags for queue 0. EXPECT_THAT( Mac80211Monitor::ParseQueueState( "00: 0xabcdefgh/0\n" "01: 0xffffffff/10\n"), ElementsAre(QState(1, 0xffffffff, 10))); // Bad length for queue 0. EXPECT_THAT( Mac80211Monitor::ParseQueueState( "00: 0x00000000/-1\n" "01: 0xffffffff/10\n"), ElementsAre(QState(1, 0xffffffff, 10))); } TEST_F(Mac80211MonitorTest, CheckAreQueuesStuckNotStuck) { EXPECT_FALSE(CheckAreQueuesStuck({})); EXPECT_FALSE(CheckAreQueuesStuck({QState(0, 0, 0)})); // Not stuck when queue length is below limit. EXPECT_FALSE(CheckAreQueuesStuck({ QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit-1)})); } TEST_F(Mac80211MonitorTest, CheckAreQueuesStuckSingleReason) { EXPECT_CALL(metrics(), SendEnumToUMA( Metrics::kMetricWifiStoppedTxQueueReason, Mac80211Monitor::kStopReasonDriver, Mac80211Monitor::kStopReasonMax)); EXPECT_CALL(metrics(), SendEnumToUMA( Metrics::kMetricWifiStoppedTxQueueReason, Mac80211Monitor::kStopReasonPowerSave, Mac80211Monitor::kStopReasonMax)); EXPECT_CALL(metrics(), SendToUMA( Metrics::kMetricWifiStoppedTxQueueLength, kQueueLengthLimit, Metrics::kMetricWifiStoppedTxQueueLengthMin, Metrics::kMetricWifiStoppedTxQueueLengthMax, Metrics::kMetricWifiStoppedTxQueueLengthNumBuckets)).Times(2); EXPECT_EQ(Mac80211Monitor::kStopFlagDriver, CheckAreQueuesStuck({ QState(0, Mac80211Monitor::kStopFlagDriver, kQueueLengthLimit)})); EXPECT_EQ(Mac80211Monitor::kStopFlagPowerSave, CheckAreQueuesStuck({ QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit)})); } TEST_F(Mac80211MonitorTest, CheckAreQueuesStuckMultipleReasons) { EXPECT_CALL(metrics(), SendEnumToUMA( Metrics::kMetricWifiStoppedTxQueueReason, Mac80211Monitor::kStopReasonPowerSave, Mac80211Monitor::kStopReasonMax)).Times(2); EXPECT_CALL(metrics(), SendEnumToUMA( Metrics::kMetricWifiStoppedTxQueueReason, Mac80211Monitor::kStopReasonDriver, Mac80211Monitor::kStopReasonMax)).Times(2); EXPECT_CALL(metrics(), SendEnumToUMA( Metrics::kMetricWifiStoppedTxQueueReason, Mac80211Monitor::kStopReasonChannelSwitch, Mac80211Monitor::kStopReasonMax)).Times(2); EXPECT_CALL(metrics(), SendToUMA( Metrics::kMetricWifiStoppedTxQueueLength, kQueueLengthLimit, Metrics::kMetricWifiStoppedTxQueueLengthMin, Metrics::kMetricWifiStoppedTxQueueLengthMax, Metrics::kMetricWifiStoppedTxQueueLengthNumBuckets)).Times(3); EXPECT_EQ(Mac80211Monitor::kStopFlagDriver | Mac80211Monitor::kStopFlagPowerSave, CheckAreQueuesStuck({ QState(0, Mac80211Monitor::kStopFlagDriver | Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit)})); EXPECT_EQ(Mac80211Monitor::kStopFlagPowerSave | Mac80211Monitor::kStopFlagChannelSwitch, CheckAreQueuesStuck({ QState(0, Mac80211Monitor::kStopFlagPowerSave | Mac80211Monitor::kStopFlagChannelSwitch, kQueueLengthLimit)})); EXPECT_EQ(Mac80211Monitor::kStopFlagDriver | Mac80211Monitor::kStopFlagChannelSwitch, CheckAreQueuesStuck({ QState(0, Mac80211Monitor::kStopFlagDriver | Mac80211Monitor::kStopFlagChannelSwitch, kQueueLengthLimit)})); } TEST_F(Mac80211MonitorTest, CheckAreQueuesStuckMultipleQueues) { EXPECT_CALL(metrics(), SendEnumToUMA( Metrics::kMetricWifiStoppedTxQueueReason, Mac80211Monitor::kStopReasonPowerSave, Mac80211Monitor::kStopReasonMax)).Times(5); EXPECT_CALL(metrics(), SendEnumToUMA( Metrics::kMetricWifiStoppedTxQueueReason, Mac80211Monitor::kStopReasonDriver, Mac80211Monitor::kStopReasonMax)).Times(2); EXPECT_CALL(metrics(), SendToUMA( Metrics::kMetricWifiStoppedTxQueueLength, kQueueLengthLimit, Metrics::kMetricWifiStoppedTxQueueLengthMin, Metrics::kMetricWifiStoppedTxQueueLengthMax, Metrics::kMetricWifiStoppedTxQueueLengthNumBuckets)).Times(5); EXPECT_EQ(Mac80211Monitor::kStopFlagPowerSave, CheckAreQueuesStuck({ QState(0, 0, 0), QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit)})); EXPECT_EQ(Mac80211Monitor::kStopFlagPowerSave, CheckAreQueuesStuck({ QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit), QState(0, 0, 0)})); EXPECT_EQ(Mac80211Monitor::kStopFlagPowerSave, CheckAreQueuesStuck({ QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit), QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit)})); EXPECT_EQ(Mac80211Monitor::kStopFlagDriver | Mac80211Monitor::kStopFlagPowerSave, CheckAreQueuesStuck({ QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit), QState(0, Mac80211Monitor::kStopFlagDriver, kQueueLengthLimit)})); EXPECT_EQ(Mac80211Monitor::kStopFlagDriver | Mac80211Monitor::kStopFlagPowerSave, CheckAreQueuesStuck({ QState(0, Mac80211Monitor::kStopFlagDriver, kQueueLengthLimit), QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit)})); } TEST_F(Mac80211MonitorTest, CheckAreQueuesStuckQueueLength) { EXPECT_CALL(metrics(), SendEnumToUMA( Metrics::kMetricWifiStoppedTxQueueReason, Mac80211Monitor::kStopReasonPowerSave, Mac80211Monitor::kStopReasonMax)).Times(4); EXPECT_CALL(metrics(), SendToUMA( Metrics::kMetricWifiStoppedTxQueueLength, kQueueLengthLimit, Metrics::kMetricWifiStoppedTxQueueLengthMin, Metrics::kMetricWifiStoppedTxQueueLengthMax, Metrics::kMetricWifiStoppedTxQueueLengthNumBuckets)).Times(4); EXPECT_TRUE(CheckAreQueuesStuck({ QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit)})); EXPECT_TRUE(CheckAreQueuesStuck({ QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit-2), QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit-1), QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit)})); EXPECT_TRUE(CheckAreQueuesStuck({ QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit), QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit-1), QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit-2)})); EXPECT_TRUE(CheckAreQueuesStuck({ QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit-1), QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit), QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit-2)})); } TEST_F(Mac80211MonitorTest, CheckAreQueuesStuckQueueLengthIgnoresUnstopped) { EXPECT_CALL(metrics(), SendEnumToUMA( Metrics::kMetricWifiStoppedTxQueueReason, Mac80211Monitor::kStopReasonPowerSave, Mac80211Monitor::kStopReasonMax)); EXPECT_CALL(metrics(), SendToUMA( Metrics::kMetricWifiStoppedTxQueueLength, kQueueLengthLimit, Metrics::kMetricWifiStoppedTxQueueLengthMin, Metrics::kMetricWifiStoppedTxQueueLengthMax, Metrics::kMetricWifiStoppedTxQueueLengthNumBuckets)); EXPECT_TRUE(CheckAreQueuesStuck({ QState(0, 0, kQueueLengthLimit * 10), QState(0, Mac80211Monitor::kStopFlagPowerSave, kQueueLengthLimit)})); } } // namespace shill