blob: 92033a47aa85702d65678550e267d85254cf7720 [file] [log] [blame]
// 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