chromium/chromeos/ash/components/network/network_sms_handler_unittest.cc

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/ash/components/network/network_sms_handler.h"

#include <memory>
#include <set>
#include <string>

#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/task_environment.h"
#include "base/values.h"
#include "chromeos/ash/components/dbus/shill/fake_sms_client.h"
#include "chromeos/ash/components/dbus/shill/modem_messaging_client.h"
#include "chromeos/ash/components/dbus/shill/shill_clients.h"
#include "chromeos/ash/components/dbus/shill/shill_device_client.h"
#include "chromeos/ash/components/dbus/shill/shill_service_client.h"
#include "chromeos/dbus/constants/dbus_switches.h"
#include "dbus/object_path.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
#include "third_party/cros_system_api/dbus/shill/dbus-constants.h"

namespace ash {

namespace {

const char kCellularDevicePath[] = "/org/freedesktop/ModemManager1/stub/0";
const char kCellularDeviceObjectPath1[] =
    "/org/freedesktop/ModemManager1/stub/0/Modem/0";
const char kCellularDeviceObjectPath2[] =
    "/org/freedesktop/ModemManager1/stub/0/Modem/1";
const char kSmsPath[] = "/SMS/0";
constexpr char kTestCellularServicePath1[] = "/service/stub/0";
constexpr char kTestCellularServicePath2[] = "/service/stub/1";
constexpr char kTestGuid1[] = "1";
constexpr char kTestGuid2[] = "2";
constexpr char kTestIccid1[] = "000000000000000000";
constexpr char kTestIccid2[] = "000000000000000001";

class TestObserver : public NetworkSmsHandler::Observer {
 public:
  TestObserver() = default;
  ~TestObserver() override = default;

  void MessageReceived(const base::Value::Dict& message) override {
    const std::string* text = message.FindString(NetworkSmsHandler::kTextKey);
    if (text)
      messages_.insert(*text);
  }

  void MessageReceivedFromNetwork(const std::string& guid,
                                  const TextMessageData& mesage_data) override {
    if (mesage_data.text.has_value()) {
      messages_.insert(*mesage_data.text);
      guid_messages_map_[guid].insert(*mesage_data.text);
    }
    if (mesage_data.number.has_value()) {
      EXPECT_EQ(FakeSMSClient::kNumber, *mesage_data.number);
    }

    if (mesage_data.timestamp.has_value()) {
      EXPECT_EQ(FakeSMSClient::kTimestamp, *mesage_data.timestamp);
    }
  }

  void ClearMessages() {
    messages_.clear();
    guid_messages_map_.clear();
  }

  // Returns the count for messages received across all cellular networks.
  int message_count() { return messages_.size(); }

  // Returns all received messages.
  const std::set<std::string>& messages() const {
    return messages_;
  }

  // Returns messages for the network with the given |guid|.
  const std::set<std::string>& messages(const std::string& guid) {
    return guid_messages_map_[guid];
  }

 private:
  std::set<std::string> messages_;
  base::flat_map<std::string, std::set<std::string>> guid_messages_map_;
};

}  // namespace

class NetworkSmsHandlerTest : public testing::Test {
 public:
  NetworkSmsHandlerTest()
      : task_environment_(
            base::test::SingleThreadTaskEnvironment::MainThreadType::UI,
            base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}
  ~NetworkSmsHandlerTest() override = default;

  void SetUp() override {
    // Append '--sms-test-messages' to the command line to tell
    // SMSClientStubImpl to generate a series of test SMS messages.
    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
    command_line->AppendSwitch(chromeos::switches::kSmsTestMessages);

    shill_clients::InitializeFakes();
    fake_sms_client_ = static_cast<FakeSMSClient*>(SMSClient::Get());
    device_test_ = ShillDeviceClient::Get()->GetTestInterface();
    ASSERT_TRUE(device_test_);
    service_test_ = ShillServiceClient::Get()->GetTestInterface();
    // We want to have only 1 cellular device.
    device_test_->ClearDevices();
    device_test_->AddDevice(kCellularDevicePath, shill::kTypeCellular,
                            "stub_cellular_device2");
    device_test_->SetDeviceProperty(
        kCellularDevicePath, shill::kDBusObjectProperty,
        base::Value(kCellularDeviceObjectPath1), /*notify_changed=*/false);
    SetupCellularModem(kCellularDeviceObjectPath1, kTestCellularServicePath1,
                       kTestGuid1, kTestIccid1, shill::kStateOnline);
    modem_messaging_test_ = ModemMessagingClient::Get()->GetTestInterface();

    // This relies on the stub dbus implementations for ShillManagerClient,
    // ShillDeviceClient, ModemMessagingClient and SMSClient.
    network_sms_handler_.reset(new NetworkSmsHandler());
    network_state_handler_ = NetworkStateHandler::InitializeForTest();
      network_sms_handler_->Init(network_state_handler_.get());

    test_observer_ = std::make_unique<TestObserver>();
    network_sms_handler_->AddObserver(test_observer_.get());
    network_sms_handler_->RequestUpdate();
    base::RunLoop().RunUntilIdle();
  }

  void TearDown() override {
    network_sms_handler_->RemoveObserver(test_observer_.get());
    network_sms_handler_.reset();
    network_state_handler_.reset();
    service_test_ = nullptr;  // Destroyed by shill_clients::Shutdown() below.
    shill_clients::Shutdown();
  }

  void ReceiveSms(const dbus::ObjectPath& object_path,
                  const dbus::ObjectPath& sms_path) {
    modem_messaging_test_->ReceiveSms(object_path, sms_path);
  }

  void CompleteReceiveSms() { fake_sms_client_->CompleteGetAll(); }

  void FastForwardReceiveSmsTimeout() {
    task_environment_.FastForwardBy(NetworkSmsHandler::kFetchSmsDetailsTimeout);
  }

  void SetupCellularModem(const std::string& object_path,
                          const std::string& service_path,
                          const std::string& guid,
                          const std::string& iccid,
                          const std::string& state) {
    device_test_->SetDeviceProperty(
        kCellularDevicePath, shill::kDBusObjectProperty,
        base::Value(object_path), /*notify_changed=*/true);
    device_test_->SetDeviceProperty(kCellularDevicePath, shill::kIccidProperty,
                                    base::Value(iccid),
                                    /*notify_changed=*/true);
    service_test_->AddService(service_path, guid, "", shill::kTypeCellular,
                              state,
                              /*visible=*/true);
    service_test_->SetServiceProperty(service_path, shill::kIccidProperty,
                                      base::Value(iccid));
  }

  void UpdateNetworkState(const std::string& service_path,
                          const std::string& state) {
    service_test_->SetServiceProperty(service_path, shill::kStateProperty,
                                      base::Value(state));
  }

 protected:
  base::test::SingleThreadTaskEnvironment task_environment_;
  raw_ptr<ShillDeviceClient::TestInterface, DanglingUntriaged> device_test_;
  raw_ptr<ModemMessagingClient::TestInterface, DanglingUntriaged>
      modem_messaging_test_;
  raw_ptr<ShillServiceClient::TestInterface> service_test_;
  std::unique_ptr<NetworkSmsHandler> network_sms_handler_;
  std::unique_ptr<TestObserver> test_observer_;

 private:
  std::unique_ptr<NetworkStateHandler> network_state_handler_;
  base::test::ScopedFeatureList features_;
  raw_ptr<FakeSMSClient, DanglingUntriaged> fake_sms_client_;
};

TEST_F(NetworkSmsHandlerTest, DbusStub) {
  EXPECT_EQ(test_observer_->message_count(), 0);

  // Test that no messages have been received yet
  const std::set<std::string>& messages(test_observer_->messages());
  // Note: The following string corresponds to values in
  // ModemMessagingClientStubImpl and SmsClientStubImpl.
  // TODO(stevenjb): Use a TestInterface to set this up to remove dependency.
  const char kMessage1[] = "FakeSMSClient: Test Message: /SMS/0";
  EXPECT_FALSE(base::Contains(messages, kMessage1));

  // Test for messages delivered by signals.
  test_observer_->ClearMessages();
  EXPECT_TRUE(modem_messaging_test_->GetPendingDeleteRequestSmsPath().empty());
  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath1),
             dbus::ObjectPath(kSmsPath));
  CompleteReceiveSms();
  base::RunLoop().RunUntilIdle();

  network_sms_handler_->RequestUpdate();
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(test_observer_->message_count(), 1);
  EXPECT_TRUE(base::Contains(messages, kMessage1));

  // There should be a request to delete the message after the message has been
  // received. Complete the request.
  EXPECT_EQ(kSmsPath, modem_messaging_test_->GetPendingDeleteRequestSmsPath());
  modem_messaging_test_->CompletePendingDeleteRequest(/*success=*/true);
  base::RunLoop().RunUntilIdle();

  // There should be no more messages to delete.
  EXPECT_TRUE(modem_messaging_test_->GetPendingDeleteRequestSmsPath().empty());

  // Receive two more messages. We shouldn't attempt to delete messages until
  // after we've finished receiving all messages.
  const std::string sms_path_1 = "/SMS/1";
  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath1),
             dbus::ObjectPath(sms_path_1));
  EXPECT_TRUE(modem_messaging_test_->GetPendingDeleteRequestSmsPath().empty());
  const std::string sms_path_2 = "/SMS/2";
  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath1),
             dbus::ObjectPath(sms_path_2));
  EXPECT_TRUE(modem_messaging_test_->GetPendingDeleteRequestSmsPath().empty());

  // Simulate no more messages being received. The last SMS added should be the
  // first one attempted to be deleted.
  CompleteReceiveSms();
  base::RunLoop().RunUntilIdle();
  CompleteReceiveSms();
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(sms_path_2,
            modem_messaging_test_->GetPendingDeleteRequestSmsPath());
  network_sms_handler_->RequestUpdate();
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(test_observer_->message_count(), 3);

  // Complete the deletion, another delete request should occur.
  modem_messaging_test_->CompletePendingDeleteRequest(/*success=*/true);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(sms_path_1,
            modem_messaging_test_->GetPendingDeleteRequestSmsPath());

  // Receive another message before completing the delete request.
  const std::string sms_path_3 = "/SMS/3";
  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath1),
             dbus::ObjectPath(sms_path_3));
  CompleteReceiveSms();
  EXPECT_EQ(sms_path_1,
            modem_messaging_test_->GetPendingDeleteRequestSmsPath());
  network_sms_handler_->RequestUpdate();
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(test_observer_->message_count(), 4);

  // Complete the deletion, the last delete request should occur.
  EXPECT_EQ(sms_path_1,
            modem_messaging_test_->GetPendingDeleteRequestSmsPath());
  modem_messaging_test_->CompletePendingDeleteRequest(/*success=*/true);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(sms_path_3,
            modem_messaging_test_->GetPendingDeleteRequestSmsPath());

  // Complete the last delete request.
  modem_messaging_test_->CompletePendingDeleteRequest(/*success=*/true);
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(modem_messaging_test_->GetPendingDeleteRequestSmsPath().empty());
  network_sms_handler_->RequestUpdate();
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(test_observer_->message_count(), 4);
}

TEST_F(NetworkSmsHandlerTest, DeleteFailure) {
  EXPECT_EQ(test_observer_->message_count(), 0);

  // Test that no messages have been received yet
  const std::set<std::string>& messages(test_observer_->messages());
  // Note: The following string corresponds to values in
  // ModemMessagingClientStubImpl and SmsClientStubImpl.
  const char kMessage1[] = "FakeSMSClient: Test Message: /SMS/0";
  EXPECT_FALSE(base::Contains(messages, kMessage1));

  // Test for messages delivered by signals.
  test_observer_->ClearMessages();
  EXPECT_TRUE(modem_messaging_test_->GetPendingDeleteRequestSmsPath().empty());
  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath1),
             dbus::ObjectPath(kSmsPath));
  CompleteReceiveSms();
  base::RunLoop().RunUntilIdle();

  network_sms_handler_->RequestUpdate();
  base::RunLoop().RunUntilIdle();
  EXPECT_GE(test_observer_->message_count(), 1);
  EXPECT_TRUE(base::Contains(messages, kMessage1));

  // There should be a request to delete the message after the message has been
  // received.
  EXPECT_EQ(kSmsPath, modem_messaging_test_->GetPendingDeleteRequestSmsPath());

  // Simulate the deletion failing. The delete request should be placed back in
  // the queue, but not invoked.
  modem_messaging_test_->CompletePendingDeleteRequest(/*success=*/false);
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(modem_messaging_test_->GetPendingDeleteRequestSmsPath().empty());

  // Receive two more messages. We shouldn't attempt to delete messages until
  // after we've finished receiving all messages.
  const std::string sms_path_1 = "/SMS/1";
  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath1),
             dbus::ObjectPath(sms_path_1));
  EXPECT_TRUE(modem_messaging_test_->GetPendingDeleteRequestSmsPath().empty());
  const std::string sms_path_2 = "/SMS/2";
  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath1),
             dbus::ObjectPath(sms_path_2));
  EXPECT_TRUE(modem_messaging_test_->GetPendingDeleteRequestSmsPath().empty());

  // Simulate no more messages being received. The last SMS added should be the
  // first one attempted to be deleted.
  CompleteReceiveSms();
  base::RunLoop().RunUntilIdle();
  CompleteReceiveSms();
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(sms_path_2,
            modem_messaging_test_->GetPendingDeleteRequestSmsPath());
  network_sms_handler_->RequestUpdate();
  base::RunLoop().RunUntilIdle();
  EXPECT_GE(test_observer_->message_count(), 3);

  // Simulate the deletion failing, the SMS should be placed back in the queue,
  // but no deletion invoked.
  modem_messaging_test_->CompletePendingDeleteRequest(/*success=*/false);
  base::RunLoop().RunUntilIdle();
  EXPECT_TRUE(modem_messaging_test_->GetPendingDeleteRequestSmsPath().empty());

  // Receive another message, it should be the first message attempted to be
  // deleted.
  const std::string sms_path_3 = "/SMS/3";
  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath1),
             dbus::ObjectPath(sms_path_3));
  CompleteReceiveSms();
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(sms_path_3,
            modem_messaging_test_->GetPendingDeleteRequestSmsPath());
  network_sms_handler_->RequestUpdate();
  base::RunLoop().RunUntilIdle();
  EXPECT_GE(test_observer_->message_count(), 4);

  // Simulate the deletion succeeding, the second SMS should be attempted to be
  // deleted.
  EXPECT_EQ(sms_path_3,
            modem_messaging_test_->GetPendingDeleteRequestSmsPath());
  modem_messaging_test_->CompletePendingDeleteRequest(/*success=*/true);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(sms_path_1,
            modem_messaging_test_->GetPendingDeleteRequestSmsPath());

  // Simulate the deletion succeeding, the first SMS should be attempted to be
  // deleted.
  modem_messaging_test_->CompletePendingDeleteRequest(/*success=*/true);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(kSmsPath, modem_messaging_test_->GetPendingDeleteRequestSmsPath());

  // Simulate the deletion succeeding, the third SMS should be attempted to be
  // deleted.
  modem_messaging_test_->CompletePendingDeleteRequest(/*success=*/true);
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(sms_path_2,
            modem_messaging_test_->GetPendingDeleteRequestSmsPath());
}

TEST_F(NetworkSmsHandlerTest, ReceiveSmsTimeout) {
  EXPECT_EQ(test_observer_->message_count(), 0);

  // Test that no messages have been received yet
  const std::set<std::string>& messages(test_observer_->messages());
  // Note: The following string corresponds to values in
  // ModemMessagingClientStubImpl and SmsClientStubImpl.
  // TODO(stevenjb): Use a TestInterface to set this up to remove dependency.
  const char kMessage1[] = "FakeSMSClient: Test Message: /SMS/0";
  EXPECT_FALSE(base::Contains(messages, kMessage1));

  // Receive 2 SMSes.
  test_observer_->ClearMessages();
  EXPECT_TRUE(modem_messaging_test_->GetPendingDeleteRequestSmsPath().empty());
  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath1),
             dbus::ObjectPath(kSmsPath));
  const std::string sms_path_2 = "/SMS/2";
  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath1),
             dbus::ObjectPath(sms_path_2));
  EXPECT_TRUE(modem_messaging_test_->GetPendingDeleteRequestSmsPath().empty());

  // Simulate the timeout passing for the first SMS. The next SMS in the queue
  // should be processed.
  FastForwardReceiveSmsTimeout();

  // Complete fetching the second SMS' details.
  CompleteReceiveSms();
  base::RunLoop().RunUntilIdle();

  // The second SMS should be found in |messages| but not the first SMS.
  network_sms_handler_->RequestUpdate();
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(test_observer_->message_count(), 1);
  EXPECT_FALSE(base::Contains(messages, kMessage1));
  EXPECT_TRUE(base::Contains(messages, "FakeSMSClient: Test Message: /SMS/2"));

  // There should be a request to delete the second SMS. Complete the request.
  EXPECT_EQ(sms_path_2,
            modem_messaging_test_->GetPendingDeleteRequestSmsPath());
  modem_messaging_test_->CompletePendingDeleteRequest(/*success=*/true);
  base::RunLoop().RunUntilIdle();

  // There should be a request to delete the first SMS. Complete the request.
  EXPECT_EQ(kSmsPath, modem_messaging_test_->GetPendingDeleteRequestSmsPath());
  modem_messaging_test_->CompletePendingDeleteRequest(/*success=*/true);
  base::RunLoop().RunUntilIdle();

  // There should be no more messages to delete.
  EXPECT_TRUE(modem_messaging_test_->GetPendingDeleteRequestSmsPath().empty());
}

TEST_F(NetworkSmsHandlerTest, EmptyDbusObjectPath) {
  // This test verifies no crash should occur when the device dbus object path
  // is an empty value.
  device_test_->SetDeviceProperty(kCellularDevicePath,
                                  shill::kDBusObjectProperty, base::Value(""),
                                  /*notify_changed=*/true);
  base::RunLoop().RunUntilIdle();
  network_sms_handler_->RequestUpdate();
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(test_observer_->message_count(), 0);
}

TEST_F(NetworkSmsHandlerTest, DeviceObjectPathChange) {
  // Fake the SIM being switched to a different SIM.
  device_test_->SetDeviceProperty(
      kCellularDevicePath, shill::kDBusObjectProperty,
      base::Value(kCellularDeviceObjectPath2), /*notify_changed=*/true);
  base::RunLoop().RunUntilIdle();
  network_sms_handler_->RequestUpdate();
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(test_observer_->message_count(), 0);

  // Test that no messages have been received yet
  const std::set<std::string>& messages(test_observer_->messages());
  // Note: The following string corresponds to values in
  // ModemMessagingClientStubImpl and SmsClientStubImpl.
  // TODO(stevenjb): Use a TestInterface to set this up to remove dependency.
  const char kMessage1[] = "FakeSMSClient: Test Message: /SMS/0";
  EXPECT_FALSE(base::Contains(messages, kMessage1));

  // Test for messages delivered by signals.
  test_observer_->ClearMessages();
  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath2),
             dbus::ObjectPath(kSmsPath));
  CompleteReceiveSms();
  base::RunLoop().RunUntilIdle();

  network_sms_handler_->RequestUpdate();
  base::RunLoop().RunUntilIdle();
  EXPECT_GE(test_observer_->message_count(), 1);
  EXPECT_TRUE(base::Contains(messages, kMessage1));
}

TEST_F(NetworkSmsHandlerTest, NetworkGuidTest) {
  // Test that no messages have been received yet
  EXPECT_EQ(test_observer_->message_count(), 0);

  const char kMessage1[] = "FakeSMSClient: Test Message: /SMS/0";
  const char kMessage2[] = "FakeSMSClient: Test Message: /SMS/1";
  EXPECT_EQ(test_observer_->messages().find(kMessage1),
            test_observer_->messages().end());

  // Test for messages for the first network.
  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath1),
             dbus::ObjectPath(kSmsPath));
  CompleteReceiveSms();
  base::RunLoop().RunUntilIdle();

  network_sms_handler_->RequestUpdate();
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(1u, test_observer_->messages(kTestGuid1).size());
  EXPECT_NE(test_observer_->messages(kTestGuid1).find(kMessage1),
            test_observer_->messages(kTestGuid1).end());
  modem_messaging_test_->CompletePendingDeleteRequest(/*success=*/true);
  base::RunLoop().RunUntilIdle();

  // Switch to a different modem.
  UpdateNetworkState(kTestCellularServicePath1, shill::kStateDisconnecting);
  SetupCellularModem(kCellularDeviceObjectPath2, kTestCellularServicePath2,
                     kTestGuid2, kTestIccid2, shill::kStateOnline);

  base::RunLoop().RunUntilIdle();
  network_sms_handler_->RequestUpdate();

  // Test for messages for messages from the second network.
  EXPECT_EQ(0u, test_observer_->messages(kTestGuid2).size());
  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath2),
             dbus::ObjectPath("/SMS/1"));
  CompleteReceiveSms();
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(2u, test_observer_->messages().size());
  EXPECT_EQ(1u, test_observer_->messages(kTestGuid2).size());
  EXPECT_NE(test_observer_->messages(kTestGuid2).find(kMessage2),
            test_observer_->messages(kTestGuid2).end());
  EXPECT_EQ(test_observer_->messages(kTestGuid1).find(kMessage2),
            test_observer_->messages(kTestGuid1).end());
}

TEST_F(NetworkSmsHandlerTest, NetworkDelayedActiveNetworkTest) {
  SetupCellularModem(kCellularDeviceObjectPath2, kTestCellularServicePath2,
                     kTestGuid2, kTestIccid2, shill::kStateIdle);
  base::RunLoop().RunUntilIdle();
  network_sms_handler_->RequestUpdate();
  EXPECT_EQ(0u, test_observer_->messages().size());
  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath2),
             dbus::ObjectPath(kSmsPath));
  CompleteReceiveSms();
  base::RunLoop().RunUntilIdle();
  // The message will be sent with the GUID of the currently connected
  // network which is kTestGuid1.
  EXPECT_EQ(1u, test_observer_->messages(kTestGuid1).size());
  EXPECT_EQ(0u, test_observer_->messages(kTestGuid2).size());

  UpdateNetworkState(kTestCellularServicePath1, shill::kStateDisconnecting);
  base::RunLoop().RunUntilIdle();
  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath2),
             dbus::ObjectPath("/SMS/1"));
  CompleteReceiveSms();
  base::RunLoop().RunUntilIdle();
  // No connected network, the GUID of the last connected
  // network will be used.
  EXPECT_EQ(2u, test_observer_->messages(kTestGuid1).size());
  EXPECT_EQ(0u, test_observer_->messages(kTestGuid2).size());

  UpdateNetworkState(kTestCellularServicePath2, shill::kStateOnline);
  base::RunLoop().RunUntilIdle();

  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath2),
             dbus::ObjectPath("/SMS/2"));
  CompleteReceiveSms();
  base::RunLoop().RunUntilIdle();
  // After updating the state, we see that the message is sent with the GUID
  // associated with the last active network.
  EXPECT_EQ(2u, test_observer_->messages(kTestGuid1).size());
  EXPECT_EQ(1u, test_observer_->messages(kTestGuid2).size());
}

TEST_F(NetworkSmsHandlerTest, MessageReceivedNeverConnectedNetwork) {
  UpdateNetworkState(kTestCellularServicePath1, shill::kStateDisconnecting);
  SetupCellularModem(kCellularDeviceObjectPath2, kTestCellularServicePath2,
                     kTestGuid2, kTestIccid2, shill::kStateDisconnecting);

  base::RunLoop().RunUntilIdle();
  network_sms_handler_->RequestUpdate();
  EXPECT_EQ(0u, test_observer_->messages().size());
  ReceiveSms(dbus::ObjectPath(kCellularDeviceObjectPath2),
             dbus::ObjectPath(kSmsPath));
  CompleteReceiveSms();
  base::RunLoop().RunUntilIdle();
  EXPECT_EQ(1u, test_observer_->messages(kTestGuid2).size());
}

}  // namespace ash