| // Copyright 2015 The Chromium 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 "content/renderer/p2p/filtering_network_manager.h" |
| |
| #include <stddef.h> |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "base/logging.h" |
| #include "base/macros.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/test/test_simple_task_runner.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "content/renderer/p2p/empty_network_manager.h" |
| #include "media/base/media_permission.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/webrtc/base/ipaddress.h" |
| |
| using NetworkList = rtc::NetworkManager::NetworkList; |
| |
| namespace { |
| |
| enum EventType { |
| MIC_DENIED, // Receive mic permission denied. |
| MIC_GRANTED, // Receive mic permission granted. |
| CAMERA_DENIED, // Receive camera permission denied. |
| CAMERA_GRANTED, // Receive camera permission granted. |
| START_UPDATING, // Client calls StartUpdating() on FilteringNetworkManager. |
| STOP_UPDATING, // Client calls StopUpdating() on FilteringNetworkManager. |
| MOCK_NETWORKS_CHANGED, // MockNetworkManager has signaled networks changed |
| // event. |
| }; |
| |
| enum ResultType { |
| NO_SIGNAL, // Do not expect SignalNetworksChanged fired. |
| SIGNAL_ENUMERATION_BLOCKED, // Expect SignalNetworksChanged and |
| // ENUMERATION_BLOCKED. |
| SIGNAL_ENUMERATION_ALLOWED, // Expect SignalNetworksChanged and |
| // ENUMERATION_ALLOWED. |
| }; |
| |
| struct TestEntry { |
| EventType event; |
| ResultType expected_result; |
| }; |
| |
| class MockNetworkManager : public rtc::NetworkManager { |
| public: |
| MockNetworkManager() { |
| network_.reset(new rtc::Network("test_eth0", "Test Network Adapter 1", |
| rtc::IPAddress(0x12345600U), 24, |
| rtc::ADAPTER_TYPE_ETHERNET)); |
| } |
| // Mimic the current behavior that once the first signal is sent, any future |
| // StartUpdating() will trigger another one. |
| void StartUpdating() override { |
| if (sent_first_update_) |
| SignalNetworksChanged(); |
| } |
| void StopUpdating() override {} |
| void GetNetworks(NetworkList* networks) const override { |
| networks->push_back(network_.get()); |
| } |
| |
| void SendNetworksChanged() { |
| sent_first_update_ = true; |
| SignalNetworksChanged(); |
| } |
| |
| private: |
| bool sent_first_update_ = false; |
| std::unique_ptr<rtc::Network> network_; |
| }; |
| |
| class MockMediaPermission : public media::MediaPermission { |
| public: |
| MockMediaPermission() {} |
| ~MockMediaPermission() override {} |
| |
| void RequestPermission( |
| Type type, |
| const GURL& security_origin, |
| const PermissionStatusCB& permission_status_cb) override { |
| NOTIMPLEMENTED(); |
| } |
| |
| void HasPermission(Type type, |
| const GURL& security_origin, |
| const PermissionStatusCB& permission_status_cb) override { |
| if (type == MediaPermission::AUDIO_CAPTURE) { |
| DCHECK(mic_callback_.is_null()); |
| mic_callback_ = permission_status_cb; |
| } else { |
| DCHECK(type == MediaPermission::VIDEO_CAPTURE); |
| DCHECK(camera_callback_.is_null()); |
| camera_callback_ = permission_status_cb; |
| } |
| } |
| |
| void SetMicPermission(bool granted) { |
| if (mic_callback_.is_null()) |
| return; |
| |
| mic_callback_.Run(granted); |
| mic_callback_ = PermissionStatusCB(); |
| } |
| |
| void SetCameraPermission(bool granted) { |
| if (camera_callback_.is_null()) |
| return; |
| |
| camera_callback_.Run(granted); |
| camera_callback_ = PermissionStatusCB(); |
| } |
| |
| private: |
| PermissionStatusCB mic_callback_; |
| PermissionStatusCB camera_callback_; |
| }; |
| |
| } // namespace |
| |
| namespace content { |
| |
| class FilteringNetworkManagerTest : public testing::Test, |
| public sigslot::has_slots<> { |
| public: |
| FilteringNetworkManagerTest() |
| : media_permission_(new MockMediaPermission()), |
| task_runner_(new base::TestSimpleTaskRunner()), |
| task_runner_handle_(task_runner_) {} |
| void SetupNetworkManager(bool multiple_routes_requested) { |
| mock_network_manager_.reset(new MockNetworkManager()); |
| if (multiple_routes_requested) { |
| FilteringNetworkManager* filtering_network_manager = |
| new FilteringNetworkManager(mock_network_manager_.get(), GURL(), |
| media_permission_.get()); |
| filtering_network_manager->Initialize(); |
| network_manager_.reset(filtering_network_manager); |
| } else { |
| network_manager_.reset( |
| new EmptyNetworkManager(mock_network_manager_.get())); |
| } |
| network_manager_->SignalNetworksChanged.connect( |
| this, &FilteringNetworkManagerTest::OnNetworksChanged); |
| } |
| |
| void RunTests(TestEntry* tests, size_t size) { |
| for (size_t i = 0; i < size; ++i) { |
| EXPECT_EQ(tests[i].expected_result, ProcessEvent(tests[i].event)) |
| << " in step: " << i; |
| } |
| } |
| |
| ResultType ProcessEvent(EventType event) { |
| clear_callback_called(); |
| switch (event) { |
| case MIC_DENIED: |
| case MIC_GRANTED: |
| media_permission_->SetMicPermission(event == MIC_GRANTED); |
| break; |
| case CAMERA_DENIED: |
| case CAMERA_GRANTED: |
| media_permission_->SetCameraPermission(event == CAMERA_GRANTED); |
| break; |
| case START_UPDATING: |
| network_manager_->StartUpdating(); |
| break; |
| case STOP_UPDATING: |
| network_manager_->StopUpdating(); |
| break; |
| case MOCK_NETWORKS_CHANGED: |
| mock_network_manager_->SendNetworksChanged(); |
| break; |
| } |
| |
| task_runner_->RunUntilIdle(); |
| |
| if (!callback_called_) |
| return NO_SIGNAL; |
| |
| if (network_manager_->enumeration_permission() == |
| rtc::NetworkManager::ENUMERATION_BLOCKED) { |
| EXPECT_EQ(0u, GetP2PNetworkList().size()); |
| return SIGNAL_ENUMERATION_BLOCKED; |
| } |
| EXPECT_EQ(1u, GetP2PNetworkList().size()); |
| return SIGNAL_ENUMERATION_ALLOWED; |
| } |
| |
| protected: |
| const NetworkList& GetP2PNetworkList() { |
| network_list_.clear(); |
| network_manager_->GetNetworks(&network_list_); |
| return network_list_; |
| } |
| |
| void OnNetworksChanged() { callback_called_ = true; } |
| void clear_callback_called() { callback_called_ = false; } |
| |
| bool callback_called_ = false; |
| std::unique_ptr<rtc::NetworkManager> network_manager_; |
| std::unique_ptr<MockNetworkManager> mock_network_manager_; |
| |
| std::unique_ptr<MockMediaPermission> media_permission_; |
| |
| NetworkList network_list_; |
| scoped_refptr<base::TestSimpleTaskRunner> task_runner_; |
| base::ThreadTaskRunnerHandle task_runner_handle_; |
| }; |
| |
| // Test that when multiple routes is not requested, SignalNetworksChanged is |
| // fired right after the StartUpdating(). |
| TEST_F(FilteringNetworkManagerTest, MultipleRoutesNotRequested) { |
| SetupNetworkManager(false); |
| TestEntry tests[] = { |
| // Underneath network manager signals, no callback as StartUpdating() is |
| // not called. |
| {MOCK_NETWORKS_CHANGED, NO_SIGNAL}, |
| // StartUpdating() is called, should receive callback as the multiple |
| // routes is not requested. |
| {START_UPDATING, SIGNAL_ENUMERATION_BLOCKED}, |
| // Further network signal should trigger callback, since the default |
| // network could have changed. |
| {MOCK_NETWORKS_CHANGED, SIGNAL_ENUMERATION_BLOCKED}, |
| // New StartUpdating() should trigger callback. |
| {START_UPDATING, SIGNAL_ENUMERATION_BLOCKED}, |
| {STOP_UPDATING, NO_SIGNAL}, |
| {STOP_UPDATING, NO_SIGNAL}, |
| {MOCK_NETWORKS_CHANGED, NO_SIGNAL}, |
| }; |
| |
| RunTests(tests, arraysize(tests)); |
| } |
| |
| // Test that multiple routes request is blocked and signaled right after |
| // StartUpdating() since mic/camera permissions are denied. |
| TEST_F(FilteringNetworkManagerTest, BlockMultipleRoutesByStartUpdating) { |
| SetupNetworkManager(true); |
| |
| TestEntry tests[] = { |
| {MOCK_NETWORKS_CHANGED, NO_SIGNAL}, |
| // Both mic and camera are denied. |
| {MIC_DENIED, NO_SIGNAL}, |
| {CAMERA_DENIED, NO_SIGNAL}, |
| // Once StartUpdating() is called, signal network changed event with |
| // ENUMERATION_BLOCKED. |
| {START_UPDATING, SIGNAL_ENUMERATION_BLOCKED}, |
| // Further network signal should trigger callback, since the default |
| // network could have changed. |
| {MOCK_NETWORKS_CHANGED, SIGNAL_ENUMERATION_BLOCKED}, |
| // New StartUpdating() should trigger callback. |
| {START_UPDATING, SIGNAL_ENUMERATION_BLOCKED}, |
| {STOP_UPDATING, NO_SIGNAL}, |
| {STOP_UPDATING, NO_SIGNAL}, |
| {MOCK_NETWORKS_CHANGED, NO_SIGNAL}, |
| }; |
| |
| RunTests(tests, arraysize(tests)); |
| } |
| |
| // Test that multiple routes request is blocked and signaled right after |
| // last pending permission check is denied since StartUpdating() has been called |
| // previously. |
| TEST_F(FilteringNetworkManagerTest, BlockMultipleRoutesByPermissionsDenied) { |
| SetupNetworkManager(true); |
| |
| TestEntry tests[] = { |
| {START_UPDATING, NO_SIGNAL}, |
| {MOCK_NETWORKS_CHANGED, NO_SIGNAL}, |
| {MIC_DENIED, NO_SIGNAL}, |
| // The last permission check being denied should immediately trigger the |
| // networks changed signal, since we already have an updated network list. |
| {CAMERA_DENIED, SIGNAL_ENUMERATION_BLOCKED}, |
| {START_UPDATING, SIGNAL_ENUMERATION_BLOCKED}, |
| {STOP_UPDATING, NO_SIGNAL}, |
| {STOP_UPDATING, NO_SIGNAL}, |
| {MOCK_NETWORKS_CHANGED, NO_SIGNAL}, |
| }; |
| |
| RunTests(tests, arraysize(tests)); |
| } |
| |
| // Test that after permissions have been denied, a network change signal from |
| // the internal NetworkManager is still needed before signaling a network |
| // change outwards. This is because even if network enumeration is blocked, |
| // we still want to give time to obtain the default IP addresses. |
| TEST_F(FilteringNetworkManagerTest, BlockMultipleRoutesByNetworksChanged) { |
| SetupNetworkManager(true); |
| |
| TestEntry tests[] = { |
| {START_UPDATING, NO_SIGNAL}, |
| {MIC_DENIED, NO_SIGNAL}, |
| {CAMERA_DENIED, NO_SIGNAL}, |
| {MOCK_NETWORKS_CHANGED, SIGNAL_ENUMERATION_BLOCKED}, |
| {START_UPDATING, SIGNAL_ENUMERATION_BLOCKED}, |
| {STOP_UPDATING, NO_SIGNAL}, |
| {STOP_UPDATING, NO_SIGNAL}, |
| {MOCK_NETWORKS_CHANGED, NO_SIGNAL}, |
| }; |
| |
| RunTests(tests, arraysize(tests)); |
| } |
| |
| // Test that multiple routes request is granted and signaled right after |
| // a pending permission check is granted since StartUpdating() has been called |
| // previously. |
| TEST_F(FilteringNetworkManagerTest, AllowMultipleRoutesByPermissionsGranted) { |
| SetupNetworkManager(true); |
| |
| TestEntry tests[] = { |
| {START_UPDATING, NO_SIGNAL}, |
| {MIC_DENIED, NO_SIGNAL}, |
| {MOCK_NETWORKS_CHANGED, NO_SIGNAL}, |
| // Once one media type is granted, signal networkschanged with |
| // ENUMERATION_ALLOWED. |
| {CAMERA_GRANTED, SIGNAL_ENUMERATION_ALLOWED}, |
| {MOCK_NETWORKS_CHANGED, SIGNAL_ENUMERATION_ALLOWED}, |
| {START_UPDATING, SIGNAL_ENUMERATION_ALLOWED}, |
| {STOP_UPDATING, NO_SIGNAL}, |
| // If there is any outstanding StartUpdating(), new event from underneath |
| // network manger should trigger SignalNetworksChanged. |
| {MOCK_NETWORKS_CHANGED, SIGNAL_ENUMERATION_ALLOWED}, |
| {STOP_UPDATING, NO_SIGNAL}, |
| // No outstanding StartUpdating(), no more signal. |
| {MOCK_NETWORKS_CHANGED, NO_SIGNAL}, |
| }; |
| |
| RunTests(tests, arraysize(tests)); |
| } |
| |
| // Test that multiple routes request is granted and signaled right after |
| // StartUpdating() since there is at least one media permission granted. |
| TEST_F(FilteringNetworkManagerTest, AllowMultipleRoutesByStartUpdating) { |
| SetupNetworkManager(true); |
| |
| TestEntry tests[] = { |
| {MIC_DENIED, NO_SIGNAL}, |
| {MOCK_NETWORKS_CHANGED, NO_SIGNAL}, |
| {CAMERA_GRANTED, NO_SIGNAL}, |
| // StartUpdating() should trigger the event since at least one media is |
| // granted and network information is populated. |
| {START_UPDATING, SIGNAL_ENUMERATION_ALLOWED}, |
| {MOCK_NETWORKS_CHANGED, SIGNAL_ENUMERATION_ALLOWED}, |
| {START_UPDATING, SIGNAL_ENUMERATION_ALLOWED}, |
| {STOP_UPDATING, NO_SIGNAL}, |
| {MOCK_NETWORKS_CHANGED, SIGNAL_ENUMERATION_ALLOWED}, |
| {STOP_UPDATING, NO_SIGNAL}, |
| {MOCK_NETWORKS_CHANGED, NO_SIGNAL}, |
| }; |
| |
| RunTests(tests, arraysize(tests)); |
| } |
| |
| // Test that multiple routes request is granted and signaled right after |
| // underneath NetworkManager's SignalNetworksChanged() as at least one |
| // permission is granted and StartUpdating() has been called. |
| TEST_F(FilteringNetworkManagerTest, AllowMultipleRoutesByNetworksChanged) { |
| SetupNetworkManager(true); |
| |
| TestEntry tests[] = { |
| {START_UPDATING, NO_SIGNAL}, |
| {CAMERA_GRANTED, NO_SIGNAL}, |
| // Underneath network manager's signal networks changed should trigger |
| // SignalNetworksChanged with ENUMERATION_ALLOWED. |
| {MOCK_NETWORKS_CHANGED, SIGNAL_ENUMERATION_ALLOWED}, |
| {MIC_DENIED, NO_SIGNAL}, |
| {MOCK_NETWORKS_CHANGED, SIGNAL_ENUMERATION_ALLOWED}, |
| {START_UPDATING, SIGNAL_ENUMERATION_ALLOWED}, |
| {STOP_UPDATING, NO_SIGNAL}, |
| {MOCK_NETWORKS_CHANGED, SIGNAL_ENUMERATION_ALLOWED}, |
| {STOP_UPDATING, NO_SIGNAL}, |
| {MOCK_NETWORKS_CHANGED, NO_SIGNAL}, |
| }; |
| |
| RunTests(tests, arraysize(tests)); |
| } |
| |
| } // namespace content |