| // Copyright (c) 2014 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/mac80211_monitor.h" |
| |
| #include <vector> |
| |
| #include <base/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_metrics.h" |
| #include "shill/mock_time.h" |
| |
| using std::string; |
| using std::vector; |
| using ::testing::_; |
| using ::testing::AnyNumber; |
| using ::testing::DoAll; |
| using ::testing::ElementsAre; |
| using ::testing::Return; |
| using ::testing::SetArgumentPointee; |
| using ::testing::StrictMock; |
| |
| namespace shill { |
| |
| namespace { |
| static const char kTestDeviceName[] = "test-dev"; |
| static const char kJunkData[] = "junk data"; |
| } |
| |
| 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_) { |
| ON_CALL(event_dispatcher_, PostDelayedTask(_, _)) |
| .WillByDefault(Return(true)); |
| 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(); |
| } |
| 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<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, WakeQueuesIfNeededRearmsTimerWhenDisconnected) { |
| FakeUpSysfs(); |
| StartMonitor("dont-care-phy"); |
| UpdateConnectedState(false); |
| EXPECT_CALL(event_dispatcher(), PostDelayedTask(_, _)); |
| 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 |