Home | History | Annotate | Download | only in cellular
      1 //
      2 // Copyright (C) 2013 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 #include "shill/cellular/active_passive_out_of_credits_detector.h"
     18 
     19 #include <string>
     20 #include <vector>
     21 
     22 #include <gtest/gtest.h>
     23 
     24 #include "shill/cellular/mock_cellular.h"
     25 #include "shill/cellular/mock_cellular_service.h"
     26 #include "shill/cellular/mock_modem_info.h"
     27 #include "shill/mock_connection.h"
     28 #include "shill/mock_connection_health_checker.h"
     29 #include "shill/mock_device_info.h"
     30 #include "shill/mock_manager.h"
     31 #include "shill/mock_traffic_monitor.h"
     32 #include "shill/test_event_dispatcher.h"
     33 
     34 using base::Bind;
     35 using base::Unretained;
     36 using std::string;
     37 using std::vector;
     38 using testing::_;
     39 using testing::AnyNumber;
     40 using testing::Mock;
     41 using testing::NiceMock;
     42 using testing::Return;
     43 using testing::ReturnPointee;
     44 using testing::ReturnRef;
     45 using testing::StrictMock;
     46 
     47 namespace shill {
     48 
     49 class ActivePassiveOutOfCreditsDetectorTest : public testing::Test {
     50  public:
     51   ActivePassiveOutOfCreditsDetectorTest()
     52       : modem_info_(nullptr, &dispatcher_, &metrics_, &manager_),
     53         device_info_(modem_info_.control_interface(), modem_info_.dispatcher(),
     54                      modem_info_.metrics(), modem_info_.manager()),
     55         manager_(modem_info_.control_interface(), modem_info_.dispatcher(),
     56                  modem_info_.metrics()),
     57         metrics_(modem_info_.dispatcher()),
     58         cellular_(new NiceMock<MockCellular>(&modem_info_,
     59                                              "usb0",
     60                                              kAddress,
     61                                              3,
     62                                              Cellular::kTypeCDMA,
     63                                              "",
     64                                              "")),
     65         service_(new NiceMock<MockCellularService>(&modem_info_, cellular_)),
     66         connection_(new NiceMock<MockConnection>(&device_info_)),
     67         out_of_credits_detector_(
     68             new ActivePassiveOutOfCreditsDetector(
     69                 modem_info_.dispatcher(), modem_info_.manager(),
     70                 modem_info_.metrics(), service_.get())) {}
     71 
     72   virtual void SetUp() {
     73     service_->connection_ = connection_;
     74     cellular_->service_ = service_;
     75     service_->SetRoamingState(kRoamingStateHome);
     76     ON_CALL(*connection_, interface_name())
     77         .WillByDefault(ReturnRef(interface_name_));
     78     ON_CALL(*connection_, dns_servers())
     79         .WillByDefault(ReturnRef(dns_servers_));
     80     ON_CALL(manager_, GetPortalCheckURL())
     81         .WillByDefault(ReturnRef(portal_check_url_));
     82     ON_CALL(*service_, explicitly_disconnected()).WillByDefault(Return(false));
     83     ON_CALL(*service_, resume_start_time())
     84         .WillByDefault(ReturnRef(resume_start_time_));
     85   }
     86 
     87   virtual void TearDown() {
     88     cellular_->service_ = nullptr;  // Break circular reference.
     89   }
     90 
     91   void OnConnectionHealthCheckerResult(
     92       ConnectionHealthChecker::Result result) {}
     93 
     94  protected:
     95   static const char kAddress[];
     96 
     97   void SetMockServiceState(Service::ConnectState old_state,
     98                            Service::ConnectState new_state) {
     99     out_of_credits_detector_->NotifyServiceStateChanged(old_state, new_state);
    100   }
    101 
    102   void SetTrafficMonitor(TrafficMonitor* traffic_monitor) {
    103     out_of_credits_detector_->set_traffic_monitor(traffic_monitor);
    104   }
    105 
    106   void SetConnectionHealthChecker(ConnectionHealthChecker* health_checker) {
    107     out_of_credits_detector_->set_connection_health_checker(health_checker);
    108   }
    109 
    110   EventDispatcherForTest dispatcher_;
    111   MockModemInfo modem_info_;
    112   NiceMock<MockDeviceInfo> device_info_;
    113   NiceMock<MockManager> manager_;
    114   NiceMock<MockMetrics> metrics_;
    115   scoped_refptr<NiceMock<MockCellular>> cellular_;
    116   scoped_refptr<NiceMock<MockCellularService>> service_;
    117   scoped_refptr<NiceMock<MockConnection>> connection_;
    118   string interface_name_;
    119   vector<string> dns_servers_;
    120   string portal_check_url_;
    121   base::Time resume_start_time_;
    122   std::unique_ptr<ActivePassiveOutOfCreditsDetector> out_of_credits_detector_;
    123 };
    124 
    125 const char ActivePassiveOutOfCreditsDetectorTest::kAddress[] = "000102030405";
    126 
    127 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
    128     ConnectDisconnectLoopOutOfCreditsDetected) {
    129   EXPECT_CALL(*service_, Connect(_, _)).Times(2);
    130   SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
    131   SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
    132   SetMockServiceState(Service::kStateConnected, Service::kStateFailure);
    133   EXPECT_TRUE(out_of_credits_detector_->IsDetecting());
    134   dispatcher_.DispatchPendingEvents();
    135   SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
    136   SetMockServiceState(Service::kStateAssociating, Service::kStateConfiguring);
    137   SetMockServiceState(Service::kStateConfiguring, Service::kStateIdle);
    138   EXPECT_TRUE(out_of_credits_detector_->IsDetecting());
    139   dispatcher_.DispatchPendingEvents();
    140   SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
    141   SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
    142   SetMockServiceState(Service::kStateConnected, Service::kStateIdle);
    143   EXPECT_TRUE(out_of_credits_detector_->out_of_credits());
    144   EXPECT_FALSE(out_of_credits_detector_->IsDetecting());
    145 }
    146 
    147 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
    148     ConnectDisconnectLoopDetectionNotSkippedAfterSlowResume) {
    149   resume_start_time_ =
    150       base::Time::Now() -
    151       base::TimeDelta::FromSeconds(
    152       ActivePassiveOutOfCreditsDetector::kOutOfCreditsResumeIgnoreSeconds + 1);
    153   EXPECT_CALL(*service_, Connect(_, _)).Times(2);
    154   SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
    155   SetMockServiceState(Service::kStateAssociating, Service::kStateFailure);
    156   EXPECT_TRUE(out_of_credits_detector_->IsDetecting());
    157   dispatcher_.DispatchPendingEvents();
    158   SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
    159   SetMockServiceState(Service::kStateAssociating, Service::kStateConfiguring);
    160   SetMockServiceState(Service::kStateConfiguring, Service::kStateIdle);
    161   EXPECT_TRUE(out_of_credits_detector_->IsDetecting());
    162   dispatcher_.DispatchPendingEvents();
    163   SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
    164   SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
    165   SetMockServiceState(Service::kStateConnected, Service::kStateIdle);
    166   EXPECT_TRUE(out_of_credits_detector_->out_of_credits());
    167   EXPECT_FALSE(out_of_credits_detector_->IsDetecting());
    168 }
    169 
    170 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
    171     ConnectDisconnectLoopDetectionSkippedAfterResume) {
    172   resume_start_time_ = base::Time::Now();
    173   ON_CALL(*service_, resume_start_time())
    174       .WillByDefault(ReturnRef(resume_start_time_));
    175   EXPECT_CALL(*service_, Connect(_, _)).Times(0);
    176   SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
    177   SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
    178   SetMockServiceState(Service::kStateConnected, Service::kStateIdle);
    179   EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
    180   EXPECT_FALSE(out_of_credits_detector_->IsDetecting());
    181   // There should not be any pending connect requests but dispatch pending
    182   // events anyway to be sure.
    183   dispatcher_.DispatchPendingEvents();
    184 }
    185 
    186 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
    187     ConnectDisconnectLoopDetectionSkippedAlreadyOutOfCredits) {
    188   EXPECT_CALL(*service_, Connect(_, _)).Times(0);
    189   out_of_credits_detector_->ReportOutOfCredits(true);
    190   SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
    191   SetMockServiceState(Service::kStateConnected, Service::kStateIdle);
    192   EXPECT_FALSE(out_of_credits_detector_->IsDetecting());
    193   // There should not be any pending connect requests but dispatch pending
    194   // events anyway to be sure.
    195   dispatcher_.DispatchPendingEvents();
    196 }
    197 
    198 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
    199     ConnectDisconnectLoopDetectionSkippedExplicitDisconnect) {
    200   EXPECT_CALL(*service_, Connect(_, _)).Times(0);
    201   SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
    202   SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
    203   EXPECT_CALL(*service_, explicitly_disconnected()).WillOnce(Return(true));
    204   SetMockServiceState(Service::kStateConnected, Service::kStateIdle);
    205   EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
    206   EXPECT_FALSE(out_of_credits_detector_->IsDetecting());
    207   // There should not be any pending connect requests but dispatch pending
    208   // events anyway to be sure.
    209   dispatcher_.DispatchPendingEvents();
    210 }
    211 
    212 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
    213     ConnectDisconnectLoopDetectionConnectionNotDropped) {
    214   EXPECT_CALL(*service_, Connect(_, _)).Times(0);
    215   SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
    216   SetMockServiceState(Service::kStateAssociating, Service::kStateConfiguring);
    217   SetMockServiceState(Service::kStateConfiguring, Service::kStateConnected);
    218   EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
    219   EXPECT_FALSE(out_of_credits_detector_->IsDetecting());
    220   // There should not be any pending connect requests but dispatch pending
    221   // events anyway to be sure.
    222   dispatcher_.DispatchPendingEvents();
    223 }
    224 
    225 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
    226     ConnectDisconnectLoopDetectionIntermittentNetwork) {
    227   EXPECT_CALL(*service_, Connect(_, _)).Times(0);
    228   SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
    229   out_of_credits_detector_->connect_start_time_ =
    230       base::Time::Now() -
    231       base::TimeDelta::FromSeconds(
    232           ActivePassiveOutOfCreditsDetector::
    233           kOutOfCreditsConnectionDropSeconds + 1);
    234   SetMockServiceState(Service::kStateConnected, Service::kStateIdle);
    235   EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
    236   EXPECT_FALSE(out_of_credits_detector_->IsDetecting());
    237   // There should not be any pending connect requests but dispatch pending
    238   // events anyway to be sure.
    239   dispatcher_.DispatchPendingEvents();
    240 }
    241 
    242 TEST_F(ActivePassiveOutOfCreditsDetectorTest, StartTrafficMonitor) {
    243   MockTrafficMonitor* traffic_monitor = new StrictMock<MockTrafficMonitor>();
    244   SetTrafficMonitor(traffic_monitor);  // Passes ownership.
    245 
    246   // Traffic monitor should only start when the service is connected.
    247   EXPECT_CALL(*traffic_monitor, Start()).Times(1);
    248   SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
    249   Mock::VerifyAndClearExpectations(traffic_monitor);
    250 
    251   // Traffic monitor should not start for other state transitions.
    252   EXPECT_CALL(*traffic_monitor, Start()).Times(0);
    253   EXPECT_CALL(*traffic_monitor, Stop()).Times(AnyNumber());
    254   SetMockServiceState(Service::kStateConnected, Service::kStateIdle);
    255   SetMockServiceState(Service::kStateIdle, Service::kStateConfiguring);
    256   SetMockServiceState(Service::kStateConfiguring, Service::kStateFailure);
    257   SetMockServiceState(Service::kStateIdle, Service::kStateAssociating);
    258   SetMockServiceState(Service::kStateConfiguring, Service::kStatePortal);
    259   SetMockServiceState(Service::kStatePortal, Service::kStateOnline);
    260 }
    261 
    262 TEST_F(ActivePassiveOutOfCreditsDetectorTest, StopTrafficMonitor) {
    263   // Traffic monitor should stop when the service is disconnected.
    264   MockTrafficMonitor* traffic_monitor = new StrictMock<MockTrafficMonitor>();
    265   SetTrafficMonitor(traffic_monitor);  // Passes ownership.
    266   EXPECT_CALL(*traffic_monitor, Start());
    267   EXPECT_CALL(*traffic_monitor, Stop());
    268   SetMockServiceState(Service::kStateAssociating, Service::kStateConnected);
    269   SetMockServiceState(Service::kStateConnected, Service::kStateIdle);
    270   Mock::VerifyAndClearExpectations(traffic_monitor);
    271 
    272   EXPECT_CALL(*traffic_monitor, Start());
    273   EXPECT_CALL(*traffic_monitor, Stop());
    274   SetMockServiceState(Service::kStateIdle, Service::kStateConnected);
    275   SetMockServiceState(Service::kStateConnected, Service::kStateFailure);
    276   Mock::VerifyAndClearExpectations(traffic_monitor);
    277 
    278   // Need an additional call to Stop() because |traffic_monitor| destructor
    279   // will call stop.
    280   EXPECT_CALL(*traffic_monitor, Stop());
    281 }
    282 
    283 TEST_F(ActivePassiveOutOfCreditsDetectorTest, OnNoNetworkRouting) {
    284   // Make sure the connection health checker starts when there is no network
    285   // routing.
    286   EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
    287   MockConnectionHealthChecker* health_checker =
    288       new MockConnectionHealthChecker(
    289           service_->connection(),
    290           modem_info_.dispatcher(),
    291           manager_.health_checker_remote_ips(),
    292           Bind(&ActivePassiveOutOfCreditsDetectorTest::
    293                OnConnectionHealthCheckerResult,
    294                Unretained(this)));
    295   SetConnectionHealthChecker(health_checker);  // Passes ownership.
    296   EXPECT_CALL(*health_checker, Start());
    297   out_of_credits_detector_->OnNoNetworkRouting(0);
    298   EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
    299   Mock::VerifyAndClearExpectations(health_checker);
    300 
    301   // Make sure connection health checker does not start again if there is a
    302   // health check in progress.
    303   EXPECT_CALL(*health_checker, health_check_in_progress())
    304       .WillOnce(Return(true));
    305   EXPECT_CALL(*health_checker, Start()).Times(0);
    306   out_of_credits_detector_->OnNoNetworkRouting(0);
    307 }
    308 
    309 TEST_F(ActivePassiveOutOfCreditsDetectorTest,
    310     OnConnectionHealthCheckerResult) {
    311   EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
    312   EXPECT_CALL(*service_, Disconnect(_, _)).Times(0);
    313   out_of_credits_detector_->OnConnectionHealthCheckerResult(
    314       ConnectionHealthChecker::kResultUnknown);
    315   EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
    316   out_of_credits_detector_->OnConnectionHealthCheckerResult(
    317       ConnectionHealthChecker::kResultConnectionFailure);
    318   EXPECT_FALSE(out_of_credits_detector_->out_of_credits());
    319   Mock::VerifyAndClearExpectations(service_.get());
    320 
    321   EXPECT_CALL(*service_, Disconnect(_,
    322       ::testing::StrEq("out-of-credits"))).
    323           Times(1);
    324   out_of_credits_detector_->OnConnectionHealthCheckerResult(
    325       ConnectionHealthChecker::kResultCongestedTxQueue);
    326   EXPECT_TRUE(out_of_credits_detector_->out_of_credits());
    327 }
    328 
    329 }  // namespace shill
    330