| // Copyright 2018 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 "shill/wifi/mac80211_monitor.h" |
| |
| #include <vector> |
| |
| #include <base/files/file_util.h> |
| #include <base/files/scoped_temp_dir.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #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::SetArgPointee; |
| using ::testing::StrictMock; |
| |
| namespace shill { |
| |
| namespace { |
| |
| const char kTestDeviceName[] = "test-dev"; |
| const char kJunkData[] = "junk data"; |
| |
| } // namespace |
| |
| using QState = Mac80211Monitor::QueueState; |
| |
| class Mac80211MonitorTest : public testing::Test { |
| public: |
| Mac80211MonitorTest() |
| : mac80211_monitor_(&event_dispatcher_, |
| kTestDeviceName, |
| kQueueLengthLimit, |
| base::Bind(&Mac80211MonitorTest::OnRepairHandler, |
| base::Unretained(this)), |
| &metrics_) { |
| mac80211_monitor_.time_ = &time_; |
| } |
| ~Mac80211MonitorTest() override = default; |
| |
| 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_.GetPath(), |
| &fake_queue_state_file_path_)); |
| CHECK(base::CreateTemporaryFileInDir(fake_sysfs_tree_.GetPath(), |
| &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_METHOD(void, OnRepairHandler, ()); |
| |
| // 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<QState>& 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<MockEventDispatcher> event_dispatcher_; |
| StrictMock<MockMetrics> metrics_; |
| StrictMock<MockTime> 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(SetArgPointee<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(SetArgPointee<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 |