Home | History | Annotate | Download | only in shill
      1 //
      2 // Copyright (C) 2015 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/icmp_session.h"
     18 
     19 #include <base/test/simple_test_tick_clock.h>
     20 #include <gtest/gtest.h>
     21 
     22 #include "shill/mock_event_dispatcher.h"
     23 #include "shill/mock_icmp.h"
     24 #include "shill/net/ip_address.h"
     25 
     26 using base::Bind;
     27 using base::Unretained;
     28 using testing::_;
     29 using testing::NiceMock;
     30 using testing::Return;
     31 using testing::StrictMock;
     32 using testing::Test;
     33 
     34 namespace shill {
     35 
     36 namespace {
     37 
     38 // Note: this header is given in network byte order, since
     39 // IcmpSession::OnEchoReplyReceived expects to receive a raw IP packet.
     40 const uint8_t kIpHeader[] = {0x45, 0x80, 0x00, 0x1c, 0x63, 0xd3, 0x00,
     41                              0x00, 0x39, 0x01, 0xcc, 0x9f, 0x4a, 0x7d,
     42                              0xe0, 0x18, 0x64, 0x6e, 0xc1, 0xea};
     43 // ICMP echo replies with 0 bytes of data and and echo ID 0. Sequence numbers
     44 // are 0x8, 0x9, and 0xa respectively to simulate replies to a sequence of sent
     45 // echo requests.
     46 const uint8_t kIcmpEchoReply1[] = {0x00, 0x00, 0xf7, 0xff,
     47                                    0x00, 0x00, 0x08, 0x00};
     48 const uint16_t kIcmpEchoReply1_SeqNum = 0x08;
     49 const uint8_t kIcmpEchoReply2[] = {0x00, 0x00, 0xf6, 0xff,
     50                                    0x00, 0x00, 0x09, 0x00};
     51 const uint16_t kIcmpEchoReply2_SeqNum = 0x09;
     52 const uint8_t kIcmpEchoReply3[] = {0x00, 0x00, 0xf5, 0xff,
     53                                    0x00, 0x00, 0x0a, 0x00};
     54 const uint16_t kIcmpEchoReply3_SeqNum = 0x0a;
     55 
     56 // This ICMP echo reply has an echo ID of 0xe, which is different from the
     57 // echo ID used in the unit tests (0).
     58 const uint8_t kIcmpEchoReplyDifferentEchoID[] = {0x00, 0x00, 0xea, 0xff,
     59                                                  0x0e, 0x00, 0x0b, 0x00};
     60 
     61 }  // namespace
     62 
     63 MATCHER_P(IsIPAddress, address, "") {
     64   // IPAddress objects don't support the "==" operator as per style, so we need
     65   // a custom matcher.
     66   return address.Equals(arg);
     67 }
     68 
     69 class IcmpSessionTest : public Test {
     70  public:
     71   IcmpSessionTest() : icmp_session_(&dispatcher_) {}
     72   virtual ~IcmpSessionTest() {}
     73 
     74   virtual void SetUp() {
     75     icmp_session_.tick_clock_ = &testing_clock_;
     76     icmp_ = new NiceMock<MockIcmp>();
     77     // Passes ownership.
     78     icmp_session_.icmp_.reset(icmp_);
     79     ON_CALL(*icmp_, IsStarted()).WillByDefault(Return(false));
     80   }
     81 
     82   virtual void TearDown() {
     83     EXPECT_CALL(*icmp_, IsStarted());
     84     IcmpSession::kNextUniqueEchoId = 0;
     85   }
     86 
     87   MOCK_METHOD1(ResultCallback, void(const IcmpSession::IcmpSessionResult&));
     88 
     89  protected:
     90   static const char kIPAddress[];
     91 
     92   void StartAndVerify(const IPAddress& destination) {
     93     EXPECT_CALL(*icmp_, IsStarted());
     94     EXPECT_CALL(*icmp_, Start()).WillOnce(Return(true));
     95     EXPECT_CALL(dispatcher_, CreateInputHandler(icmp_->socket(), _, _));
     96     EXPECT_CALL(dispatcher_, PostDelayedTask(_, GetTimeoutSeconds() * 1000));
     97     EXPECT_CALL(dispatcher_, PostTask(_));
     98     EXPECT_TRUE(Start(destination));
     99     EXPECT_TRUE(GetSeqNumToSentRecvTime()->empty());
    100     EXPECT_TRUE(GetReceivedEchoReplySeqNumbers()->empty());
    101     EXPECT_CALL(*icmp_, IsStarted()).WillRepeatedly(Return(true));
    102   }
    103 
    104   bool Start(const IPAddress& destination) {
    105     return icmp_session_.Start(
    106         destination, Bind(&IcmpSessionTest::ResultCallback, Unretained(this)));
    107   }
    108 
    109   void Stop() {
    110     icmp_session_.Stop();
    111   }
    112 
    113   bool SeqNumToSentRecvTimeContains(uint16_t seq_num) {
    114     return icmp_session_.seq_num_to_sent_recv_time_.find(seq_num) !=
    115            icmp_session_.seq_num_to_sent_recv_time_.end();
    116   }
    117 
    118   bool ReceivedEchoReplySeqNumbersContains(uint16_t seq_num) {
    119     return icmp_session_.received_echo_reply_seq_numbers_.find(seq_num) !=
    120            icmp_session_.received_echo_reply_seq_numbers_.end();
    121   }
    122 
    123   void TransmitEchoRequestTask(const IPAddress& destination,
    124                                bool transmit_request_success) {
    125     EXPECT_CALL(*icmp_, TransmitEchoRequest(IsIPAddress(destination),
    126                                             icmp_session_.echo_id_,
    127                                             GetCurrentSequenceNumber()))
    128         .WillOnce(Return(transmit_request_success));
    129     icmp_session_.TransmitEchoRequestTask(destination);
    130   }
    131 
    132   void ReportResultAndStopSession() {
    133     icmp_session_.ReportResultAndStopSession();
    134   }
    135 
    136   void VerifyIcmpSessionStopped() {
    137     EXPECT_TRUE(icmp_session_.timeout_callback_.IsCancelled());
    138     EXPECT_FALSE(icmp_session_.echo_reply_handler_);
    139   }
    140 
    141   void OnEchoReplyReceived(InputData* data) {
    142     icmp_session_.OnEchoReplyReceived(data);
    143   }
    144 
    145   IcmpSession::IcmpSessionResult GenerateIcmpResult() {
    146     return icmp_session_.GenerateIcmpResult();
    147   }
    148 
    149   std::map<uint16_t, IcmpSession::SentRecvTimePair>* GetSeqNumToSentRecvTime() {
    150     return &icmp_session_.seq_num_to_sent_recv_time_;
    151   }
    152   std::set<uint16_t>* GetReceivedEchoReplySeqNumbers() {
    153     return &icmp_session_.received_echo_reply_seq_numbers_;
    154   }
    155   uint16_t GetNextUniqueEchoId() const {
    156     return IcmpSession::kNextUniqueEchoId;
    157   }
    158   int GetTotalNumEchoRequests() const {
    159     return IcmpSession::kTotalNumEchoRequests;
    160   }
    161   int GetCurrentSequenceNumber() const {
    162     return icmp_session_.current_sequence_number_;
    163   }
    164   void SetCurrentSequenceNumber(uint16_t val) {
    165     icmp_session_.current_sequence_number_ = val;
    166   }
    167   size_t GetTimeoutSeconds() const { return IcmpSession::kTimeoutSeconds; }
    168   int GetEchoRequestIntervalSeconds() const {
    169     return IcmpSession::kEchoRequestIntervalSeconds;
    170   }
    171 
    172   MockIcmp* icmp_;
    173   StrictMock<MockEventDispatcher> dispatcher_;
    174   IcmpSession icmp_session_;
    175   base::SimpleTestTickClock testing_clock_;
    176 };
    177 
    178 const char IcmpSessionTest::kIPAddress[] = "10.0.1.1";
    179 
    180 TEST_F(IcmpSessionTest, Constructor) {
    181   // |icmp_session_| should have been assigned the value of |kNextUniqueEchoId|
    182   // on construction, and caused the value of this static variable to be
    183   // incremented.
    184   uint16_t saved_echo_id = GetNextUniqueEchoId();
    185   EXPECT_EQ(saved_echo_id - 1, icmp_session_.echo_id_);
    186 
    187   // The next IcmpSession object constructed, |session| should get the next
    188   // unique value of |kNextUniqueEchoId|, and further increment this variable.
    189   IcmpSession session(&dispatcher_);
    190   EXPECT_EQ(saved_echo_id, session.echo_id_);
    191   EXPECT_EQ(saved_echo_id + 1, GetNextUniqueEchoId());
    192 }
    193 
    194 TEST_F(IcmpSessionTest, StartWhileAlreadyStarted) {
    195   IPAddress ipv4_destination(IPAddress::kFamilyIPv4);
    196   EXPECT_TRUE(ipv4_destination.SetAddressFromString(kIPAddress));
    197   StartAndVerify(ipv4_destination);
    198 
    199   // Since an ICMP session is already started, we should fail to start it again.
    200   EXPECT_CALL(*icmp_, Start()).Times(0);
    201   EXPECT_CALL(dispatcher_, CreateInputHandler(_, _, _)).Times(0);
    202   EXPECT_CALL(dispatcher_, PostDelayedTask(_, _)).Times(0);
    203   EXPECT_CALL(dispatcher_, PostTask(_)).Times(0);
    204   EXPECT_FALSE(Start(ipv4_destination));
    205 }
    206 
    207 TEST_F(IcmpSessionTest, StopWhileNotStarted) {
    208   // Attempting to stop the ICMP session while it is not started should do
    209   // nothing.
    210   EXPECT_CALL(*icmp_, IsStarted()).WillOnce(Return(false));
    211   EXPECT_CALL(*this, ResultCallback(_)).Times(0);
    212   EXPECT_CALL(*icmp_, Stop()).Times(0);
    213   Stop();
    214 }
    215 
    216 TEST_F(IcmpSessionTest, SessionSuccess) {
    217   // Test a successful ICMP session where the sending of requests and receiving
    218   // of replies are interleaved. Moreover, test the case where transmitting an
    219   // echo request fails.
    220 
    221   base::TimeTicks now = testing_clock_.NowTicks();
    222   base::TimeTicks kSentTime1 = base::TimeTicks::FromInternalValue(10);
    223   base::TimeTicks kRecvTime1 = base::TimeTicks::FromInternalValue(20);
    224   base::TimeTicks kSentTime2 = base::TimeTicks::FromInternalValue(30);
    225   base::TimeTicks kSentTime3 = base::TimeTicks::FromInternalValue(40);
    226   base::TimeTicks kRecvTime2 = base::TimeTicks::FromInternalValue(50);
    227   base::TimeTicks kWrongEchoIDRecvTime = base::TimeTicks::FromInternalValue(60);
    228   base::TimeTicks kRecvTime3 = base::TimeTicks::FromInternalValue(70);
    229 
    230   IcmpSession::IcmpSessionResult expected_result;
    231   expected_result.push_back(kRecvTime1 - kSentTime1);
    232   expected_result.push_back(kRecvTime2 - kSentTime2);
    233   expected_result.push_back(kRecvTime3 - kSentTime3);
    234 
    235   // Initiate session.
    236   IPAddress ipv4_destination(IPAddress::kFamilyIPv4);
    237   EXPECT_TRUE(ipv4_destination.SetAddressFromString(kIPAddress));
    238   StartAndVerify(ipv4_destination);
    239 
    240   // Send the first echo request.
    241   testing_clock_.Advance(kSentTime1 - now);
    242   now = testing_clock_.NowTicks();
    243   SetCurrentSequenceNumber(kIcmpEchoReply1_SeqNum);
    244   EXPECT_CALL(dispatcher_,
    245               PostDelayedTask(_, GetEchoRequestIntervalSeconds() * 1000));
    246   TransmitEchoRequestTask(ipv4_destination, true);
    247   EXPECT_TRUE(GetReceivedEchoReplySeqNumbers()->empty());
    248   EXPECT_EQ(1, GetSeqNumToSentRecvTime()->size());
    249   EXPECT_TRUE(SeqNumToSentRecvTimeContains(kIcmpEchoReply1_SeqNum));
    250   EXPECT_EQ(now, GetSeqNumToSentRecvTime()->at(kIcmpEchoReply1_SeqNum).first);
    251   EXPECT_EQ(kIcmpEchoReply2_SeqNum, GetCurrentSequenceNumber());
    252 
    253   // Receive first reply.
    254   testing_clock_.Advance(kRecvTime1 - now);
    255   now = testing_clock_.NowTicks();
    256   uint8_t buffer_1[sizeof(kIpHeader) + sizeof(kIcmpEchoReply1)];
    257   memcpy(buffer_1, kIpHeader, sizeof(kIpHeader));
    258   memcpy(buffer_1 + sizeof(kIpHeader), kIcmpEchoReply1,
    259          sizeof(kIcmpEchoReply1));
    260   InputData data_1(reinterpret_cast<unsigned char*>(buffer_1),
    261                    sizeof(buffer_1));
    262   EXPECT_CALL(*this, ResultCallback(_)).Times(0);
    263   OnEchoReplyReceived(&data_1);
    264   EXPECT_EQ(1, GetReceivedEchoReplySeqNumbers()->size());
    265   EXPECT_TRUE(ReceivedEchoReplySeqNumbersContains(kIcmpEchoReply1_SeqNum));
    266 
    267   // Send the second echo request.
    268   testing_clock_.Advance(kSentTime2 - now);
    269   now = testing_clock_.NowTicks();
    270   EXPECT_CALL(dispatcher_,
    271               PostDelayedTask(_, GetEchoRequestIntervalSeconds() * 1000));
    272   TransmitEchoRequestTask(ipv4_destination, true);
    273   EXPECT_EQ(1, GetReceivedEchoReplySeqNumbers()->size());
    274   EXPECT_EQ(2, GetSeqNumToSentRecvTime()->size());
    275   EXPECT_TRUE(SeqNumToSentRecvTimeContains(kIcmpEchoReply2_SeqNum));
    276   EXPECT_EQ(now, GetSeqNumToSentRecvTime()->at(kIcmpEchoReply2_SeqNum).first);
    277   EXPECT_EQ(kIcmpEchoReply3_SeqNum, GetCurrentSequenceNumber());
    278 
    279   // Sending final request.
    280   testing_clock_.Advance(kSentTime3 - now);
    281   now = testing_clock_.NowTicks();
    282   EXPECT_CALL(dispatcher_, PostDelayedTask(_, _)).Times(0);
    283   EXPECT_CALL(*icmp_, Stop()).Times(0);
    284   TransmitEchoRequestTask(ipv4_destination, true);
    285   EXPECT_EQ(1, GetReceivedEchoReplySeqNumbers()->size());
    286   EXPECT_EQ(3, GetSeqNumToSentRecvTime()->size());
    287   EXPECT_TRUE(SeqNumToSentRecvTimeContains(kIcmpEchoReply3_SeqNum));
    288   EXPECT_EQ(now, GetSeqNumToSentRecvTime()->at(kIcmpEchoReply3_SeqNum).first);
    289   EXPECT_EQ(kIcmpEchoReply3_SeqNum + 1, GetCurrentSequenceNumber());
    290 
    291   // Receive second reply.
    292   testing_clock_.Advance(kRecvTime2 - now);
    293   now = testing_clock_.NowTicks();
    294   uint8_t buffer_2[sizeof(kIpHeader) + sizeof(kIcmpEchoReply2)];
    295   memcpy(buffer_2, kIpHeader, sizeof(kIpHeader));
    296   memcpy(buffer_2 + sizeof(kIpHeader), kIcmpEchoReply2,
    297          sizeof(kIcmpEchoReply2));
    298   InputData data_2(reinterpret_cast<unsigned char*>(buffer_2),
    299                    sizeof(buffer_2));
    300   EXPECT_CALL(*this, ResultCallback(_)).Times(0);
    301   EXPECT_CALL(*icmp_, Stop()).Times(0);
    302   OnEchoReplyReceived(&data_2);
    303   EXPECT_EQ(3, GetSeqNumToSentRecvTime()->size());
    304   EXPECT_EQ(2, GetReceivedEchoReplySeqNumbers()->size());
    305   EXPECT_TRUE(ReceivedEchoReplySeqNumbersContains(kIcmpEchoReply2_SeqNum));
    306 
    307   // Receive a reply that has an echo ID that does not match that of this
    308   // ICMP session. This reply will not be processed.
    309   testing_clock_.Advance(kWrongEchoIDRecvTime - now);
    310   now = testing_clock_.NowTicks();
    311   uint8_t buffer_3[sizeof(kIpHeader) + sizeof(kIcmpEchoReplyDifferentEchoID)];
    312   memcpy(buffer_3, kIpHeader, sizeof(kIpHeader));
    313   memcpy(buffer_3 + sizeof(kIpHeader), kIcmpEchoReplyDifferentEchoID,
    314          sizeof(kIcmpEchoReplyDifferentEchoID));
    315   InputData data_3(reinterpret_cast<unsigned char*>(buffer_3),
    316                    sizeof(buffer_3));
    317   EXPECT_CALL(*this, ResultCallback(_)).Times(0);
    318   EXPECT_CALL(*icmp_, Stop()).Times(0);
    319   OnEchoReplyReceived(&data_3);
    320   EXPECT_EQ(3, GetSeqNumToSentRecvTime()->size());
    321   EXPECT_EQ(2, GetReceivedEchoReplySeqNumbers()->size());
    322 
    323   // Receive third reply, which concludes the ICMP session.
    324   testing_clock_.Advance(kRecvTime3 - now);
    325   now = testing_clock_.NowTicks();
    326   uint8_t buffer_4[sizeof(kIpHeader) + sizeof(kIcmpEchoReply3)];
    327   memcpy(buffer_4, kIpHeader, sizeof(kIpHeader));
    328   memcpy(buffer_4 + sizeof(kIpHeader), kIcmpEchoReply3,
    329          sizeof(kIcmpEchoReply3));
    330   InputData data_4(reinterpret_cast<unsigned char*>(buffer_4),
    331                    sizeof(buffer_4));
    332   EXPECT_CALL(*this, ResultCallback(expected_result));
    333   EXPECT_CALL(*icmp_, Stop());
    334   OnEchoReplyReceived(&data_4);
    335   EXPECT_EQ(3, GetSeqNumToSentRecvTime()->size());
    336   EXPECT_EQ(3, GetReceivedEchoReplySeqNumbers()->size());
    337   EXPECT_TRUE(ReceivedEchoReplySeqNumbersContains(kIcmpEchoReply3_SeqNum));
    338 
    339   VerifyIcmpSessionStopped();
    340 }
    341 
    342 TEST_F(IcmpSessionTest, SessionTimeoutOrInterrupted) {
    343   // Test a failed ICMP session where we neither send out all echo requests nor
    344   // receive all echo replies before stopping the ICMP session (because of a
    345   // timeout or a manually-triggered stop). Moreover, test that echo requests
    346   // that are sent unsuccessfully are sent again.
    347 
    348   base::TimeTicks now = testing_clock_.NowTicks();
    349   base::TimeTicks kSentTime1 = base::TimeTicks::FromInternalValue(10);
    350   base::TimeTicks kSentTime2 = base::TimeTicks::FromInternalValue(20);
    351   base::TimeTicks kRecvTime1 = base::TimeTicks::FromInternalValue(30);
    352   base::TimeTicks kResendTime1 = base::TimeTicks::FromInternalValue(40);
    353 
    354   IcmpSession::IcmpSessionResult expected_partial_result;
    355   expected_partial_result.push_back(kRecvTime1 - kSentTime1);
    356   expected_partial_result.push_back(base::TimeDelta());
    357 
    358   // Initiate session.
    359   IPAddress ipv4_destination(IPAddress::kFamilyIPv4);
    360   EXPECT_TRUE(ipv4_destination.SetAddressFromString(kIPAddress));
    361   StartAndVerify(ipv4_destination);
    362 
    363   // Send the first echo request successfully.
    364   testing_clock_.Advance(kSentTime1 - now);
    365   now = testing_clock_.NowTicks();
    366   SetCurrentSequenceNumber(kIcmpEchoReply1_SeqNum);
    367   EXPECT_CALL(dispatcher_,
    368               PostDelayedTask(_, GetEchoRequestIntervalSeconds() * 1000));
    369   TransmitEchoRequestTask(ipv4_destination, true);
    370   EXPECT_TRUE(GetReceivedEchoReplySeqNumbers()->empty());
    371   EXPECT_EQ(1, GetSeqNumToSentRecvTime()->size());
    372   EXPECT_TRUE(SeqNumToSentRecvTimeContains(kIcmpEchoReply1_SeqNum));
    373   EXPECT_EQ(now, GetSeqNumToSentRecvTime()->at(kIcmpEchoReply1_SeqNum).first);
    374   EXPECT_EQ(kIcmpEchoReply2_SeqNum, GetCurrentSequenceNumber());
    375 
    376   // Send the second echo request unsuccessfully.
    377   testing_clock_.Advance(kSentTime2 - now);
    378   now = testing_clock_.NowTicks();
    379   EXPECT_CALL(dispatcher_,
    380               PostDelayedTask(_, GetEchoRequestIntervalSeconds() * 1000));
    381   TransmitEchoRequestTask(ipv4_destination, false);
    382   EXPECT_TRUE(GetReceivedEchoReplySeqNumbers()->empty());
    383   EXPECT_EQ(1, GetSeqNumToSentRecvTime()->size());
    384   EXPECT_FALSE(SeqNumToSentRecvTimeContains(kIcmpEchoReply2_SeqNum));
    385   // The sequence number should still be incremented when we fail to transmit an
    386   // echo request.
    387   EXPECT_EQ(kIcmpEchoReply3_SeqNum, GetCurrentSequenceNumber());
    388 
    389   // Receive first reply.
    390   testing_clock_.Advance(kRecvTime1 - now);
    391   now = testing_clock_.NowTicks();
    392   uint8_t buffer_1[sizeof(kIpHeader) + sizeof(kIcmpEchoReply1)];
    393   memcpy(buffer_1, kIpHeader, sizeof(kIpHeader));
    394   memcpy(buffer_1 + sizeof(kIpHeader), kIcmpEchoReply1,
    395          sizeof(kIcmpEchoReply1));
    396   InputData data_1(reinterpret_cast<unsigned char*>(buffer_1),
    397                    sizeof(buffer_1));
    398   EXPECT_CALL(*this, ResultCallback(_)).Times(0);
    399   OnEchoReplyReceived(&data_1);
    400   EXPECT_EQ(1, GetReceivedEchoReplySeqNumbers()->size());
    401   EXPECT_TRUE(ReceivedEchoReplySeqNumbersContains(kIcmpEchoReply1_SeqNum));
    402 
    403   // Resend second echo request successfully.
    404   testing_clock_.Advance(kResendTime1 - now);
    405   now = testing_clock_.NowTicks();
    406   EXPECT_CALL(dispatcher_,
    407               PostDelayedTask(_, GetEchoRequestIntervalSeconds() * 1000));
    408   TransmitEchoRequestTask(ipv4_destination, true);
    409   EXPECT_EQ(1, GetReceivedEchoReplySeqNumbers()->size());
    410   EXPECT_EQ(2, GetSeqNumToSentRecvTime()->size());
    411   EXPECT_TRUE(SeqNumToSentRecvTimeContains(kIcmpEchoReply3_SeqNum));
    412   EXPECT_EQ(now, GetSeqNumToSentRecvTime()->at(kIcmpEchoReply3_SeqNum).first);
    413   EXPECT_EQ(kIcmpEchoReply3_SeqNum + 1, GetCurrentSequenceNumber());
    414 
    415   // Timeout triggered, so report partial results.
    416   EXPECT_CALL(*this, ResultCallback(expected_partial_result));
    417   EXPECT_CALL(*icmp_, Stop());
    418   ReportResultAndStopSession();
    419   EXPECT_EQ(2, GetSeqNumToSentRecvTime()->size());
    420   EXPECT_EQ(1, GetReceivedEchoReplySeqNumbers()->size());
    421   VerifyIcmpSessionStopped();
    422 }
    423 
    424 TEST_F(IcmpSessionTest, DoNotReportResultsOnStop) {
    425   // Initiate session.
    426   IPAddress ipv4_destination(IPAddress::kFamilyIPv4);
    427   EXPECT_TRUE(ipv4_destination.SetAddressFromString(kIPAddress));
    428   StartAndVerify(ipv4_destination);
    429 
    430   // Session interrupted manually by calling Stop(), so do not report results.
    431   EXPECT_CALL(*this, ResultCallback(_)).Times(0);
    432   EXPECT_CALL(*icmp_, Stop());
    433   Stop();
    434   VerifyIcmpSessionStopped();
    435 }
    436 
    437 TEST_F(IcmpSessionTest, AnyRepliesReceived) {
    438   IcmpSession::IcmpSessionResult none_sent;
    439   EXPECT_FALSE(IcmpSession::AnyRepliesReceived(none_sent));
    440 
    441   IcmpSession::IcmpSessionResult two_sent_none_received;
    442   two_sent_none_received.push_back(base::TimeDelta());
    443   two_sent_none_received.push_back(base::TimeDelta());
    444   EXPECT_FALSE(IcmpSession::AnyRepliesReceived(two_sent_none_received));
    445 
    446   IcmpSession::IcmpSessionResult one_sent_one_received;
    447   one_sent_one_received.push_back(base::TimeDelta::FromSeconds(10));
    448   EXPECT_TRUE(IcmpSession::AnyRepliesReceived(one_sent_one_received));
    449 
    450   IcmpSession::IcmpSessionResult two_sent_one_received;
    451   two_sent_one_received.push_back(base::TimeDelta::FromSeconds(20));
    452   two_sent_one_received.push_back(base::TimeDelta());
    453   EXPECT_TRUE(IcmpSession::AnyRepliesReceived(two_sent_one_received));
    454 }
    455 
    456 TEST_F(IcmpSessionTest, IsPacketLossPercentageGreaterThan) {
    457   // If we sent no echo requests out, we expect no replies, therefore we have
    458   // 0% packet loss.
    459   IcmpSession::IcmpSessionResult none_sent_none_received;
    460   EXPECT_FALSE(IcmpSession::IsPacketLossPercentageGreaterThan(
    461       none_sent_none_received, 0));
    462 
    463   // If we receive all replies, we experience 0% packet loss.
    464   IcmpSession::IcmpSessionResult three_sent_three_received;
    465   three_sent_three_received.push_back(base::TimeDelta::FromSeconds(10));
    466   three_sent_three_received.push_back(base::TimeDelta::FromSeconds(10));
    467   three_sent_three_received.push_back(base::TimeDelta::FromSeconds(10));
    468   EXPECT_FALSE(IcmpSession::IsPacketLossPercentageGreaterThan(
    469       three_sent_three_received, 0));
    470 
    471   // If we sent 3 requests and received 2 replies, we have ~33% packet loss.
    472   IcmpSession::IcmpSessionResult three_sent_two_received;
    473   three_sent_two_received.push_back(base::TimeDelta::FromSeconds(10));
    474   three_sent_two_received.push_back(base::TimeDelta::FromSeconds(10));
    475   three_sent_two_received.push_back(base::TimeDelta());
    476   EXPECT_FALSE(IcmpSession::IsPacketLossPercentageGreaterThan(
    477       three_sent_two_received, 60));
    478   EXPECT_FALSE(IcmpSession::IsPacketLossPercentageGreaterThan(
    479       three_sent_two_received, 33));
    480   EXPECT_TRUE(IcmpSession::IsPacketLossPercentageGreaterThan(
    481       three_sent_two_received, 32));
    482   EXPECT_TRUE(IcmpSession::IsPacketLossPercentageGreaterThan(
    483       three_sent_two_received, 10));
    484 }
    485 
    486 }  // namespace shill
    487