chromium/chrome/browser/media/router/providers/openscreen/discovery/open_screen_listener_unittest.cc

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

#include "chrome/browser/media/router/providers/openscreen/discovery/open_screen_listener.h"

#include "base/time/time.h"
#include "net/base/host_port_pair.h"
#include "net/base/ip_address.h"

#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using openscreen::osp::ServiceInfo;
using ::testing::_;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::WithArg;

namespace media_router {

const char kServiceType[] = "openscreen_.udp_";

class MockServiceListenerObserver
    : public openscreen::osp::ServiceListener::Observer {
 public:
  MOCK_METHOD0(OnStarted, void());
  MOCK_METHOD0(OnStopped, void());
  MOCK_METHOD0(OnSuspended, void());
  MOCK_METHOD0(OnSearching, void());

  MOCK_METHOD1(OnReceiverAdded, void(const ServiceInfo&));
  MOCK_METHOD1(OnReceiverChanged, void(const ServiceInfo&));
  MOCK_METHOD1(OnReceiverRemoved, void(const ServiceInfo&));
  MOCK_METHOD0(OnAllReceiversRemoved, void());

  MOCK_METHOD1(OnError, void(openscreen::osp::ServiceListenerError));
  MOCK_METHOD1(OnMetrics, void(openscreen::osp::ServiceListener::Metrics));
};

// Although the testing framework can do a byte comparison, when it fails
// it's difficult to figure out *exactly* what is wrong with the actual
// Service Info class.
MATCHER_P(ServiceInfoEquals, expected, "") {
  return (expected.service_id == arg.service_id) &&
         (expected.friendly_name == arg.friendly_name) &&
         (expected.network_interface_index == arg.network_interface_index) &&
         (expected.v4_endpoint == arg.v4_endpoint) &&
         (expected.v6_endpoint == arg.v6_endpoint);
}

class OpenScreenListenerTest : public ::testing::Test {
 protected:
  void SetUp() override {
    valid_description_.service_name = "mock_service.test_service_type";
    valid_description_.address = net::HostPortPair("192.168.0.10", 8888);
    valid_description_.metadata = {"foo", "bar", "baz"};
    valid_description_.ip_address = net::IPAddress(192, 168, 0, 10);
    valid_description_.last_seen = base::Time();

    service_info_.service_id = "mock_service.test_service_type";
    service_info_.friendly_name = "mock_service";
    service_info_.v4_endpoint =
        openscreen::IPEndpoint{openscreen::IPAddress(192, 168, 0, 10), 8888};
    service_info_.v6_endpoint = {};
  }

  OpenScreenListenerTest() : listener(kServiceType), observer() {
    listener.AddObserver(&observer);
  }

  void ExpectReceiverAdded(const ServiceInfo& info) {
    EXPECT_CALL(observer, OnReceiverAdded(ServiceInfoEquals(info)));
  }

  void ExpectReceiverChanged(const ServiceInfo& info) {
    EXPECT_CALL(observer, OnReceiverChanged(ServiceInfoEquals(info)));
  }

  void ExpectReceiverRemoved(const ServiceInfo& info) {
    EXPECT_CALL(observer, OnReceiverRemoved(ServiceInfoEquals(info)));
  }

  OpenScreenListener listener;
  StrictMock<MockServiceListenerObserver> observer;
  local_discovery::ServiceDescription valid_description_;
  ServiceInfo service_info_;
};

TEST_F(OpenScreenListenerTest, DeviceAddedNotifiesObserversIfStarted) {
  listener.OnDeviceChanged(kServiceType, true, valid_description_);

  EXPECT_CALL(observer, OnStarted()).Times(1);
  listener.Start();
  ExpectReceiverAdded(service_info_);
  listener.OnDeviceChanged(kServiceType, true, valid_description_);
}

TEST_F(OpenScreenListenerTest, DeviceChangedNotifiesObserversIfStarted) {
  listener.OnDeviceChanged(kServiceType, false, valid_description_);

  EXPECT_CALL(observer, OnStarted()).Times(1);
  listener.Start();
  ExpectReceiverAdded(service_info_);
  listener.OnDeviceChanged(kServiceType, true, valid_description_);

  ExpectReceiverChanged(service_info_);
  listener.OnDeviceChanged(kServiceType, false, valid_description_);
}

TEST_F(OpenScreenListenerTest, DeviceRemovedNotifiesObserversIfStarted) {
  listener.OnDeviceRemoved(kServiceType, valid_description_.service_name);

  EXPECT_CALL(observer, OnStarted()).Times(1);
  listener.Start();
  ExpectReceiverAdded(service_info_);
  listener.OnDeviceChanged(kServiceType, true, valid_description_);

  ExpectReceiverRemoved(service_info_);
  listener.OnDeviceRemoved(kServiceType, valid_description_.service_name);
}

TEST_F(OpenScreenListenerTest, CachedFlushNotifiesObserversIfStarted) {
  listener.OnDeviceCacheFlushed(kServiceType);

  EXPECT_CALL(observer, OnStarted()).Times(1);
  listener.Start();
  EXPECT_CALL(observer, OnAllReceiversRemoved()).Times(1);
  listener.OnDeviceCacheFlushed(kServiceType);
}

TEST_F(OpenScreenListenerTest, CachedFlushEmptiesReceiverList) {
  EXPECT_CALL(observer, OnStarted()).Times(1);
  listener.Start();

  ExpectReceiverAdded(service_info_);
  listener.OnDeviceChanged(kServiceType, true, valid_description_);

  ExpectReceiverAdded(service_info_);
  listener.OnDeviceChanged(kServiceType, true, valid_description_);

  EXPECT_EQ(2ul, listener.GetReceivers().size());
  EXPECT_CALL(observer, OnAllReceiversRemoved()).Times(1);
  listener.OnDeviceCacheFlushed(kServiceType);
  EXPECT_EQ(0ul, listener.GetReceivers().size());
}

TEST_F(OpenScreenListenerTest, StartNotifiesObservers) {
  EXPECT_CALL(observer, OnStarted()).Times(1);
  listener.Start();
}

TEST_F(OpenScreenListenerTest, StopNotifiesObservers) {
  EXPECT_CALL(observer, OnStarted()).Times(1);
  EXPECT_CALL(observer, OnStopped()).Times(1);

  listener.Start();
  listener.Stop();
}

TEST_F(OpenScreenListenerTest, SuspendNotifiesObservers) {
  EXPECT_CALL(observer, OnStarted()).Times(2);
  EXPECT_CALL(observer, OnSuspended()).Times(2);

  listener.Start();
  listener.Suspend();
  listener.StartAndSuspend();
}

TEST_F(OpenScreenListenerTest, ResumeNotifiesObservers) {
  EXPECT_CALL(observer, OnStarted()).Times(2);
  EXPECT_CALL(observer, OnSuspended()).Times(1);

  listener.Start();
  listener.Suspend();
  listener.Resume();
}

TEST_F(OpenScreenListenerTest, SearchingNotifiesObservers) {
  EXPECT_CALL(observer, OnStarted()).Times(1);
  listener.Start();
  EXPECT_CALL(observer, OnSearching()).Times(1);
  listener.SearchNow();
}

TEST_F(OpenScreenListenerTest, RemovedObserversDoNotGetNotified) {
  listener.RemoveObserver(&observer);

  listener.Start();
  listener.Stop();
  listener.StartAndSuspend();
  listener.Resume();
  listener.SearchNow();
  listener.Suspend();
  listener.Resume();
  listener.OnDeviceCacheFlushed(kServiceType);
  listener.OnDeviceChanged(kServiceType, true, valid_description_);
  listener.OnDeviceChanged(kServiceType, true, valid_description_);
  listener.OnDeviceRemoved(kServiceType, valid_description_.service_name);
}

TEST_F(OpenScreenListenerTest, DoesNotRecordReceiversIfNotStarted) {
  EXPECT_EQ(0ul, listener.GetReceivers().size());

  listener.OnDeviceChanged(kServiceType, true, valid_description_);
  listener.OnDeviceChanged(kServiceType, false, valid_description_);
  listener.OnDeviceChanged(kServiceType, true, valid_description_);
  EXPECT_EQ(0ul, listener.GetReceivers().size());
}
}  // namespace media_router