| // Copyright 2016 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/browser/webrtc/webrtc_eventlog_host.h" |
| |
| #include <set> |
| #include <tuple> |
| |
| #include "base/files/file.h" |
| #include "base/files/file_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/task_scheduler/post_task.h" |
| #include "base/task_scheduler/task_traits.h" |
| #include "build/build_config.h" |
| #include "content/browser/renderer_host/render_process_host_impl.h" |
| #include "content/common/media/peer_connection_tracker_messages.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/test/mock_render_process_host.h" |
| #include "content/public/test/test_browser_context.h" |
| #include "content/public/test/test_browser_thread_bundle.h" |
| #include "content/public/test/test_utils.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| #if defined(OS_WIN) |
| #define IntToStringType base::IntToString16 |
| #else |
| #define IntToStringType base::IntToString |
| #endif |
| |
| namespace content { |
| |
| namespace { |
| |
| // Get the expected Rtc eventlog file name. The name will be |
| // <temporary path>.<render process id>.<peer connection local id> |
| base::FilePath GetExpectedEventLogFileName(const base::FilePath& base_file, |
| int render_process_id, |
| int peer_connection_local_id) { |
| return base_file.AddExtension(IntToStringType(render_process_id)) |
| .AddExtension(IntToStringType(peer_connection_local_id)); |
| } |
| |
| } // namespace |
| |
| class WebRtcEventlogHostTest : public testing::Test { |
| public: |
| WebRtcEventlogHostTest() |
| : mock_render_process_host_(static_cast<MockRenderProcessHost*>( |
| mock_render_process_factory_.CreateRenderProcessHost( |
| &test_browser_context_))), |
| render_id_(mock_render_process_host_->GetID()), |
| event_log_host_(render_id_) {} |
| TestBrowserThreadBundle thread_bundle_; |
| MockRenderProcessHostFactory mock_render_process_factory_; |
| TestBrowserContext test_browser_context_; |
| std::unique_ptr<MockRenderProcessHost> mock_render_process_host_; |
| const int render_id_; |
| WebRTCEventLogHost event_log_host_; |
| base::FilePath base_file_; |
| |
| void StartLogging() { |
| ASSERT_TRUE(base::CreateTemporaryFile(&base_file_)); |
| EXPECT_TRUE(base::DeleteFile(base_file_, false)); |
| EXPECT_FALSE(base::PathExists(base_file_)); |
| EXPECT_TRUE(event_log_host_.StartWebRTCEventLog(base_file_)); |
| RunAllTasksUntilIdle(); |
| } |
| |
| void StopLogging() { |
| EXPECT_TRUE(event_log_host_.StopWebRTCEventLog()); |
| RunAllTasksUntilIdle(); |
| } |
| |
| void ValidateStartIPCMessageAndCloseFile(const IPC::Message* msg, |
| const int peer_connection_id) { |
| ASSERT_TRUE(msg); |
| std::tuple<int, IPC::PlatformFileForTransit> start_params; |
| PeerConnectionTracker_StartEventLog::Read(msg, &start_params); |
| EXPECT_EQ(peer_connection_id, std::get<0>(start_params)); |
| ASSERT_NE(IPC::InvalidPlatformFileForTransit(), std::get<1>(start_params)); |
| IPC::PlatformFileForTransitToFile(std::get<1>(start_params)).Close(); |
| } |
| |
| // This version of the function returns the peer connection ID instead of |
| // validating it. |
| int ReadStartIPCMessageAndCloseFile(const IPC::Message* msg) { |
| EXPECT_TRUE(msg); |
| if (msg) { |
| std::tuple<int, IPC::PlatformFileForTransit> start_params; |
| PeerConnectionTracker_StartEventLog::Read(msg, &start_params); |
| EXPECT_NE(IPC::InvalidPlatformFileForTransit(), |
| std::get<1>(start_params)); |
| if (std::get<1>(start_params) != IPC::InvalidPlatformFileForTransit()) { |
| IPC::PlatformFileForTransitToFile(std::get<1>(start_params)).Close(); |
| } |
| return std::get<0>(start_params); |
| } |
| return -1; |
| } |
| |
| void ValidateStopIPCMessage(const IPC::Message* msg, |
| const int peer_connection_id) { |
| ASSERT_TRUE(msg); |
| std::tuple<int> stop_params; |
| PeerConnectionTracker_StopEventLog::Read(msg, &stop_params); |
| EXPECT_EQ(peer_connection_id, std::get<0>(stop_params)); |
| } |
| |
| // This version of the function returns the peer connection ID instead of |
| // validating it. |
| int ReadStopIPCMessage(const IPC::Message* msg) { |
| EXPECT_TRUE(msg); |
| if (msg) { |
| std::tuple<int> stop_params; |
| PeerConnectionTracker_StopEventLog::Read(msg, &stop_params); |
| return std::get<0>(stop_params); |
| } |
| return -1; |
| } |
| }; |
| |
| // This test calls StartWebRTCEventLog() and StopWebRTCEventLog() without having |
| // added any PeerConnections. It is expected that no IPC messages will be sent. |
| TEST_F(WebRtcEventlogHostTest, NoPeerConnectionTest) { |
| mock_render_process_host_->sink().ClearMessages(); |
| |
| // Start logging and check that no IPC messages were sent. |
| StartLogging(); |
| EXPECT_EQ(size_t(0), mock_render_process_host_->sink().message_count()); |
| |
| // Stop logging and check that no IPC messages were sent. |
| StopLogging(); |
| EXPECT_EQ(size_t(0), mock_render_process_host_->sink().message_count()); |
| } |
| |
| // This test calls StartWebRTCEventLog() and StopWebRTCEventLog() after adding a |
| // single PeerConnection. It is expected that one IPC message will be sent for |
| // each of the Start and Stop calls, and that a logfile is created. |
| TEST_F(WebRtcEventlogHostTest, OnePeerConnectionTest) { |
| const int kTestPeerConnectionId = 123; |
| mock_render_process_host_->sink().ClearMessages(); |
| |
| // Add a PeerConnection and start logging. |
| event_log_host_.PeerConnectionAdded(kTestPeerConnectionId); |
| StartLogging(); |
| |
| // Check that the correct IPC message was sent. |
| EXPECT_EQ(size_t(1), mock_render_process_host_->sink().message_count()); |
| const IPC::Message* start_msg = |
| mock_render_process_host_->sink().GetMessageAt(0); |
| ValidateStartIPCMessageAndCloseFile(start_msg, kTestPeerConnectionId); |
| |
| // Stop logging. |
| mock_render_process_host_->sink().ClearMessages(); |
| StopLogging(); |
| |
| // Check that the correct IPC message was sent. |
| EXPECT_EQ(size_t(1), mock_render_process_host_->sink().message_count()); |
| const IPC::Message* stop_msg = |
| mock_render_process_host_->sink().GetMessageAt(0); |
| ValidateStopIPCMessage(stop_msg, kTestPeerConnectionId); |
| |
| // Clean up the logfile. |
| base::FilePath expected_file = GetExpectedEventLogFileName( |
| base_file_, render_id_, kTestPeerConnectionId); |
| ASSERT_TRUE(base::PathExists(expected_file)); |
| EXPECT_TRUE(base::DeleteFile(expected_file, false)); |
| } |
| |
| // This test calls StartWebRTCEventLog() and StopWebRTCEventLog() after adding |
| // two PeerConnections. It is expected that two IPC messages will be sent for |
| // each of the Start and Stop calls, and that a file is created for both |
| // PeerConnections. |
| |
| TEST_F(WebRtcEventlogHostTest, TwoPeerConnectionsTest) { |
| const int kTestPeerConnectionId1 = 123; |
| const int kTestPeerConnectionId2 = 321; |
| mock_render_process_host_->sink().ClearMessages(); |
| |
| // Add two PeerConnections and start logging. |
| event_log_host_.PeerConnectionAdded(kTestPeerConnectionId1); |
| event_log_host_.PeerConnectionAdded(kTestPeerConnectionId2); |
| StartLogging(); |
| |
| // Check that the correct IPC messages were sent. |
| EXPECT_EQ(size_t(2), mock_render_process_host_->sink().message_count()); |
| const IPC::Message* start_msg1 = |
| mock_render_process_host_->sink().GetMessageAt(0); |
| int start_msg1_id = ReadStartIPCMessageAndCloseFile(start_msg1); |
| const IPC::Message* start_msg2 = |
| mock_render_process_host_->sink().GetMessageAt(1); |
| int start_msg2_id = ReadStartIPCMessageAndCloseFile(start_msg2); |
| |
| const std::set<int> expected_ids = {kTestPeerConnectionId1, |
| kTestPeerConnectionId2}; |
| std::set<int> actual_start_ids = {start_msg1_id, start_msg2_id}; |
| EXPECT_EQ(expected_ids, actual_start_ids); |
| |
| // Stop logging. |
| mock_render_process_host_->sink().ClearMessages(); |
| StopLogging(); |
| |
| // Check that the correct IPC messages were sent. |
| EXPECT_EQ(size_t(2), mock_render_process_host_->sink().message_count()); |
| const IPC::Message* stop_msg1 = |
| mock_render_process_host_->sink().GetMessageAt(0); |
| int stop_msg1_id = ReadStopIPCMessage(stop_msg1); |
| const IPC::Message* stop_msg2 = |
| mock_render_process_host_->sink().GetMessageAt(1); |
| int stop_msg2_id = ReadStopIPCMessage(stop_msg2); |
| |
| std::set<int> actual_stop_ids = {stop_msg1_id, stop_msg2_id}; |
| EXPECT_EQ(expected_ids, actual_stop_ids); |
| |
| // Clean up the logfiles. |
| base::FilePath expected_file1 = GetExpectedEventLogFileName( |
| base_file_, render_id_, kTestPeerConnectionId1); |
| base::FilePath expected_file2 = GetExpectedEventLogFileName( |
| base_file_, render_id_, kTestPeerConnectionId2); |
| ASSERT_TRUE(base::PathExists(expected_file1)); |
| EXPECT_TRUE(base::DeleteFile(expected_file1, false)); |
| ASSERT_TRUE(base::PathExists(expected_file2)); |
| EXPECT_TRUE(base::DeleteFile(expected_file2, false)); |
| } |
| |
| // This test calls StartWebRTCEventLog() and StopWebRTCEventLog() after adding |
| // more PeerConnections than the maximum allowed. It is expected that only the |
| // maximum allowed number of IPC messages and log files will be opened, but we |
| // expect the number of stop IPC messages to be equal to the actual number of |
| // PeerConnections. |
| TEST_F(WebRtcEventlogHostTest, ExceedMaxPeerConnectionsTest) { |
| #if defined(OS_ANDROID) |
| const int kMaxNumberLogFiles = 3; |
| #else |
| const int kMaxNumberLogFiles = 5; |
| #endif |
| const int kNumberOfPeerConnections = kMaxNumberLogFiles + 1; |
| mock_render_process_host_->sink().ClearMessages(); |
| |
| // Add the maximum number + 1 PeerConnections and start logging. |
| for (int i = 0; i < kNumberOfPeerConnections; ++i) |
| event_log_host_.PeerConnectionAdded(i); |
| StartLogging(); |
| |
| // Check that the correct IPC messages were sent. |
| { |
| std::set<int> actual_ids, expected_ids; |
| ASSERT_EQ(size_t(kMaxNumberLogFiles), |
| mock_render_process_host_->sink().message_count()); |
| for (int i = 0; i < kMaxNumberLogFiles; ++i) { |
| const IPC::Message* start_msg = |
| mock_render_process_host_->sink().GetMessageAt(i); |
| int id = ReadStartIPCMessageAndCloseFile(start_msg); |
| actual_ids.insert(id); |
| expected_ids.insert(i); |
| } |
| EXPECT_EQ(actual_ids, expected_ids); |
| } |
| |
| // Stop logging. |
| mock_render_process_host_->sink().ClearMessages(); |
| StopLogging(); |
| |
| // Check that the correct IPC messages were sent. |
| { |
| std::set<int> actual_ids, expected_ids; |
| ASSERT_EQ(size_t(kNumberOfPeerConnections), |
| mock_render_process_host_->sink().message_count()); |
| for (int i = 0; i < kNumberOfPeerConnections; ++i) { |
| const IPC::Message* stop_msg = |
| mock_render_process_host_->sink().GetMessageAt(i); |
| int id = ReadStopIPCMessage(stop_msg); |
| actual_ids.insert(id); |
| expected_ids.insert(i); |
| } |
| EXPECT_EQ(actual_ids, expected_ids); |
| } |
| |
| // Clean up the logfiles. |
| for (int i = 0; i < kMaxNumberLogFiles; ++i) { |
| base::FilePath expected_file = |
| GetExpectedEventLogFileName(base_file_, render_id_, i); |
| ASSERT_TRUE(base::PathExists(expected_file)); |
| EXPECT_TRUE(base::DeleteFile(expected_file, false)); |
| } |
| |
| // Check that not too many files were created. |
| for (int i = kMaxNumberLogFiles; i < kNumberOfPeerConnections; ++i) { |
| base::FilePath expected_file = |
| GetExpectedEventLogFileName(base_file_, render_id_, i); |
| EXPECT_FALSE(base::PathExists(expected_file)); |
| } |
| } |
| |
| // This test calls StartWebRTCEventLog() and StopWebRTCEventLog() after first |
| // adding and then removing a single PeerConnection. It is expected that no IPC |
| // message will be sent. |
| TEST_F(WebRtcEventlogHostTest, AddRemovePeerConnectionTest) { |
| const int kTestPeerConnectionId = 123; |
| mock_render_process_host_->sink().ClearMessages(); |
| |
| // Add and immediately remove a PeerConnection. |
| event_log_host_.PeerConnectionAdded(kTestPeerConnectionId); |
| event_log_host_.PeerConnectionRemoved(kTestPeerConnectionId); |
| |
| // Start logging and check that no IPC messages were sent. |
| StartLogging(); |
| EXPECT_EQ(size_t(0), mock_render_process_host_->sink().message_count()); |
| |
| // Stop logging and check that no IPC messages were sent. |
| StopLogging(); |
| EXPECT_EQ(size_t(0), mock_render_process_host_->sink().message_count()); |
| |
| // Check that no logfile was created. |
| base::FilePath expected_file = GetExpectedEventLogFileName( |
| base_file_, render_id_, kTestPeerConnectionId); |
| ASSERT_FALSE(base::PathExists(expected_file)); |
| } |
| |
| } // namespace content |