| // Copyright 2017 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 "chrome/browser/media/webrtc/webrtc_event_log_manager.h" |
| |
| #include <algorithm> |
| #include <list> |
| #include <map> |
| #include <memory> |
| #include <numeric> |
| #include <queue> |
| #include <string> |
| #include <tuple> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/big_endian.h" |
| #include "base/bind.h" |
| #include "base/files/file.h" |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/files/scoped_temp_dir.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/optional.h" |
| #include "base/run_loop.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/synchronization/waitable_event.h" |
| #include "base/test/gtest_util.h" |
| #include "base/test/scoped_command_line.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/simple_test_clock.h" |
| #include "base/threading/sequenced_task_runner_handle.h" |
| #include "base/time/time.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/media/webrtc/webrtc_event_log_manager_common.h" |
| #include "chrome/browser/media/webrtc/webrtc_event_log_manager_unittest_helpers.h" |
| #include "chrome/browser/prefs/browser_prefs.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/test/base/testing_browser_process.h" |
| #include "chrome/test/base/testing_profile.h" |
| #include "components/pref_registry/pref_registry_syncable.h" |
| #include "components/prefs/testing_pref_store.h" |
| #include "components/sync_preferences/pref_service_mock_factory.h" |
| #include "components/sync_preferences/pref_service_syncable.h" |
| #include "content/public/browser/network_service_instance.h" |
| #include "content/public/test/mock_render_process_host.h" |
| #include "content/public/test/test_browser_thread_bundle.h" |
| #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" |
| #include "services/network/test/test_network_connection_tracker.h" |
| #include "services/network/test/test_url_loader_factory.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/zlib/google/compression_utils.h" |
| |
| #if defined(OS_WIN) |
| #define IntToStringType base::IntToString16 |
| #else |
| #define IntToStringType base::IntToString |
| #endif |
| |
| using ::testing::_; |
| using ::testing::Invoke; |
| using ::testing::NiceMock; |
| |
| using BrowserContext = content::BrowserContext; |
| using BrowserContextId = WebRtcEventLogPeerConnectionKey::BrowserContextId; |
| using MockRenderProcessHost = content::MockRenderProcessHost; |
| using PeerConnectionKey = WebRtcEventLogPeerConnectionKey; |
| using RenderProcessHost = content::RenderProcessHost; |
| |
| using Compression = WebRtcEventLogCompression; |
| |
| namespace { |
| |
| #if !defined(OS_ANDROID) |
| |
| auto SaveFilePathTo(base::Optional<base::FilePath>* output) { |
| return [output](PeerConnectionKey ignored_key, base::FilePath file_path) { |
| *output = file_path; |
| }; |
| } |
| |
| auto SaveKeyAndFilePathTo(base::Optional<PeerConnectionKey>* key_output, |
| base::Optional<base::FilePath>* file_path_output) { |
| return [key_output, file_path_output](PeerConnectionKey key, |
| base::FilePath file_path) { |
| *key_output = key; |
| *file_path_output = file_path; |
| }; |
| } |
| |
| const int kMaxActiveRemoteLogFiles = |
| static_cast<int>(kMaxActiveRemoteBoundWebRtcEventLogs); |
| const int kMaxPendingRemoteLogFiles = |
| static_cast<int>(kMaxPendingRemoteBoundWebRtcEventLogs); |
| |
| base::Time GetLastModificationTime(const base::FilePath& file_path) { |
| base::File::Info file_info; |
| if (!base::GetFileInfo(file_path, &file_info)) { |
| EXPECT_TRUE(false); |
| return base::Time(); |
| } |
| return file_info.last_modified; |
| } |
| |
| #endif |
| |
| // Common default/arbitrary values. |
| static constexpr int kLid = 478; |
| |
| PeerConnectionKey GetPeerConnectionKey(const RenderProcessHost* rph, int lid) { |
| const BrowserContext* browser_context = rph->GetBrowserContext(); |
| const auto browser_context_id = GetBrowserContextId(browser_context); |
| return PeerConnectionKey(rph->GetID(), lid, browser_context_id); |
| } |
| |
| bool CreateRemoteBoundLogFile(const base::FilePath& dir, |
| const base::FilePath::StringPieceType& extension, |
| base::FilePath* file_path, |
| base::File* file) { |
| *file_path = |
| dir.Append(kRemoteBoundWebRtcEventLogFileNamePrefix) |
| .InsertBeforeExtensionASCII("01234567890123456789012345678901") |
| .AddExtension(extension); |
| constexpr int file_flags = base::File::FLAG_CREATE | base::File::FLAG_WRITE | |
| base::File::FLAG_EXCLUSIVE_WRITE; |
| file->Initialize(*file_path, file_flags); |
| return (file->IsValid() && file->created()); |
| } |
| |
| // This implementation does not upload files, nor pretends to have finished an |
| // upload. Most importantly, it does not get rid of the locally-stored log file |
| // after finishing a simulated upload; this is useful because it keeps the file |
| // on disk, where unit tests may inspect it. |
| // This class enforces an expectation over the upload being cancelled or not. |
| class NullWebRtcEventLogUploader : public WebRtcEventLogUploader { |
| public: |
| NullWebRtcEventLogUploader(const WebRtcLogFileInfo& log_file, |
| bool cancellation_expected) |
| : log_file_(log_file), |
| cancellation_expected_(cancellation_expected), |
| was_cancelled_(false) {} |
| |
| ~NullWebRtcEventLogUploader() override { |
| EXPECT_EQ(was_cancelled_, cancellation_expected_); |
| } |
| |
| const WebRtcLogFileInfo& GetWebRtcLogFileInfo() const override { |
| return log_file_; |
| } |
| |
| bool Cancel() override { |
| EXPECT_TRUE(cancellation_expected_); |
| if (was_cancelled_) { // Should not be called more than once. |
| EXPECT_TRUE(false); |
| return false; |
| } |
| was_cancelled_ = true; |
| return true; |
| } |
| |
| class Factory : public WebRtcEventLogUploader::Factory { |
| public: |
| Factory(bool cancellation_expected, |
| base::Optional<size_t> expected_instance_count = |
| base::Optional<size_t>()) |
| : cancellation_expected_(cancellation_expected), |
| expected_instance_count_(expected_instance_count), |
| instance_count_(0) {} |
| |
| ~Factory() override { |
| if (expected_instance_count_.has_value()) { |
| EXPECT_EQ(instance_count_, expected_instance_count_.value()); |
| } |
| } |
| |
| std::unique_ptr<WebRtcEventLogUploader> Create( |
| const WebRtcLogFileInfo& log_file, |
| UploadResultCallback callback) override { |
| if (expected_instance_count_.has_value()) { |
| EXPECT_LE(++instance_count_, expected_instance_count_.value()); |
| } |
| return std::make_unique<NullWebRtcEventLogUploader>( |
| log_file, cancellation_expected_); |
| } |
| |
| private: |
| const bool cancellation_expected_; |
| const base::Optional<size_t> expected_instance_count_; |
| size_t instance_count_; |
| }; |
| |
| private: |
| const WebRtcLogFileInfo log_file_; |
| const bool cancellation_expected_; |
| bool was_cancelled_; |
| }; |
| |
| class MockWebRtcLocalEventLogsObserver : public WebRtcLocalEventLogsObserver { |
| public: |
| ~MockWebRtcLocalEventLogsObserver() override = default; |
| MOCK_METHOD2(OnLocalLogStarted, |
| void(PeerConnectionKey, const base::FilePath&)); |
| MOCK_METHOD1(OnLocalLogStopped, void(PeerConnectionKey)); |
| }; |
| |
| class MockWebRtcRemoteEventLogsObserver : public WebRtcRemoteEventLogsObserver { |
| public: |
| ~MockWebRtcRemoteEventLogsObserver() override = default; |
| MOCK_METHOD2(OnRemoteLogStarted, |
| void(PeerConnectionKey, const base::FilePath&)); |
| MOCK_METHOD1(OnRemoteLogStopped, void(PeerConnectionKey)); |
| }; |
| |
| } // namespace |
| |
| class WebRtcEventLogManagerTestBase : public ::testing::Test { |
| public: |
| WebRtcEventLogManagerTestBase() |
| : test_shared_url_loader_factory_( |
| base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( |
| &test_url_loader_factory_)), |
| run_loop_(std::make_unique<base::RunLoop>()), |
| uploader_run_loop_(std::make_unique<base::RunLoop>()), |
| browser_context_(nullptr), |
| browser_context_id_(GetBrowserContextId(browser_context_.get())) { |
| TestingBrowserProcess::GetGlobal()->SetSharedURLLoaderFactory( |
| test_shared_url_loader_factory_); |
| |
| // Avoid proactive pruning; it has the potential to mess up tests, as well |
| // as keep pendings tasks around with a dangling reference to the unit |
| // under test. (Zero is a sentinel value for disabling proactive pruning.) |
| scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII( |
| ::switches::kWebRtcRemoteEventLogProactivePruningDelta, "0"); |
| |
| EXPECT_TRUE(local_logs_base_dir_.CreateUniqueTempDir()); |
| local_logs_base_path_ = local_logs_base_dir_.GetPath().Append( |
| FILE_PATH_LITERAL("local_event_logs")); |
| |
| EXPECT_TRUE(profiles_dir_.CreateUniqueTempDir()); |
| } |
| |
| ~WebRtcEventLogManagerTestBase() override { |
| WaitForPendingTasks(); |
| |
| base::RunLoop run_loop; |
| event_log_manager_->ShutDownForTesting(run_loop.QuitClosure()); |
| run_loop.Run(); |
| |
| // We do not want to satisfy any unsatisfied expectations by destroying |
| // |rph_|, |browser_context_|, etc., at the end of the test, before we |
| // destroy |event_log_manager_|. However, we must also make sure that their |
| // destructors do not attempt to access |event_log_manager_|, which in |
| // normal code lives forever, but not in the unit tests. |
| event_log_manager_.reset(); |
| |
| // Guard against unexpected state changes. |
| EXPECT_TRUE(webrtc_state_change_instructions_.empty()); |
| } |
| |
| void SetUp() override { |
| SetUp(std::make_unique<network::TestNetworkConnectionTracker>( |
| true, network::mojom::ConnectionType::CONNECTION_ETHERNET)); |
| } |
| |
| void SetUp(std::unique_ptr<network::NetworkConnectionTracker> tracker) { |
| network_connection_tracker_ = std::move(tracker); |
| content::SetNetworkConnectionTrackerForTesting( |
| network_connection_tracker_.get()); |
| SetLocalLogsObserver(&local_observer_); |
| SetRemoteLogsObserver(&remote_observer_); |
| LoadMainTestProfile(); |
| } |
| |
| void CreateWebRtcEventLogManager( |
| base::Optional<Compression> remote = base::Optional<Compression>()) { |
| DCHECK(!event_log_manager_); |
| |
| event_log_manager_ = WebRtcEventLogManager::CreateSingletonInstance(); |
| |
| local_log_extension_ = kWebRtcEventLogUncompressedExtension; |
| |
| if (remote.has_value()) { |
| auto factory = CreateLogFileWriterFactory(remote.value()); |
| remote_log_extension_ = factory->Extension(); |
| event_log_manager_->SetRemoteLogFileWriterFactoryForTesting( |
| std::move(factory)); |
| } else { |
| // kWebRtcRemoteEventLogGzipped is turned on by default. |
| remote_log_extension_ = kWebRtcEventLogGzippedExtension; |
| } |
| } |
| |
| void LoadMainTestProfile() { |
| browser_context_ = CreateBrowserContext("browser_context_"); |
| browser_context_id_ = GetBrowserContextId(browser_context_.get()); |
| rph_ = std::make_unique<MockRenderProcessHost>(browser_context_.get()); |
| } |
| |
| void UnloadMainTestProfile() { |
| rph_.reset(); |
| browser_context_.reset(); |
| browser_context_id_ = GetBrowserContextId(browser_context_.get()); |
| EXPECT_FALSE(upload_suppressing_rph_); |
| } |
| |
| void WaitForReply() { |
| run_loop_->Run(); |
| run_loop_.reset(new base::RunLoop); // Allow re-blocking. |
| } |
| |
| void Reply() { run_loop_->QuitWhenIdle(); } |
| |
| base::OnceClosure ReplyClosure() { |
| // Intermediary pointer used to help the compiler distinguish between |
| // the overloaded Reply() functions. |
| void (WebRtcEventLogManagerTestBase::*function)() = |
| &WebRtcEventLogManagerTestBase::Reply; |
| return base::BindOnce(function, base::Unretained(this)); |
| } |
| |
| template <typename T> |
| void Reply(T* output, T val) { |
| *output = val; |
| run_loop_->QuitWhenIdle(); |
| } |
| |
| template <typename T> |
| base::OnceCallback<void(T)> ReplyClosure(T* output) { |
| // Intermediary pointer used to help the compiler distinguish between |
| // the overloaded Reply() functions. |
| void (WebRtcEventLogManagerTestBase::*function)(T*, T) = |
| &WebRtcEventLogManagerTestBase::Reply; |
| return base::BindOnce(function, base::Unretained(this), output); |
| } |
| |
| void Reply(bool* output_bool, |
| std::string* output_str1, |
| std::string* output_str2, |
| bool bool_val, |
| const std::string& str1_val, |
| const std::string& str2_val) { |
| *output_bool = bool_val; |
| *output_str1 = str1_val; |
| *output_str2 = str2_val; |
| run_loop_->QuitWhenIdle(); |
| } |
| |
| base::OnceCallback<void(bool, const std::string&, const std::string&)> |
| ReplyClosure(bool* output_bool, |
| std::string* output_str1, |
| std::string* output_str2) { |
| // Intermediary pointer used to help the compiler distinguish between |
| // the overloaded Reply() functions. |
| void (WebRtcEventLogManagerTestBase::*function)( |
| bool*, std::string*, std::string*, bool, const std::string&, |
| const std::string&) = &WebRtcEventLogManagerTestBase::Reply; |
| return base::BindOnce(function, base::Unretained(this), output_bool, |
| output_str1, output_str2); |
| } |
| |
| bool PeerConnectionAdded(const PeerConnectionKey& key, |
| std::string peer_connection_id = std::string()) { |
| if (peer_connection_id.empty()) { |
| // If the test does not specify an explicit peer connection ID, then that |
| // is not the focus of the test, and any unique identifier would do. |
| peer_connection_id = GetUniqueId(key.render_process_id, key.lid); |
| } |
| |
| bool result; |
| event_log_manager_->PeerConnectionAdded(key.render_process_id, key.lid, |
| peer_connection_id, |
| ReplyClosure(&result)); |
| WaitForReply(); |
| return result; |
| } |
| |
| bool PeerConnectionRemoved(const PeerConnectionKey& key) { |
| bool result; |
| event_log_manager_->PeerConnectionRemoved(key.render_process_id, key.lid, |
| ReplyClosure(&result)); |
| WaitForReply(); |
| return result; |
| } |
| |
| bool PeerConnectionStopped(const PeerConnectionKey& key) { |
| bool result; |
| event_log_manager_->PeerConnectionStopped(key.render_process_id, key.lid, |
| ReplyClosure(&result)); |
| WaitForReply(); |
| return result; |
| } |
| |
| bool EnableLocalLogging( |
| size_t max_size_bytes = kWebRtcEventLogManagerUnlimitedFileSize) { |
| return EnableLocalLogging(local_logs_base_path_, max_size_bytes); |
| } |
| |
| bool EnableLocalLogging( |
| base::FilePath local_logs_base_path, |
| size_t max_size_bytes = kWebRtcEventLogManagerUnlimitedFileSize) { |
| bool result; |
| event_log_manager_->EnableLocalLogging(local_logs_base_path, max_size_bytes, |
| ReplyClosure(&result)); |
| WaitForReply(); |
| return result; |
| } |
| |
| bool DisableLocalLogging() { |
| bool result; |
| event_log_manager_->DisableLocalLogging(ReplyClosure(&result)); |
| WaitForReply(); |
| return result; |
| } |
| |
| bool StartRemoteLogging(int render_process_id, |
| const std::string& peer_connection_id, |
| size_t max_size_bytes, |
| std::string* log_id_output = nullptr, |
| std::string* error_message_output = nullptr) { |
| bool result; |
| std::string log_id; |
| std::string error_message; |
| |
| event_log_manager_->StartRemoteLogging( |
| render_process_id, peer_connection_id, max_size_bytes, |
| ReplyClosure(&result, &log_id, &error_message)); |
| |
| WaitForReply(); |
| |
| // If successful, only |log_id|. If unsuccessful, only |error_message| set. |
| DCHECK_EQ(result, !log_id.empty()); |
| DCHECK_EQ(!result, !error_message.empty()); |
| |
| if (error_message_output) { |
| *error_message_output = error_message; |
| } |
| |
| if (log_id_output) { |
| *log_id_output = log_id; |
| } |
| |
| return result; |
| } |
| |
| bool StartRemoteLogging(int render_process_id, |
| const std::string& peer_connection_id, |
| std::string* log_id_output = nullptr, |
| std::string* error_message_output = nullptr) { |
| return StartRemoteLogging(render_process_id, peer_connection_id, |
| kMaxRemoteLogFileSizeBytes, log_id_output, |
| error_message_output); |
| } |
| |
| bool StartRemoteLogging(const PeerConnectionKey& key, |
| std::string* log_id_output = nullptr, |
| std::string* error_message_output = nullptr) { |
| return StartRemoteLogging(key.render_process_id, GetUniqueId(key), |
| kMaxRemoteLogFileSizeBytes, log_id_output, |
| error_message_output); |
| } |
| |
| bool StartRemoteLogging(const PeerConnectionKey& key, size_t max_size_bytes) { |
| return StartRemoteLogging(key.render_process_id, GetUniqueId(key), |
| max_size_bytes); |
| } |
| |
| void ClearCacheForBrowserContext( |
| const content::BrowserContext* browser_context, |
| const base::Time& delete_begin, |
| const base::Time& delete_end) { |
| event_log_manager_->ClearCacheForBrowserContext( |
| browser_context, delete_begin, delete_end, ReplyClosure()); |
| WaitForReply(); |
| } |
| |
| void SetLocalLogsObserver(WebRtcLocalEventLogsObserver* observer) { |
| event_log_manager_->SetLocalLogsObserver(observer, ReplyClosure()); |
| WaitForReply(); |
| } |
| |
| void SetRemoteLogsObserver(WebRtcRemoteEventLogsObserver* observer) { |
| event_log_manager_->SetRemoteLogsObserver(observer, ReplyClosure()); |
| WaitForReply(); |
| } |
| |
| void SetWebRtcEventLogUploaderFactoryForTesting( |
| std::unique_ptr<WebRtcEventLogUploader::Factory> factory) { |
| event_log_manager_->SetWebRtcEventLogUploaderFactoryForTesting( |
| std::move(factory), ReplyClosure()); |
| WaitForReply(); |
| } |
| |
| std::pair<bool, bool> OnWebRtcEventLogWrite(const PeerConnectionKey& key, |
| const std::string& message) { |
| std::pair<bool, bool> result; |
| event_log_manager_->OnWebRtcEventLogWrite(key.render_process_id, key.lid, |
| message, ReplyClosure(&result)); |
| WaitForReply(); |
| return result; |
| } |
| |
| void FreezeClockAt(const base::Time::Exploded& frozen_time_exploded) { |
| base::Time frozen_time; |
| ASSERT_TRUE( |
| base::Time::FromLocalExploded(frozen_time_exploded, &frozen_time)); |
| frozen_clock_.SetNow(frozen_time); |
| event_log_manager_->SetClockForTesting(&frozen_clock_, ReplyClosure()); |
| WaitForReply(); |
| } |
| |
| void SetWebRtcEventLoggingState(const PeerConnectionKey& key, |
| bool event_logging_enabled) { |
| webrtc_state_change_instructions_.emplace(key, event_logging_enabled); |
| } |
| |
| void ExpectWebRtcStateChangeInstruction(const PeerConnectionKey& key, |
| bool enabled) { |
| ASSERT_FALSE(webrtc_state_change_instructions_.empty()); |
| auto& instruction = webrtc_state_change_instructions_.front(); |
| EXPECT_EQ(instruction.key.render_process_id, key.render_process_id); |
| EXPECT_EQ(instruction.key.lid, key.lid); |
| EXPECT_EQ(instruction.enabled, enabled); |
| webrtc_state_change_instructions_.pop(); |
| } |
| |
| void SetPeerConnectionTrackerProxyForTesting( |
| std::unique_ptr<WebRtcEventLogManager::PeerConnectionTrackerProxy> |
| pc_tracker_proxy) { |
| event_log_manager_->SetPeerConnectionTrackerProxyForTesting( |
| std::move(pc_tracker_proxy), ReplyClosure()); |
| WaitForReply(); |
| } |
| |
| // Allows either creating a TestingProfile with a predetermined name |
| // (useful when trying to "reload" a profile), or one with an arbitrary name. |
| virtual std::unique_ptr<TestingProfile> CreateBrowserContext() { |
| return CreateBrowserContext(""); |
| } |
| virtual std::unique_ptr<TestingProfile> CreateBrowserContext( |
| std::string profile_name) { |
| return CreateBrowserContext(profile_name, true); |
| } |
| virtual std::unique_ptr<TestingProfile> CreateBrowserContext( |
| std::string profile_name, |
| bool policy_allows_remote_logging) { |
| // If profile name not specified, select a unique name. |
| if (profile_name.empty()) { |
| static size_t index = 0; |
| profile_name = std::to_string(++index); |
| } |
| |
| // Set a directory for the profile, derived from its name, so that |
| // recreating the profile will get the same directory. |
| const base::FilePath profile_path = |
| profiles_dir_.GetPath().AppendASCII(profile_name); |
| if (base::PathExists(profile_path)) { |
| EXPECT_TRUE(base::DirectoryExists(profile_path)); |
| } else { |
| EXPECT_TRUE(base::CreateDirectory(profile_path)); |
| } |
| |
| // Prepare to specify preferences for the profile. |
| sync_preferences::PrefServiceMockFactory factory; |
| factory.set_user_prefs(base::WrapRefCounted(new TestingPrefStore())); |
| scoped_refptr<user_prefs::PrefRegistrySyncable> registry( |
| new user_prefs::PrefRegistrySyncable); |
| sync_preferences::PrefServiceSyncable* regular_prefs = |
| factory.CreateSyncable(registry.get()).release(); |
| |
| // Set the preference associated with the policy for WebRTC remote-bound |
| // event logging. |
| RegisterUserProfilePrefs(registry.get()); |
| regular_prefs->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed, |
| policy_allows_remote_logging); |
| |
| // Build the profile. |
| TestingProfile::Builder profile_builder; |
| profile_builder.SetProfileName(profile_name); |
| profile_builder.SetPath(profile_path); |
| profile_builder.SetPrefService(base::WrapUnique(regular_prefs)); |
| std::unique_ptr<TestingProfile> browser_context = profile_builder.Build(); |
| |
| // Blocks on the unit under test's task runner, so that we won't proceed |
| // with the test (e.g. check that files were created) before finished |
| // processing this even (which is signaled to it from |
| // BrowserContext::EnableForBrowserContext). |
| WaitForPendingTasks(); |
| |
| return browser_context; |
| } |
| |
| base::FilePath RemoteBoundLogsDir( |
| const BrowserContext* browser_context) const { |
| return RemoteBoundLogsDir(browser_context->GetPath()); |
| } |
| |
| base::FilePath RemoteBoundLogsDir( |
| const base::FilePath& browser_context_base_dir) const { |
| return GetRemoteBoundWebRtcEventLogsDir(browser_context_base_dir); |
| } |
| |
| // Initiate an arbitrary synchronous operation, allowing any tasks pending |
| // on the manager's internal task queue to be completed. |
| // If given a RunLoop, we first block on it. The reason to do both is that |
| // with the RunLoop we wait on some tasks which we know also post additional |
| // tasks, then, after that chain is completed, we also wait for any potential |
| // leftovers. For example, the run loop could wait for n-1 files to be |
| // uploaded, then it is released when the last one's upload is initiated, |
| // then we wait for the last file's upload to be completed. |
| void WaitForPendingTasks(base::RunLoop* run_loop = nullptr) { |
| if (run_loop) { |
| run_loop->Run(); |
| } |
| |
| base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, |
| base::WaitableEvent::InitialState::NOT_SIGNALED); |
| event_log_manager_->GetTaskRunnerForTesting()->PostTask( |
| FROM_HERE, |
| base::BindOnce([](base::WaitableEvent* event) { event->Signal(); }, |
| &event)); |
| event.Wait(); |
| } |
| |
| void SuppressUploading() { |
| if (!upload_suppressing_browser_context_) { // First suppression. |
| upload_suppressing_browser_context_ = CreateBrowserContext(); |
| } |
| DCHECK(!upload_suppressing_rph_) << "Uploading already suppressed."; |
| upload_suppressing_rph_ = std::make_unique<MockRenderProcessHost>( |
| upload_suppressing_browser_context_.get()); |
| const auto key = GetPeerConnectionKey(upload_suppressing_rph_.get(), 0); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| } |
| |
| void UnsuppressUploading() { |
| DCHECK(upload_suppressing_rph_) << "Uploading not suppressed."; |
| const auto key = GetPeerConnectionKey(upload_suppressing_rph_.get(), 0); |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| upload_suppressing_rph_.reset(); |
| } |
| |
| void ExpectLocalFileContents(const base::FilePath& file_path, |
| const std::string& expected_contents) { |
| std::string file_contents; |
| ASSERT_TRUE(base::ReadFileToString(file_path, &file_contents)); |
| EXPECT_EQ(file_contents, expected_contents); |
| } |
| |
| void ExpectRemoteFileContents(const base::FilePath& file_path, |
| const std::string& expected_event_log) { |
| std::string file_contents; |
| ASSERT_TRUE(base::ReadFileToString(file_path, &file_contents)); |
| |
| if (remote_log_extension_ == kWebRtcEventLogUncompressedExtension) { |
| EXPECT_EQ(file_contents, expected_event_log); |
| } else if (remote_log_extension_ == kWebRtcEventLogGzippedExtension) { |
| std::string uncompressed_log; |
| ASSERT_TRUE( |
| compression::GzipUncompress(file_contents, &uncompressed_log)); |
| EXPECT_EQ(uncompressed_log, expected_event_log); |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| // When the peer connection's ID is not the focus of the test, this allows |
| // us to conveniently assign unique IDs to peer connections. |
| std::string GetUniqueId(int render_process_id, int lid) { |
| return std::to_string(render_process_id) + "_" + std::to_string(lid); |
| } |
| std::string GetUniqueId(const PeerConnectionKey& key) { |
| return GetUniqueId(key.render_process_id, key.lid); |
| } |
| |
| bool UploadConditionsHold() { |
| base::RunLoop run_loop; |
| bool result; |
| |
| auto callback = [](base::RunLoop* run_loop, bool* result_out, bool result) { |
| *result_out = result; |
| run_loop->QuitWhenIdle(); |
| }; |
| |
| event_log_manager_->UploadConditionsHoldForTesting( |
| base::BindOnce(callback, &run_loop, &result)); |
| run_loop.Run(); |
| |
| return result; |
| } |
| |
| // Testing utilities. |
| content::TestBrowserThreadBundle test_browser_thread_bundle_; |
| base::test::ScopedFeatureList scoped_feature_list_; |
| base::test::ScopedCommandLine scoped_command_line_; |
| base::SimpleTestClock frozen_clock_; |
| network::TestURLLoaderFactory test_url_loader_factory_; |
| scoped_refptr<network::SharedURLLoaderFactory> |
| test_shared_url_loader_factory_; |
| |
| // The main loop, which allows waiting for the operations invoked on the |
| // unit-under-test to be completed. Do not use this object directly from the |
| // tests, since that would be error-prone. (Specifically, one must not produce |
| // two events that could produce replies, without waiting on the first reply |
| // in between.) |
| std::unique_ptr<base::RunLoop> run_loop_; |
| |
| // Allows waiting for upload operations. |
| std::unique_ptr<base::RunLoop> uploader_run_loop_; |
| |
| // Unit under test. |
| std::unique_ptr<WebRtcEventLogManager> event_log_manager_; |
| |
| // The NetworkConnectionTracker instance used by the WebRtcEventLogManager. |
| std::unique_ptr<network::NetworkConnectionTracker> |
| network_connection_tracker_; |
| |
| // Extensions associated with local/remote-bound event logs. Depends on |
| // whether they're compressed. |
| base::FilePath::StringPieceType local_log_extension_; |
| base::FilePath::StringPieceType remote_log_extension_; |
| |
| // The directory which will contain all profiles. |
| base::ScopedTempDir profiles_dir_; |
| |
| // Default BrowserContext and RenderProcessHost, to be used by tests which |
| // do not require anything fancy (such as seeding the BrowserContext with |
| // pre-existing logs files from a previous session, or working with multiple |
| // BrowserContext objects). |
| |
| std::unique_ptr<TestingProfile> browser_context_; |
| BrowserContextId browser_context_id_; |
| std::unique_ptr<MockRenderProcessHost> rph_; |
| |
| // Used for suppressing the upload of finished files, by creating an active |
| // remote-bound log associated with an independent BrowserContext which |
| // does not otherwise interfere with the test. |
| std::unique_ptr<TestingProfile> upload_suppressing_browser_context_; |
| std::unique_ptr<MockRenderProcessHost> upload_suppressing_rph_; |
| |
| // The directory where we'll save local log files. |
| base::ScopedTempDir local_logs_base_dir_; |
| // local_logs_base_dir_ + log files' name prefix. |
| base::FilePath local_logs_base_path_; |
| |
| // WebRtcEventLogManager instructs WebRTC, via PeerConnectionTracker, to |
| // only send WebRTC messages for certain peer connections. Some tests make |
| // sure that this is done correctly, by waiting for these notifications, then |
| // testing them. |
| // Because a single action - disabling of local logging - could crease a |
| // series of such instructions, we keep a queue of them. However, were one |
| // to actually test that scenario, one would have to account for the lack |
| // of a guarantee over the order in which these instructions are produced. |
| struct WebRtcStateChangeInstruction { |
| WebRtcStateChangeInstruction(PeerConnectionKey key, bool enabled) |
| : key(key), enabled(enabled) {} |
| PeerConnectionKey key; |
| bool enabled; |
| }; |
| std::queue<WebRtcStateChangeInstruction> webrtc_state_change_instructions_; |
| |
| // Observers for local/remote logging being started/stopped. By having them |
| // here, we achieve two goals: |
| // 1. Reduce boilerplate in the tests themselves. |
| // 2. Avoid lifetime issues, where the observer might be deallocated before |
| // a RenderProcessHost is deallocated (which can potentially trigger a |
| // callback on the observer). |
| NiceMock<MockWebRtcLocalEventLogsObserver> local_observer_; |
| NiceMock<MockWebRtcRemoteEventLogsObserver> remote_observer_; |
| |
| DISALLOW_COPY_AND_ASSIGN(WebRtcEventLogManagerTestBase); |
| }; |
| |
| #if !defined(OS_ANDROID) |
| |
| class WebRtcEventLogManagerTest : public WebRtcEventLogManagerTestBase, |
| public ::testing::WithParamInterface<bool> { |
| public: |
| WebRtcEventLogManagerTest() { |
| scoped_feature_list_.InitAndEnableFeature(features::kWebRtcRemoteEventLog); |
| |
| // Use a low delay, or the tests would run for quite a long time. |
| scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII( |
| ::switches::kWebRtcRemoteEventLogUploadDelayMs, "100"); |
| } |
| |
| ~WebRtcEventLogManagerTest() override = default; |
| |
| void SetUp() override { |
| CreateWebRtcEventLogManager(Compression::GZIP_PERFECT_ESTIMATION); |
| |
| auto tracker = std::make_unique<network::TestNetworkConnectionTracker>( |
| true, network::mojom::ConnectionType::CONNECTION_ETHERNET); |
| WebRtcEventLogManagerTestBase::SetUp(std::move(tracker)); |
| |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<NullWebRtcEventLogUploader::Factory>(false)); |
| } |
| }; |
| |
| class WebRtcEventLogManagerTestCacheClearing |
| : public WebRtcEventLogManagerTest { |
| public: |
| ~WebRtcEventLogManagerTestCacheClearing() override = default; |
| |
| void CreatePendingLogFiles(BrowserContext* browser_context) { |
| ASSERT_TRUE(pending_logs_.find(browser_context) == pending_logs_.end()); |
| auto& elements = pending_logs_[browser_context]; |
| elements = std::make_unique<BrowserContextAssociatedElements>(); |
| |
| for (size_t i = 0; i < kMaxActiveRemoteBoundWebRtcEventLogs; ++i) { |
| elements->rphs.push_back( |
| std::make_unique<MockRenderProcessHost>(browser_context)); |
| const auto key = GetPeerConnectionKey(elements->rphs[i].get(), kLid); |
| elements->file_paths.push_back(CreatePendingRemoteLogFile(key)); |
| ASSERT_TRUE(elements->file_paths[i]); |
| ASSERT_TRUE(base::PathExists(*elements->file_paths[i])); |
| |
| pending_latest_mod_ = GetLastModificationTime(*elements->file_paths[i]); |
| if (pending_earliest_mod_.is_null()) { // First file. |
| pending_earliest_mod_ = pending_latest_mod_; |
| } |
| } |
| } |
| |
| void ClearPendingLogFiles() { pending_logs_.clear(); } |
| |
| base::Optional<base::FilePath> CreateRemoteLogFile( |
| const PeerConnectionKey& key, |
| bool pending) { |
| base::Optional<base::FilePath> file_path; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_path))); |
| EXPECT_TRUE(PeerConnectionAdded(key)); |
| EXPECT_TRUE(StartRemoteLogging(key)); |
| if (pending) { |
| // Transition from ACTIVE to PENDING. |
| EXPECT_TRUE(PeerConnectionRemoved(key)); |
| } |
| return file_path; |
| } |
| |
| base::Optional<base::FilePath> CreateActiveRemoteLogFile( |
| const PeerConnectionKey& key) { |
| return CreateRemoteLogFile(key, false); |
| } |
| |
| base::Optional<base::FilePath> CreatePendingRemoteLogFile( |
| const PeerConnectionKey& key) { |
| return CreateRemoteLogFile(key, true); |
| } |
| |
| protected: |
| // When closing a file, rather than check its last modification date, which |
| // is potentially expensive, WebRtcRemoteEventLogManager reads the system |
| // clock, which should be close enough. For tests, however, the difference |
| // could be enough to flake the tests, if not for this epsilon. Given the |
| // focus of the tests that use this, this epsilon can be arbitrarily large. |
| static const base::TimeDelta kEpsion; |
| |
| struct BrowserContextAssociatedElements { |
| std::vector<std::unique_ptr<MockRenderProcessHost>> rphs; |
| std::vector<base::Optional<base::FilePath>> file_paths; |
| }; |
| |
| std::map<const BrowserContext*, |
| std::unique_ptr<BrowserContextAssociatedElements>> |
| pending_logs_; |
| |
| // Latest modification times of earliest and latest pending log files. |
| base::Time pending_earliest_mod_; |
| base::Time pending_latest_mod_; |
| }; |
| |
| const base::TimeDelta WebRtcEventLogManagerTestCacheClearing::kEpsion = |
| base::TimeDelta::FromHours(1); |
| |
| class WebRtcEventLogManagerTestWithRemoteLoggingDisabled |
| : public WebRtcEventLogManagerTestBase, |
| public ::testing::WithParamInterface<bool> { |
| public: |
| WebRtcEventLogManagerTestWithRemoteLoggingDisabled() |
| : feature_enabled_(GetParam()), policy_enabled_(!feature_enabled_) { |
| if (feature_enabled_) { |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kWebRtcRemoteEventLog); |
| } else { |
| scoped_feature_list_.InitAndDisableFeature( |
| features::kWebRtcRemoteEventLog); |
| } |
| CreateWebRtcEventLogManager(); |
| } |
| |
| ~WebRtcEventLogManagerTestWithRemoteLoggingDisabled() override = default; |
| |
| // Override CreateBrowserContext() to use policy_enabled_. |
| std::unique_ptr<TestingProfile> CreateBrowserContext() override { |
| return CreateBrowserContext(""); |
| } |
| std::unique_ptr<TestingProfile> CreateBrowserContext( |
| std::string profile_name) override { |
| return CreateBrowserContext(profile_name, policy_enabled_); |
| } |
| std::unique_ptr<TestingProfile> CreateBrowserContext( |
| std::string profile_name, |
| bool policy_allows_remote_logging) override { |
| DCHECK_EQ(policy_enabled_, policy_allows_remote_logging); |
| return WebRtcEventLogManagerTestBase::CreateBrowserContext( |
| profile_name, policy_allows_remote_logging); |
| } |
| |
| private: |
| const bool feature_enabled_; // Whether the Finch kill-switch is engaged. |
| const bool policy_enabled_; // Whether the policy is enabled for the profile. |
| }; |
| |
| class WebRtcEventLogManagerTestPolicy : public WebRtcEventLogManagerTestBase { |
| public: |
| ~WebRtcEventLogManagerTestPolicy() override = default; |
| |
| // Defer to setup from the body. |
| void SetUp() override {} |
| |
| void SetUp(bool feature_enabled) { |
| if (feature_enabled) { |
| scoped_feature_list_.InitAndEnableFeature( |
| features::kWebRtcRemoteEventLog); |
| } else { |
| scoped_feature_list_.InitAndDisableFeature( |
| features::kWebRtcRemoteEventLog); |
| } |
| |
| // Avoid proactive pruning; it has the potential to mess up tests, as well |
| // as keep pendings tasks around with a dangling reference to the unit |
| // under test. (Zero is a sentinel value for disabling proactive pruning.) |
| scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII( |
| ::switches::kWebRtcRemoteEventLogUploadDelayMs, "0"); |
| |
| CreateWebRtcEventLogManager(Compression::GZIP_PERFECT_ESTIMATION); |
| |
| WebRtcEventLogManagerTestBase::SetUp(); |
| } |
| }; |
| |
| class WebRtcEventLogManagerTestUploadSuppressionDisablingFlag |
| : public WebRtcEventLogManagerTestBase { |
| public: |
| WebRtcEventLogManagerTestUploadSuppressionDisablingFlag() { |
| scoped_feature_list_.InitAndEnableFeature(features::kWebRtcRemoteEventLog); |
| |
| scoped_command_line_.GetProcessCommandLine()->AppendSwitch( |
| ::switches::kWebRtcRemoteEventLogUploadNoSuppression); |
| |
| // Use a low delay, or the tests would run for quite a long time. |
| scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII( |
| ::switches::kWebRtcRemoteEventLogUploadDelayMs, "100"); |
| |
| CreateWebRtcEventLogManager(); |
| } |
| |
| ~WebRtcEventLogManagerTestUploadSuppressionDisablingFlag() override = default; |
| }; |
| |
| class WebRtcEventLogManagerTestForNetworkConnectivity |
| : public WebRtcEventLogManagerTestBase, |
| public ::testing::WithParamInterface< |
| std::tuple<bool, |
| network::mojom::ConnectionType, |
| network::mojom::ConnectionType>> { |
| public: |
| WebRtcEventLogManagerTestForNetworkConnectivity() |
| : get_conn_type_is_sync_(std::get<0>(GetParam())), |
| supported_type_(std::get<1>(GetParam())), |
| unsupported_type_(std::get<2>(GetParam())) { |
| scoped_feature_list_.InitAndEnableFeature(features::kWebRtcRemoteEventLog); |
| |
| // Use a low delay, or the tests would run for quite a long time. |
| scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII( |
| ::switches::kWebRtcRemoteEventLogUploadDelayMs, "100"); |
| |
| CreateWebRtcEventLogManager(); |
| } |
| |
| ~WebRtcEventLogManagerTestForNetworkConnectivity() override = default; |
| |
| void SetUp() override { |
| // Do nothing; the test body itself will call the super-class's SetUp |
| // with the correct MockNetworkConnectionTracker. |
| } |
| |
| void UnloadProfileAndSeedPendingLog() { |
| DCHECK(browser_context_path_.empty()) << "Not expected to be called twice."; |
| |
| // Unload the profile, but remember where it stores its files (for sanity). |
| browser_context_path_ = browser_context_->GetPath(); |
| const base::FilePath remote_logs_dir = |
| RemoteBoundLogsDir(browser_context_.get()); |
| UnloadMainTestProfile(); |
| |
| // Seed the remote logs' directory with one log file, simulating the |
| // creation of logs in a previous session. |
| ASSERT_TRUE(CreateDirectory(remote_logs_dir)); |
| |
| base::FilePath file_path; |
| ASSERT_TRUE(CreateRemoteBoundLogFile(remote_logs_dir, remote_log_extension_, |
| &file_path, &file_)); |
| |
| expected_files_.emplace_back(browser_context_id_, file_path, |
| GetLastModificationTime(file_path)); |
| } |
| |
| const bool get_conn_type_is_sync_; |
| const network::mojom::ConnectionType supported_type_; |
| const network::mojom::ConnectionType unsupported_type_; |
| |
| base::FilePath browser_context_path_; // For sanity over the test itself. |
| std::list<WebRtcLogFileInfo> expected_files_; |
| base::File file_; |
| }; |
| |
| class WebRtcEventLogManagerTestUploadDelay |
| : public WebRtcEventLogManagerTestBase { |
| public: |
| ~WebRtcEventLogManagerTestUploadDelay() override = default; |
| |
| void SetUp() override { |
| // Intercept and block the call to SetUp(). The test body will call |
| // the version that sets an upload delay instead. |
| } |
| |
| void SetUp(size_t upload_delay_ms) { |
| scoped_feature_list_.InitAndEnableFeature(features::kWebRtcRemoteEventLog); |
| |
| scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII( |
| ::switches::kWebRtcRemoteEventLogUploadDelayMs, |
| std::to_string(upload_delay_ms)); |
| |
| CreateWebRtcEventLogManager(); |
| |
| WebRtcEventLogManagerTestBase::SetUp(); |
| } |
| |
| // There's a trade-off between the test runtime and the likelihood of a |
| // false-positive (lowered when the time is increased). |
| // Since false-positives can be caught handled even if only manifesting |
| // occasionally, this value should be enough. |
| static const size_t kDefaultUploadDelayMs = 500; |
| |
| // For tests where we don't intend to wait, prevent flakiness by setting |
| // an unrealistically long delay. |
| static const size_t kIntentionallyExcessiveDelayMs = 1000 * 1000 * 1000; |
| }; |
| |
| // For testing compression issues. |
| class WebRtcEventLogManagerTestCompression |
| : public WebRtcEventLogManagerTestBase { |
| public: |
| WebRtcEventLogManagerTestCompression() { |
| scoped_feature_list_.InitAndEnableFeature(features::kWebRtcRemoteEventLog); |
| |
| // Avoid proactive pruning; it has the potential to mess up tests, as well |
| // as keep pendings tasks around with a dangling reference to the unit |
| // under test. (Zero is a sentinel value for disabling proactive pruning.) |
| scoped_command_line_.GetProcessCommandLine()->AppendSwitchASCII( |
| ::switches::kWebRtcRemoteEventLogUploadDelayMs, "0"); |
| } |
| |
| ~WebRtcEventLogManagerTestCompression() override = default; |
| |
| void SetUp() override { |
| // Defer until Init(), which will allow the test body more control. |
| } |
| |
| void Init(base::Optional<WebRtcEventLogCompression> remote_compression = |
| base::Optional<WebRtcEventLogCompression>()) { |
| CreateWebRtcEventLogManager(remote_compression); |
| |
| auto tracker = std::make_unique<network::TestNetworkConnectionTracker>( |
| true, network::mojom::ConnectionType::CONNECTION_ETHERNET); |
| WebRtcEventLogManagerTestBase::SetUp(std::move(tracker)); |
| } |
| }; |
| |
| class WebRtcEventLogManagerTestIncognito |
| : public WebRtcEventLogManagerTestBase { |
| public: |
| WebRtcEventLogManagerTestIncognito() : incognito_profile_(nullptr) { |
| scoped_feature_list_.InitAndEnableFeature(features::kWebRtcRemoteEventLog); |
| CreateWebRtcEventLogManager(); |
| } |
| |
| ~WebRtcEventLogManagerTestIncognito() override { |
| incognito_rph_.reset(); |
| if (incognito_profile_) { |
| DCHECK(browser_context_); |
| browser_context_->DestroyOffTheRecordProfile(); |
| } |
| } |
| |
| void SetUp() override { |
| WebRtcEventLogManagerTestBase::SetUp(); |
| |
| incognito_profile_ = browser_context_->GetOffTheRecordProfile(); |
| incognito_rph_ = |
| std::make_unique<MockRenderProcessHost>(incognito_profile_); |
| } |
| |
| Profile* incognito_profile_; |
| std::unique_ptr<MockRenderProcessHost> incognito_rph_; |
| }; |
| |
| namespace { |
| |
| class PeerConnectionTrackerProxyForTesting |
| : public WebRtcEventLogManager::PeerConnectionTrackerProxy { |
| public: |
| explicit PeerConnectionTrackerProxyForTesting( |
| WebRtcEventLogManagerTestBase* test) |
| : test_(test) {} |
| |
| ~PeerConnectionTrackerProxyForTesting() override = default; |
| |
| void SetWebRtcEventLoggingState(const PeerConnectionKey& key, |
| bool event_logging_enabled) override { |
| test_->SetWebRtcEventLoggingState(key, event_logging_enabled); |
| } |
| |
| private: |
| WebRtcEventLogManagerTestBase* const test_; |
| }; |
| |
| // The factory for the following fake uploader produces a sequence of |
| // uploaders which fail the test if given a file other than that which they |
| // expect. The factory itself likewise fails the test if destroyed before |
| // producing all expected uploaders, or if it's asked for more uploaders than |
| // it expects to create. This allows us to test for sequences of uploads. |
| class FileListExpectingWebRtcEventLogUploader : public WebRtcEventLogUploader { |
| public: |
| class Factory : public WebRtcEventLogUploader::Factory { |
| public: |
| Factory(std::list<WebRtcLogFileInfo>* expected_files, |
| bool result, |
| base::RunLoop* run_loop) |
| : result_(result), run_loop_(run_loop) { |
| expected_files_.swap(*expected_files); |
| if (expected_files_.empty()) { |
| run_loop_->QuitWhenIdle(); |
| } |
| } |
| |
| ~Factory() override { EXPECT_TRUE(expected_files_.empty()); } |
| |
| std::unique_ptr<WebRtcEventLogUploader> Create( |
| const WebRtcLogFileInfo& log_file, |
| UploadResultCallback callback) override { |
| if (expected_files_.empty()) { |
| EXPECT_FALSE(true); // More files uploaded than expected. |
| } else { |
| EXPECT_EQ(log_file.path, expected_files_.front().path); |
| // Because LoadMainTestProfile() and UnloadMainTestProfile() mess up the |
| // BrowserContextId in ways that would not happen in production, |
| // we cannot verify |log_file.browser_context_id| is correct. |
| // This is unimportant to the test. |
| |
| base::DeleteFile(log_file.path, false); |
| expected_files_.pop_front(); |
| } |
| |
| if (expected_files_.empty()) { |
| run_loop_->QuitWhenIdle(); |
| } |
| |
| return std::make_unique<FileListExpectingWebRtcEventLogUploader>( |
| log_file, result_, std::move(callback)); |
| } |
| |
| private: |
| std::list<WebRtcLogFileInfo> expected_files_; |
| const bool result_; |
| base::RunLoop* const run_loop_; |
| }; |
| |
| // The logic is in the factory; the uploader just reports success so that the |
| // next file may become eligible for uploading. |
| FileListExpectingWebRtcEventLogUploader(const WebRtcLogFileInfo& log_file, |
| bool result, |
| UploadResultCallback callback) |
| : log_file_(log_file) { |
| base::SequencedTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::BindOnce(std::move(callback), log_file_.path, result)); |
| } |
| |
| ~FileListExpectingWebRtcEventLogUploader() override = default; |
| |
| const WebRtcLogFileInfo& GetWebRtcLogFileInfo() const override { |
| return log_file_; |
| } |
| |
| bool Cancel() override { |
| NOTREACHED() << "Incompatible with this kind of test."; |
| return true; |
| } |
| |
| private: |
| const WebRtcLogFileInfo log_file_; |
| }; |
| |
| } // namespace |
| |
| TEST_F(WebRtcEventLogManagerTest, PeerConnectionAddedReturnsTrue) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| EXPECT_TRUE(PeerConnectionAdded(key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| PeerConnectionAddedReturnsFalseIfAlreadyAdded) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| EXPECT_FALSE(PeerConnectionAdded(key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, PeerConnectionRemovedReturnsTrue) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| EXPECT_TRUE(PeerConnectionRemoved(key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| PeerConnectionRemovedReturnsFalseIfNeverAdded) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| EXPECT_FALSE(PeerConnectionRemoved(key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| PeerConnectionRemovedReturnsFalseIfAlreadyRemoved) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| EXPECT_FALSE(PeerConnectionRemoved(key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, EnableLocalLoggingReturnsTrue) { |
| EXPECT_TRUE(EnableLocalLogging()); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| EnableLocalLoggingReturnsFalseIfCalledWhenAlreadyEnabled) { |
| ASSERT_TRUE(EnableLocalLogging()); |
| EXPECT_FALSE(EnableLocalLogging()); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, DisableLocalLoggingReturnsTrue) { |
| ASSERT_TRUE(EnableLocalLogging()); |
| EXPECT_TRUE(DisableLocalLogging()); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, DisableLocalLoggingReturnsIfNeverEnabled) { |
| EXPECT_FALSE(DisableLocalLogging()); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, DisableLocalLoggingReturnsIfAlreadyDisabled) { |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(DisableLocalLogging()); |
| EXPECT_FALSE(DisableLocalLogging()); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnWebRtcEventLogWriteReturnsFalseAndFalseWhenAllLoggingDisabled) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| // Note that EnableLocalLogging() and StartRemoteLogging() weren't called. |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| EXPECT_EQ(OnWebRtcEventLogWrite(key, "log"), std::make_pair(false, false)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnWebRtcEventLogWriteReturnsFalseAndFalseForUnknownPeerConnection) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(EnableLocalLogging()); |
| // Note that PeerConnectionAdded() wasn't called. |
| EXPECT_EQ(OnWebRtcEventLogWrite(key, "log"), std::make_pair(false, false)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnWebRtcEventLogWriteReturnsLocalTrueWhenPcKnownAndLocalLoggingOn) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| EXPECT_EQ(OnWebRtcEventLogWrite(key, "log"), std::make_pair(true, false)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnWebRtcEventLogWriteReturnsRemoteTrueWhenPcKnownAndRemoteLogging) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| EXPECT_EQ(OnWebRtcEventLogWrite(key, "log"), std::make_pair(false, true)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnWebRtcEventLogWriteReturnsTrueAndTrueeWhenAllLoggingEnabled) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| EXPECT_EQ(OnWebRtcEventLogWrite(key, "log"), std::make_pair(true, true)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnLocalLogStartedNotCalledIfLocalLoggingEnabledWithoutPeerConnections) { |
| EXPECT_CALL(local_observer_, OnLocalLogStarted(_, _)).Times(0); |
| ASSERT_TRUE(EnableLocalLogging()); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnLocalLogStoppedNotCalledIfLocalLoggingDisabledWithoutPeerConnections) { |
| EXPECT_CALL(local_observer_, OnLocalLogStopped(_)).Times(0); |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(DisableLocalLogging()); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnLocalLogStartedCalledForPeerConnectionAddedAndLocalLoggingEnabled) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| EXPECT_CALL(local_observer_, OnLocalLogStarted(key, _)).Times(1); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(EnableLocalLogging()); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnLocalLogStartedCalledForLocalLoggingEnabledAndPeerConnectionAdded) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| EXPECT_CALL(local_observer_, OnLocalLogStarted(key, _)).Times(1); |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnLocalLogStoppedCalledAfterLocalLoggingDisabled) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| EXPECT_CALL(local_observer_, OnLocalLogStopped(key)).Times(1); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(DisableLocalLogging()); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnLocalLogStoppedCalledAfterPeerConnectionRemoved) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| EXPECT_CALL(local_observer_, OnLocalLogStopped(key)).Times(1); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, LocalLogCreatesEmptyFileWhenStarted) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| base::Optional<base::FilePath> file_path; |
| ON_CALL(local_observer_, OnLocalLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_path))); |
| |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(file_path); |
| ASSERT_FALSE(file_path->empty()); |
| |
| // Make sure the file would be closed, so that we could safely read it. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| ExpectLocalFileContents(*file_path, ""); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, LocalLogCreateAndWriteToFile) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| base::Optional<base::FilePath> file_path; |
| ON_CALL(local_observer_, OnLocalLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_path))); |
| |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(file_path); |
| ASSERT_FALSE(file_path->empty()); |
| |
| const std::string log = "To strive, to seek, to find, and not to yield."; |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, log), std::make_pair(true, false)); |
| |
| // Make sure the file would be closed, so that we could safely read it. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| ExpectLocalFileContents(*file_path, log); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, LocalLogMultipleWritesToSameFile) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| base::Optional<base::FilePath> file_path; |
| ON_CALL(local_observer_, OnLocalLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_path))); |
| |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(file_path); |
| ASSERT_FALSE(file_path->empty()); |
| |
| const std::string logs[] = {"Old age hath yet his honour and his toil;", |
| "Death closes all: but something ere the end,", |
| "Some work of noble note, may yet be done,", |
| "Not unbecoming men that strove with Gods."}; |
| for (const std::string& log : logs) { |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, log), std::make_pair(true, false)); |
| } |
| |
| // Make sure the file would be closed, so that we could safely read it. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| ExpectLocalFileContents( |
| *file_path, |
| std::accumulate(std::begin(logs), std::end(logs), std::string())); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, LocalLogFileSizeLimitNotExceeded) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| base::Optional<base::FilePath> file_path; |
| ON_CALL(local_observer_, OnLocalLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_path))); |
| |
| const std::string log = "There lies the port; the vessel puffs her sail:"; |
| const size_t file_size_limit_bytes = log.length() / 2; |
| |
| ASSERT_TRUE(EnableLocalLogging(file_size_limit_bytes)); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(file_path); |
| ASSERT_FALSE(file_path->empty()); |
| |
| // Failure is reported, because not everything could be written. The file |
| // will also be closed. |
| EXPECT_CALL(local_observer_, OnLocalLogStopped(key)).Times(1); |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, log), std::make_pair(false, false)); |
| |
| // Additional calls to Write() have no effect. |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, "ignored"), |
| std::make_pair(false, false)); |
| |
| ExpectLocalFileContents(*file_path, ""); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, LocalLogSanityOverUnlimitedFileSizes) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| base::Optional<base::FilePath> file_path; |
| ON_CALL(local_observer_, OnLocalLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_path))); |
| |
| ASSERT_TRUE(EnableLocalLogging(kWebRtcEventLogManagerUnlimitedFileSize)); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(file_path); |
| ASSERT_FALSE(file_path->empty()); |
| |
| const std::string log1 = "Who let the dogs out?"; |
| const std::string log2 = "Woof, woof, woof, woof, woof!"; |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, log1), std::make_pair(true, false)); |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, log2), std::make_pair(true, false)); |
| |
| // Make sure the file would be closed, so that we could safely read it. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| ExpectLocalFileContents(*file_path, log1 + log2); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, LocalLogNoWriteAfterLogStopped) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| base::Optional<base::FilePath> file_path; |
| ON_CALL(local_observer_, OnLocalLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_path))); |
| |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(file_path); |
| ASSERT_FALSE(file_path->empty()); |
| |
| const std::string log_before = "log_before_stop"; |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, log_before), |
| std::make_pair(true, false)); |
| EXPECT_CALL(local_observer_, OnLocalLogStopped(key)).Times(1); |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| const std::string log_after = "log_after_stop"; |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, log_after), |
| std::make_pair(false, false)); |
| |
| ExpectLocalFileContents(*file_path, log_before); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, LocalLogOnlyWritesTheLogsAfterStarted) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| // Calls to Write() before the log was started are ignored. |
| EXPECT_CALL(local_observer_, OnLocalLogStarted(_, _)).Times(0); |
| const std::string log1 = "The lights begin to twinkle from the rocks:"; |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, log1), std::make_pair(false, false)); |
| ASSERT_TRUE(base::IsDirectoryEmpty(local_logs_base_dir_.GetPath())); |
| |
| base::Optional<base::FilePath> file_path; |
| EXPECT_CALL(local_observer_, OnLocalLogStarted(key, _)) |
| .Times(1) |
| .WillOnce(Invoke(SaveFilePathTo(&file_path))); |
| |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(file_path); |
| ASSERT_FALSE(file_path->empty()); |
| |
| // Calls after the log started have an effect. The calls to Write() from |
| // before the log started are not remembered. |
| const std::string log2 = "The long day wanes: the slow moon climbs: the deep"; |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, log2), std::make_pair(true, false)); |
| |
| // Make sure the file would be closed, so that we could safely read it. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| ExpectLocalFileContents(*file_path, log2); |
| } |
| |
| // Note: This test also covers the scenario LocalLogExistingFilesNotOverwritten, |
| // which is therefore not explicitly tested. |
| TEST_F(WebRtcEventLogManagerTest, LocalLoggingRestartCreatesNewFile) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| const std::vector<std::string> logs = {"<setup>", "<punchline>", "<encore>"}; |
| std::vector<base::Optional<PeerConnectionKey>> keys(logs.size()); |
| std::vector<base::Optional<base::FilePath>> file_paths(logs.size()); |
| |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| |
| for (size_t i = 0; i < logs.size(); ++i) { |
| ON_CALL(local_observer_, OnLocalLogStarted(_, _)) |
| .WillByDefault(Invoke(SaveKeyAndFilePathTo(&keys[i], &file_paths[i]))); |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(keys[i]); |
| ASSERT_EQ(*keys[i], key); |
| ASSERT_TRUE(file_paths[i]); |
| ASSERT_FALSE(file_paths[i]->empty()); |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, logs[i]), std::make_pair(true, false)); |
| ASSERT_TRUE(DisableLocalLogging()); |
| } |
| |
| for (size_t i = 0; i < logs.size(); ++i) { |
| ExpectLocalFileContents(*file_paths[i], logs[i]); |
| } |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, LocalLogMultipleActiveFiles) { |
| ASSERT_TRUE(EnableLocalLogging()); |
| |
| std::list<MockRenderProcessHost> rphs; |
| for (size_t i = 0; i < 3; ++i) { |
| rphs.emplace_back(browser_context_.get()); // (MockRenderProcessHost ctor) |
| } |
| |
| std::vector<PeerConnectionKey> keys; |
| for (auto& rph : rphs) { |
| keys.push_back(GetPeerConnectionKey(&rph, kLid)); |
| } |
| |
| std::vector<base::Optional<base::FilePath>> file_paths(keys.size()); |
| for (size_t i = 0; i < keys.size(); ++i) { |
| ON_CALL(local_observer_, OnLocalLogStarted(keys[i], _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_paths[i]))); |
| ASSERT_TRUE(PeerConnectionAdded(keys[i])); |
| ASSERT_TRUE(file_paths[i]); |
| ASSERT_FALSE(file_paths[i]->empty()); |
| } |
| |
| std::vector<std::string> logs; |
| for (size_t i = 0; i < keys.size(); ++i) { |
| logs.emplace_back(std::to_string(rph_->GetID()) + std::to_string(kLid)); |
| ASSERT_EQ(OnWebRtcEventLogWrite(keys[i], logs[i]), |
| std::make_pair(true, false)); |
| } |
| |
| // Make sure the file woulds be closed, so that we could safely read them. |
| ASSERT_TRUE(DisableLocalLogging()); |
| |
| for (size_t i = 0; i < keys.size(); ++i) { |
| ExpectLocalFileContents(*file_paths[i], logs[i]); |
| } |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, LocalLogLimitActiveLocalLogFiles) { |
| ASSERT_TRUE(EnableLocalLogging()); |
| |
| const int kMaxLocalLogFiles = |
| static_cast<int>(kMaxNumberLocalWebRtcEventLogFiles); |
| for (int i = 0; i < kMaxLocalLogFiles; ++i) { |
| const auto key = GetPeerConnectionKey(rph_.get(), i); |
| EXPECT_CALL(local_observer_, OnLocalLogStarted(key, _)).Times(1); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| } |
| |
| EXPECT_CALL(local_observer_, OnLocalLogStarted(_, _)).Times(0); |
| const auto last_key = GetPeerConnectionKey(rph_.get(), kMaxLocalLogFiles); |
| ASSERT_TRUE(PeerConnectionAdded(last_key)); |
| } |
| |
| // When a log reaches its maximum size limit, it is closed, and no longer |
| // counted towards the limit. |
| TEST_F(WebRtcEventLogManagerTest, LocalLogFilledLogNotCountedTowardsLogsLimit) { |
| const std::string log = "very_short_log"; |
| ASSERT_TRUE(EnableLocalLogging(log.size())); |
| |
| const int kMaxLocalLogFiles = |
| static_cast<int>(kMaxNumberLocalWebRtcEventLogFiles); |
| for (int i = 0; i < kMaxLocalLogFiles; ++i) { |
| const auto key = GetPeerConnectionKey(rph_.get(), i); |
| EXPECT_CALL(local_observer_, OnLocalLogStarted(key, _)).Times(1); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| } |
| |
| // By writing to one of the logs, we fill it and end up closing it, allowing |
| // an additional log to be written. |
| const auto removed_key = GetPeerConnectionKey(rph_.get(), 0); |
| EXPECT_EQ(OnWebRtcEventLogWrite(removed_key, log), |
| std::make_pair(true, false)); |
| |
| // We now have room for one additional log. |
| const auto last_key = GetPeerConnectionKey(rph_.get(), kMaxLocalLogFiles); |
| EXPECT_CALL(local_observer_, OnLocalLogStarted(last_key, _)).Times(1); |
| ASSERT_TRUE(PeerConnectionAdded(last_key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| LocalLogForRemovedPeerConnectionNotCountedTowardsLogsLimit) { |
| ASSERT_TRUE(EnableLocalLogging()); |
| |
| const int kMaxLocalLogFiles = |
| static_cast<int>(kMaxNumberLocalWebRtcEventLogFiles); |
| for (int i = 0; i < kMaxLocalLogFiles; ++i) { |
| const auto key = GetPeerConnectionKey(rph_.get(), i); |
| EXPECT_CALL(local_observer_, OnLocalLogStarted(key, _)).Times(1); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| } |
| |
| // When one peer connection is removed, one log is stopped, thereby allowing |
| // an additional log to be opened. |
| const auto removed_key = GetPeerConnectionKey(rph_.get(), 0); |
| EXPECT_CALL(local_observer_, OnLocalLogStopped(removed_key)).Times(1); |
| ASSERT_TRUE(PeerConnectionRemoved(removed_key)); |
| |
| // We now have room for one additional log. |
| const auto last_key = GetPeerConnectionKey(rph_.get(), kMaxLocalLogFiles); |
| EXPECT_CALL(local_observer_, OnLocalLogStarted(last_key, _)).Times(1); |
| ASSERT_TRUE(PeerConnectionAdded(last_key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, LocalLogIllegalPath) { |
| // Since the log file won't be properly opened, these will not be called. |
| EXPECT_CALL(local_observer_, OnLocalLogStarted(_, _)).Times(0); |
| EXPECT_CALL(local_observer_, OnLocalLogStopped(_)).Times(0); |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| |
| // See the documentation of the function for why |true| is expected despite |
| // the path being illegal. |
| const base::FilePath illegal_path(FILE_PATH_LITERAL(":!@#$%|`^&*\\/")); |
| EXPECT_TRUE(EnableLocalLogging(illegal_path)); |
| |
| EXPECT_TRUE(base::IsDirectoryEmpty(local_logs_base_dir_.GetPath())); |
| } |
| |
| #if defined(OS_POSIX) |
| TEST_F(WebRtcEventLogManagerTest, LocalLogLegalPathWithoutPermissionsSanity) { |
| RemoveWritePermissions(local_logs_base_dir_.GetPath()); |
| |
| // Since the log file won't be properly opened, these will not be called. |
| EXPECT_CALL(local_observer_, OnLocalLogStarted(_, _)).Times(0); |
| EXPECT_CALL(local_observer_, OnLocalLogStopped(_)).Times(0); |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| |
| // See the documentation of the function for why |true| is expected despite |
| // the path being illegal. |
| EXPECT_TRUE(EnableLocalLogging(local_logs_base_path_)); |
| |
| EXPECT_TRUE(base::IsDirectoryEmpty(local_logs_base_dir_.GetPath())); |
| |
| // Write() has no effect (but is handled gracefully). |
| EXPECT_EQ(OnWebRtcEventLogWrite(key, "Why did the chicken cross the road?"), |
| std::make_pair(false, false)); |
| EXPECT_TRUE(base::IsDirectoryEmpty(local_logs_base_dir_.GetPath())); |
| |
| // Logging was enabled, even if it had no effect because of the lacking |
| // permissions; therefore, the operation of disabling it makes sense. |
| EXPECT_TRUE(DisableLocalLogging()); |
| EXPECT_TRUE(base::IsDirectoryEmpty(local_logs_base_dir_.GetPath())); |
| } |
| #endif // defined(OS_POSIX) |
| |
| TEST_F(WebRtcEventLogManagerTest, LocalLogEmptyStringHandledGracefully) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| // By writing a log after the empty string, we show that no odd behavior is |
| // encountered, such as closing the file (an actual bug from WebRTC). |
| const std::vector<std::string> logs = {"<setup>", "", "<encore>"}; |
| |
| base::Optional<base::FilePath> file_path; |
| |
| ON_CALL(local_observer_, OnLocalLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_path))); |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(file_path); |
| ASSERT_FALSE(file_path->empty()); |
| |
| for (size_t i = 0; i < logs.size(); ++i) { |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, logs[i]), std::make_pair(true, false)); |
| } |
| ASSERT_TRUE(DisableLocalLogging()); |
| |
| ExpectLocalFileContents( |
| *file_path, |
| std::accumulate(std::begin(logs), std::end(logs), std::string())); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, LocalLogFilenameMatchesExpectedFormat) { |
| using StringType = base::FilePath::StringType; |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| base::Optional<base::FilePath> file_path; |
| ON_CALL(local_observer_, OnLocalLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_path))); |
| |
| const base::Time::Exploded frozen_time_exploded{ |
| 2017, // Four digit year "2007" |
| 9, // 1-based month (values 1 = January, etc.) |
| 3, // 0-based day of week (0 = Sunday, etc.) |
| 6, // 1-based day of month (1-31) |
| 10, // Hour within the current day (0-23) |
| 43, // Minute within the current hour (0-59) |
| 29, // Second within the current minute. |
| 0 // Milliseconds within the current second (0-999) |
| }; |
| ASSERT_TRUE(frozen_time_exploded.HasValidValues()); |
| FreezeClockAt(frozen_time_exploded); |
| |
| const StringType user_defined = FILE_PATH_LITERAL("user_defined"); |
| const base::FilePath local_logs_base_path = |
| local_logs_base_dir_.GetPath().Append(user_defined); |
| |
| ASSERT_TRUE(EnableLocalLogging(local_logs_base_path)); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(file_path); |
| ASSERT_FALSE(file_path->empty()); |
| |
| // [user_defined]_[date]_[time]_[render_process_id]_[lid].[extension] |
| const StringType date = FILE_PATH_LITERAL("20170906"); |
| const StringType time = FILE_PATH_LITERAL("1043"); |
| base::FilePath expected_path = local_logs_base_path; |
| expected_path = local_logs_base_path.InsertBeforeExtension( |
| FILE_PATH_LITERAL("_") + date + FILE_PATH_LITERAL("_") + time + |
| FILE_PATH_LITERAL("_") + IntToStringType(rph_->GetID()) + |
| FILE_PATH_LITERAL("_") + IntToStringType(kLid)); |
| expected_path = expected_path.AddExtension(local_log_extension_); |
| |
| EXPECT_EQ(file_path, expected_path); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| LocalLogFilenameMatchesExpectedFormatRepeatedFilename) { |
| using StringType = base::FilePath::StringType; |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| base::Optional<base::FilePath> file_path_1; |
| base::Optional<base::FilePath> file_path_2; |
| EXPECT_CALL(local_observer_, OnLocalLogStarted(key, _)) |
| .WillOnce(Invoke(SaveFilePathTo(&file_path_1))) |
| .WillOnce(Invoke(SaveFilePathTo(&file_path_2))); |
| |
| const base::Time::Exploded frozen_time_exploded{ |
| 2017, // Four digit year "2007" |
| 9, // 1-based month (values 1 = January, etc.) |
| 3, // 0-based day of week (0 = Sunday, etc.) |
| 6, // 1-based day of month (1-31) |
| 10, // Hour within the current day (0-23) |
| 43, // Minute within the current hour (0-59) |
| 29, // Second within the current minute. |
| 0 // Milliseconds within the current second (0-999) |
| }; |
| ASSERT_TRUE(frozen_time_exploded.HasValidValues()); |
| FreezeClockAt(frozen_time_exploded); |
| |
| const StringType user_defined_portion = FILE_PATH_LITERAL("user_defined"); |
| const base::FilePath local_logs_base_path = |
| local_logs_base_dir_.GetPath().Append(user_defined_portion); |
| |
| ASSERT_TRUE(EnableLocalLogging(local_logs_base_path)); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(file_path_1); |
| ASSERT_FALSE(file_path_1->empty()); |
| |
| // [user_defined]_[date]_[time]_[render_process_id]_[lid].[extension] |
| const StringType date = FILE_PATH_LITERAL("20170906"); |
| const StringType time = FILE_PATH_LITERAL("1043"); |
| base::FilePath expected_path_1 = local_logs_base_path; |
| expected_path_1 = local_logs_base_path.InsertBeforeExtension( |
| FILE_PATH_LITERAL("_") + date + FILE_PATH_LITERAL("_") + time + |
| FILE_PATH_LITERAL("_") + IntToStringType(rph_->GetID()) + |
| FILE_PATH_LITERAL("_") + IntToStringType(kLid)); |
| expected_path_1 = expected_path_1.AddExtension(local_log_extension_); |
| |
| ASSERT_EQ(file_path_1, expected_path_1); |
| |
| ASSERT_TRUE(DisableLocalLogging()); |
| ASSERT_TRUE(EnableLocalLogging(local_logs_base_path)); |
| ASSERT_TRUE(file_path_2); |
| ASSERT_FALSE(file_path_2->empty()); |
| |
| const base::FilePath expected_path_2 = |
| expected_path_1.InsertBeforeExtension(FILE_PATH_LITERAL(" (1)")); |
| |
| // Focus of the test - starting the same log again produces a new file, |
| // with an expected new filename. |
| ASSERT_EQ(file_path_2, expected_path_2); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnRemoteLogStartedNotCalledIfRemoteLoggingNotEnabled) { |
| EXPECT_CALL(remote_observer_, OnRemoteLogStarted(_, _)).Times(0); |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnRemoteLogStoppedNotCalledIfRemoteLoggingNotEnabled) { |
| EXPECT_CALL(remote_observer_, OnRemoteLogStopped(_)).Times(0); |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnRemoteLogStartedCalledIfRemoteLoggingEnabled) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| EXPECT_CALL(remote_observer_, OnRemoteLogStarted(key, _)).Times(1); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnRemoteLogStoppedCalledIfRemoteLoggingEnabledThenPcRemoved) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| EXPECT_CALL(remote_observer_, OnRemoteLogStopped(key)).Times(1); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| BrowserContextInitializationCreatesDirectoryForRemoteLogs) { |
| auto browser_context = CreateBrowserContext(); |
| const base::FilePath remote_logs_path = |
| RemoteBoundLogsDir(browser_context.get()); |
| EXPECT_TRUE(base::DirectoryExists(remote_logs_path)); |
| EXPECT_TRUE(base::IsDirectoryEmpty(remote_logs_path)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartRemoteLoggingReturnsFalseIfUnknownPeerConnection) { |
| const auto key = GetPeerConnectionKey(rph_.get(), 0); |
| std::string error_message; |
| EXPECT_FALSE( |
| StartRemoteLogging(key.render_process_id, "id", nullptr, &error_message)); |
| EXPECT_EQ(error_message, |
| kStartRemoteLoggingFailureUnknownOrInactivePeerConnection); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartRemoteLoggingReturnsFalseIfUnknownPeerConnectionId) { |
| const auto key = GetPeerConnectionKey(rph_.get(), 0); |
| ASSERT_TRUE(PeerConnectionAdded(key, "real_id")); |
| std::string error_message; |
| EXPECT_FALSE(StartRemoteLogging(key.render_process_id, "wrong_id", nullptr, |
| &error_message)); |
| EXPECT_EQ(error_message, |
| kStartRemoteLoggingFailureUnknownOrInactivePeerConnection); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartRemoteLoggingReturnsTrueIfKnownPeerConnection) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| const std::string id = "id"; // For explicitness' sake. |
| ASSERT_TRUE(PeerConnectionAdded(key, id)); |
| EXPECT_TRUE(StartRemoteLogging(key.render_process_id, id)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartRemoteLoggingReturnsFalseIfRestartAttempt) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| const std::string id = "id"; // For explicitness' sake. |
| ASSERT_TRUE(PeerConnectionAdded(key, id)); |
| ASSERT_TRUE(StartRemoteLogging(key.render_process_id, id)); |
| std::string error_message; |
| EXPECT_FALSE( |
| StartRemoteLogging(key.render_process_id, id, nullptr, &error_message)); |
| EXPECT_EQ(error_message, kStartRemoteLoggingFailureAlreadyLogging); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartRemoteLoggingReturnsFalseIfUnlimitedFileSize) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| const std::string id = "id"; // For explicitness' sake. |
| ASSERT_TRUE(PeerConnectionAdded(key, id)); |
| std::string error_message; |
| EXPECT_FALSE(StartRemoteLogging(key.render_process_id, id, |
| kWebRtcEventLogManagerUnlimitedFileSize, |
| nullptr, &error_message)); |
| EXPECT_EQ(error_message, kStartRemoteLoggingFailureUnlimitedSizeDisallowed); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartRemoteLoggingReturnsTrueIfFileSizeAtOrBelowLimit) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| const std::string id = "id"; // For explicitness' sake. |
| ASSERT_TRUE(PeerConnectionAdded(key, id)); |
| EXPECT_TRUE(StartRemoteLogging(key.render_process_id, id, |
| kMaxRemoteLogFileSizeBytes)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartRemoteLoggingReturnsFalseIfFileSizeToSmall) { |
| const size_t min_size = |
| CreateLogFileWriterFactory(Compression::GZIP_NULL_ESTIMATION) |
| ->MinFileSizeBytes(); |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| const std::string id = "id"; // For explicitness' sake. |
| ASSERT_TRUE(PeerConnectionAdded(key, id)); |
| std::string error_message; |
| EXPECT_FALSE(StartRemoteLogging(key.render_process_id, id, min_size - 1, |
| nullptr, &error_message)); |
| EXPECT_EQ(error_message, kStartRemoteLoggingFailureMaxSizeTooSmall); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartRemoteLoggingReturnsFalseIfExcessivelyLargeFileSize) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| const std::string id = "id"; // For explicitness' sake. |
| ASSERT_TRUE(PeerConnectionAdded(key, id)); |
| std::string error_message; |
| EXPECT_FALSE(StartRemoteLogging(key.render_process_id, id, |
| kMaxRemoteLogFileSizeBytes + 1, nullptr, |
| &error_message)); |
| EXPECT_EQ(error_message, kStartRemoteLoggingFailureMaxSizeTooLarge); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartRemoteLoggingReturnsFalseIfPeerConnectionAlreadyClosed) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| const std::string id = "id"; // For explicitness' sake. |
| ASSERT_TRUE(PeerConnectionAdded(key, id)); |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| std::string error_message; |
| EXPECT_FALSE( |
| StartRemoteLogging(key.render_process_id, id, nullptr, &error_message)); |
| EXPECT_EQ(error_message, |
| kStartRemoteLoggingFailureUnknownOrInactivePeerConnection); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartRemoteLoggingDoesNotReturnIdWhenUnsuccessful) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| const std::string pc_id = "pc_id"; // For explicitness' sake. |
| ASSERT_TRUE(PeerConnectionAdded(key, pc_id)); |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| std::string log_id; |
| ASSERT_FALSE(StartRemoteLogging(key.render_process_id, pc_id, &log_id)); |
| |
| EXPECT_TRUE(log_id.empty()); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartRemoteLoggingReturnsLegalIdWhenSuccessful) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| const std::string pc_id = "pc_id"; // For explicitness' sake. |
| ASSERT_TRUE(PeerConnectionAdded(key, pc_id)); |
| |
| std::string log_id; |
| ASSERT_TRUE(StartRemoteLogging(key.render_process_id, pc_id, &log_id)); |
| |
| EXPECT_EQ(log_id.size(), 32u); |
| EXPECT_EQ(log_id.find_first_not_of("0123456789ABCDEF"), std::string::npos); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartRemoteLoggingSavesToFileWithCorrectFileNameFormat) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| base::Optional<base::FilePath> file_path; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_path))); |
| |
| const std::string pc_id = "pc_id"; // For explicitness' sake. |
| ASSERT_TRUE(PeerConnectionAdded(key, pc_id)); |
| |
| std::string log_id; |
| ASSERT_TRUE(StartRemoteLogging(key.render_process_id, pc_id, &log_id)); |
| |
| const base::FilePath expected_filename = |
| base::FilePath(kRemoteBoundWebRtcEventLogFileNamePrefix) |
| .InsertBeforeExtensionASCII(log_id) |
| .AddExtension(remote_log_extension_); |
| EXPECT_EQ(file_path->BaseName(), expected_filename); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, StartRemoteLoggingCreatesEmptyFile) { |
| base::Optional<base::FilePath> file_path; |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| EXPECT_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .Times(1) |
| .WillOnce(Invoke(SaveFilePathTo(&file_path))); |
| |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| |
| // Close file before examining its contents. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| ExpectRemoteFileContents(*file_path, ""); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, RemoteLogFileCreatedInCorrectDirectory) { |
| // Set up separate browser contexts; each one will get one log. |
| constexpr size_t kLogsNum = 3; |
| std::unique_ptr<TestingProfile> browser_contexts[kLogsNum]; |
| std::vector<std::unique_ptr<MockRenderProcessHost>> rphs; |
| for (size_t i = 0; i < kLogsNum; ++i) { |
| browser_contexts[i] = CreateBrowserContext(); |
| rphs.emplace_back( |
| std::make_unique<MockRenderProcessHost>(browser_contexts[i].get())); |
| } |
| |
| // Prepare to store the logs' paths in distinct memory locations. |
| base::Optional<base::FilePath> file_paths[kLogsNum]; |
| for (size_t i = 0; i < kLogsNum; ++i) { |
| const auto key = GetPeerConnectionKey(rphs[i].get(), kLid); |
| EXPECT_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .Times(1) |
| .WillOnce(Invoke(SaveFilePathTo(&file_paths[i]))); |
| } |
| |
| // Start one log for each browser context. |
| for (const auto& rph : rphs) { |
| const auto key = GetPeerConnectionKey(&*rph, kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| } |
| |
| // All log files must be created in their own context's directory. |
| for (size_t i = 0; i < base::size(browser_contexts); ++i) { |
| ASSERT_TRUE(file_paths[i]); |
| EXPECT_TRUE(browser_contexts[i]->GetPath().IsParent(*file_paths[i])); |
| } |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartRemoteLoggingSanityIfDuplicateIdsInDifferentRendererProcesses) { |
| std::unique_ptr<MockRenderProcessHost> rphs[2] = { |
| std::make_unique<MockRenderProcessHost>(browser_context_.get()), |
| std::make_unique<MockRenderProcessHost>(browser_context_.get()), |
| }; |
| |
| PeerConnectionKey keys[2] = {GetPeerConnectionKey(rphs[0].get(), 0), |
| GetPeerConnectionKey(rphs[1].get(), 0)}; |
| |
| // The ID is shared, but that's not a problem, because the renderer process |
| // are different. |
| const std::string id = "shared_id"; |
| ASSERT_TRUE(PeerConnectionAdded(keys[0], id)); |
| ASSERT_TRUE(PeerConnectionAdded(keys[1], id)); |
| |
| // Make sure the logs get written to separate files. |
| base::Optional<base::FilePath> file_paths[2]; |
| for (size_t i = 0; i < 2; ++i) { |
| EXPECT_CALL(remote_observer_, OnRemoteLogStarted(keys[i], _)) |
| .Times(1) |
| .WillOnce(Invoke(SaveFilePathTo(&file_paths[i]))); |
| } |
| |
| EXPECT_TRUE(StartRemoteLogging(keys[0].render_process_id, id)); |
| EXPECT_TRUE(StartRemoteLogging(keys[1].render_process_id, id)); |
| |
| EXPECT_TRUE(file_paths[0]); |
| EXPECT_TRUE(file_paths[1]); |
| EXPECT_NE(file_paths[0], file_paths[1]); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnWebRtcEventLogWriteWritesToTheRemoteBoundFile) { |
| base::Optional<base::FilePath> file_path; |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| EXPECT_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .Times(1) |
| .WillOnce(Invoke(SaveFilePathTo(&file_path))); |
| |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| |
| const char* const log = "1 + 1 = 3"; |
| EXPECT_EQ(OnWebRtcEventLogWrite(key, log), std::make_pair(false, true)); |
| |
| // Close file before examining its contents. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| ExpectRemoteFileContents(*file_path, log); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, WriteToBothLocalAndRemoteFiles) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| |
| base::Optional<base::FilePath> local_path; |
| EXPECT_CALL(local_observer_, OnLocalLogStarted(key, _)) |
| .Times(1) |
| .WillOnce(Invoke(SaveFilePathTo(&local_path))); |
| |
| base::Optional<base::FilePath> remote_path; |
| EXPECT_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .Times(1) |
| .WillOnce(Invoke(SaveFilePathTo(&remote_path))); |
| |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| |
| ASSERT_TRUE(local_path); |
| ASSERT_FALSE(local_path->empty()); |
| ASSERT_TRUE(remote_path); |
| ASSERT_FALSE(remote_path->empty()); |
| |
| const char* const log = "logloglog"; |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, log), std::make_pair(true, true)); |
| |
| // Ensure the flushing of the file to disk before attempting to read them. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| ExpectLocalFileContents(*local_path, log); |
| ExpectRemoteFileContents(*remote_path, log); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, MultipleWritesToSameRemoteBoundLogfile) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| base::Optional<base::FilePath> file_path; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_path))); |
| |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ASSERT_TRUE(file_path); |
| ASSERT_FALSE(file_path->empty()); |
| |
| const std::string logs[] = {"ABC", "DEF", "XYZ"}; |
| for (const std::string& log : logs) { |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, log), std::make_pair(false, true)); |
| } |
| |
| // Make sure the file would be closed, so that we could safely read it. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| ExpectRemoteFileContents( |
| *file_path, |
| std::accumulate(std::begin(logs), std::end(logs), std::string())); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| RemoteLogFileSizeLimitNotExceededSingleWrite) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| base::Optional<base::FilePath> file_path; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_path))); |
| |
| const std::string log = "tpyo"; |
| |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key, GzippedSize(log) - 1)); |
| |
| // Failure is reported, because not everything could be written. The file |
| // will also be closed. |
| EXPECT_CALL(remote_observer_, OnRemoteLogStopped(key)).Times(1); |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, log), std::make_pair(false, false)); |
| |
| // Make sure the file would be closed, so that we could safely read it. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| // No partial writes occurred. |
| ExpectRemoteFileContents(*file_path, ""); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| RemoteLogFileSizeLimitNotExceededMultipleWrites) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| base::Optional<base::FilePath> file_path; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_path))); |
| |
| const std::string log1 = "abcabc"; |
| const std::string log2 = "defghijklmnopqrstuvwxyz"; |
| |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key, 1 + GzippedSize(log1))); |
| |
| // First write works. |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, log1), std::make_pair(false, true)); |
| |
| // On the second write, failure is reported, because not everything could be |
| // written. The file will also be closed. |
| EXPECT_CALL(remote_observer_, OnRemoteLogStopped(key)).Times(1); |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, log2), std::make_pair(false, false)); |
| |
| ExpectRemoteFileContents(*file_path, log1); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| LogMultipleActiveRemoteLogsSameBrowserContext) { |
| const std::vector<PeerConnectionKey> keys = { |
| GetPeerConnectionKey(rph_.get(), 0), GetPeerConnectionKey(rph_.get(), 1), |
| GetPeerConnectionKey(rph_.get(), 2)}; |
| |
| std::vector<base::Optional<base::FilePath>> file_paths(keys.size()); |
| for (size_t i = 0; i < keys.size(); ++i) { |
| ON_CALL(remote_observer_, OnRemoteLogStarted(keys[i], _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_paths[i]))); |
| ASSERT_TRUE(PeerConnectionAdded(keys[i])); |
| ASSERT_TRUE(StartRemoteLogging(keys[i])); |
| ASSERT_TRUE(file_paths[i]); |
| ASSERT_FALSE(file_paths[i]->empty()); |
| } |
| |
| std::vector<std::string> logs; |
| for (size_t i = 0; i < keys.size(); ++i) { |
| logs.emplace_back(std::to_string(rph_->GetID()) + std::to_string(i)); |
| ASSERT_EQ(OnWebRtcEventLogWrite(keys[i], logs[i]), |
| std::make_pair(false, true)); |
| } |
| |
| // Make sure the file woulds be closed, so that we could safely read them. |
| for (auto& key : keys) { |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| } |
| |
| for (size_t i = 0; i < keys.size(); ++i) { |
| ExpectRemoteFileContents(*file_paths[i], logs[i]); |
| } |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| LogMultipleActiveRemoteLogsDifferentBrowserContexts) { |
| constexpr size_t kLogsNum = 3; |
| std::unique_ptr<TestingProfile> browser_contexts[kLogsNum]; |
| std::vector<std::unique_ptr<MockRenderProcessHost>> rphs; |
| for (size_t i = 0; i < kLogsNum; ++i) { |
| browser_contexts[i] = CreateBrowserContext(); |
| rphs.emplace_back( |
| std::make_unique<MockRenderProcessHost>(browser_contexts[i].get())); |
| } |
| |
| std::vector<PeerConnectionKey> keys; |
| for (auto& rph : rphs) { |
| keys.push_back(GetPeerConnectionKey(rph.get(), kLid)); |
| } |
| |
| std::vector<base::Optional<base::FilePath>> file_paths(keys.size()); |
| for (size_t i = 0; i < keys.size(); ++i) { |
| ON_CALL(remote_observer_, OnRemoteLogStarted(keys[i], _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_paths[i]))); |
| ASSERT_TRUE(PeerConnectionAdded(keys[i])); |
| ASSERT_TRUE(StartRemoteLogging(keys[i])); |
| ASSERT_TRUE(file_paths[i]); |
| ASSERT_FALSE(file_paths[i]->empty()); |
| } |
| |
| std::vector<std::string> logs; |
| for (size_t i = 0; i < keys.size(); ++i) { |
| logs.emplace_back(std::to_string(rph_->GetID()) + std::to_string(i)); |
| ASSERT_EQ(OnWebRtcEventLogWrite(keys[i], logs[i]), |
| std::make_pair(false, true)); |
| } |
| |
| // Make sure the file woulds be closed, so that we could safely read them. |
| for (auto& key : keys) { |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| } |
| |
| for (size_t i = 0; i < keys.size(); ++i) { |
| ExpectRemoteFileContents(*file_paths[i], logs[i]); |
| } |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, DifferentRemoteLogsMayHaveDifferentMaximums) { |
| const std::string logs[2] = {"abra", "cadabra"}; |
| std::vector<base::Optional<base::FilePath>> file_paths(base::size(logs)); |
| std::vector<PeerConnectionKey> keys; |
| for (size_t i = 0; i < base::size(logs); ++i) { |
| keys.push_back(GetPeerConnectionKey(rph_.get(), i)); |
| ON_CALL(remote_observer_, OnRemoteLogStarted(keys[i], _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_paths[i]))); |
| } |
| |
| for (size_t i = 0; i < keys.size(); ++i) { |
| ASSERT_TRUE(PeerConnectionAdded(keys[i])); |
| ASSERT_TRUE(StartRemoteLogging(keys[i], GzippedSize(logs[i]))); |
| } |
| |
| for (size_t i = 0; i < keys.size(); ++i) { |
| // The write is successful, but the file closed, indicating that the |
| // maximum file size has been reached. |
| EXPECT_CALL(remote_observer_, OnRemoteLogStopped(keys[i])).Times(1); |
| ASSERT_EQ(OnWebRtcEventLogWrite(keys[i], logs[i]), |
| std::make_pair(false, true)); |
| ASSERT_TRUE(file_paths[i]); |
| ExpectRemoteFileContents(*file_paths[i], logs[i]); |
| } |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, RemoteLogFileClosedWhenCapacityReached) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| base::Optional<base::FilePath> file_path; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_path))); |
| |
| const std::string log = "Let X equal X."; |
| |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key, GzippedSize(log))); |
| ASSERT_TRUE(file_path); |
| |
| EXPECT_CALL(remote_observer_, OnRemoteLogStopped(key)).Times(1); |
| EXPECT_EQ(OnWebRtcEventLogWrite(key, log), std::make_pair(false, true)); |
| } |
| |
| #if defined(OS_POSIX) |
| // TODO(crbug.com/775415): Add unit tests for lacking read permissions when |
| // looking to upload the file. |
| TEST_F(WebRtcEventLogManagerTest, |
| FailureToCreateRemoteLogsDirHandledGracefully) { |
| const base::FilePath browser_context_dir = browser_context_->GetPath(); |
| const base::FilePath remote_logs_path = |
| RemoteBoundLogsDir(browser_context_.get()); |
| |
| // Unload the profile, delete its remove logs directory, and remove write |
| // permissions from it, thereby preventing it from being created again. |
| UnloadMainTestProfile(); |
| ASSERT_TRUE(base::DeleteFile(remote_logs_path, /*recursive=*/true)); |
| RemoveWritePermissions(browser_context_dir); |
| |
| // Graceful handling by BrowserContext::EnableForBrowserContext, despite |
| // failing to create the remote logs' directory.. |
| LoadMainTestProfile(); |
| EXPECT_FALSE(base::DirectoryExists(remote_logs_path)); |
| |
| // Graceful handling of PeerConnectionAdded: True returned because the |
| // remote-logs' manager can still safely reason about the state of peer |
| // connections even if one of its browser contexts is defective.) |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| EXPECT_TRUE(PeerConnectionAdded(key)); |
| |
| // Graceful handling of StartRemoteLogging: False returned because it's |
| // impossible to write the log to a file. |
| std::string error_message; |
| EXPECT_FALSE(StartRemoteLogging(key, nullptr, &error_message)); |
| EXPECT_EQ(error_message, kStartRemoteLoggingFailureGeneric); |
| |
| // Graceful handling of OnWebRtcEventLogWrite: False returned because the |
| // log could not be written at all, let alone in its entirety. |
| const char* const log = "This is not a log."; |
| EXPECT_EQ(OnWebRtcEventLogWrite(key, log), std::make_pair(false, false)); |
| |
| // Graceful handling of PeerConnectionRemoved: True returned because the |
| // remote-logs' manager can still safely reason about the state of peer |
| // connections even if one of its browser contexts is defective. |
| EXPECT_TRUE(PeerConnectionRemoved(key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, GracefullyHandleFailureToStartRemoteLogFile) { |
| // WebRTC logging will not be turned on. |
| EXPECT_CALL(remote_observer_, OnRemoteLogStarted(_, _)).Times(0); |
| EXPECT_CALL(remote_observer_, OnRemoteLogStopped(_)).Times(0); |
| |
| // Remove write permissions from the directory. |
| const base::FilePath remote_logs_path = |
| RemoteBoundLogsDir(browser_context_.get()); |
| ASSERT_TRUE(base::DirectoryExists(remote_logs_path)); |
| RemoveWritePermissions(remote_logs_path); |
| |
| // StartRemoteLogging() will now fail. |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| std::string error_message; |
| EXPECT_FALSE(StartRemoteLogging(key, nullptr, &error_message)); |
| EXPECT_EQ(error_message, kStartRemoteLoggingFailureGeneric); |
| EXPECT_EQ(OnWebRtcEventLogWrite(key, "abc"), std::make_pair(false, false)); |
| EXPECT_TRUE(base::IsDirectoryEmpty(remote_logs_path)); |
| } |
| #endif // defined(OS_POSIX) |
| |
| TEST_F(WebRtcEventLogManagerTest, RemoteLogLimitActiveLogFiles) { |
| for (int i = 0; i < kMaxActiveRemoteLogFiles + 1; ++i) { |
| const auto key = GetPeerConnectionKey(rph_.get(), i); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| } |
| |
| for (int i = 0; i < kMaxActiveRemoteLogFiles; ++i) { |
| const auto key = GetPeerConnectionKey(rph_.get(), i); |
| EXPECT_CALL(remote_observer_, OnRemoteLogStarted(key, _)).Times(1); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| } |
| |
| EXPECT_CALL(remote_observer_, OnRemoteLogStarted(_, _)).Times(0); |
| const auto new_key = |
| GetPeerConnectionKey(rph_.get(), kMaxActiveRemoteLogFiles); |
| EXPECT_FALSE(StartRemoteLogging(new_key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| RemoteLogFilledLogNotCountedTowardsLogsLimit) { |
| const std::string log = "very_short_log"; |
| |
| for (int i = 0; i < kMaxActiveRemoteLogFiles; ++i) { |
| const auto key = GetPeerConnectionKey(rph_.get(), i); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| EXPECT_CALL(remote_observer_, OnRemoteLogStarted(key, _)).Times(1); |
| ASSERT_TRUE(StartRemoteLogging(key, GzippedSize(log))); |
| } |
| |
| // By writing to one of the logs until it reaches capacity, we fill it, |
| // causing it to close, therefore allowing an additional log. |
| const auto removed_key = GetPeerConnectionKey(rph_.get(), 0); |
| EXPECT_EQ(OnWebRtcEventLogWrite(removed_key, log), |
| std::make_pair(false, true)); |
| |
| // We now have room for one additional log. |
| const auto new_key = |
| GetPeerConnectionKey(rph_.get(), kMaxActiveRemoteLogFiles); |
| EXPECT_CALL(remote_observer_, OnRemoteLogStarted(new_key, _)).Times(1); |
| ASSERT_TRUE(PeerConnectionAdded(new_key)); |
| ASSERT_TRUE(StartRemoteLogging(new_key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| RemoteLogForRemovedPeerConnectionNotCountedTowardsLogsLimit) { |
| for (int i = 0; i < kMaxActiveRemoteLogFiles; ++i) { |
| const auto key = GetPeerConnectionKey(rph_.get(), i); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| EXPECT_CALL(remote_observer_, OnRemoteLogStarted(key, _)).Times(1); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| } |
| |
| // By removing a peer connection associated with one of the logs, we allow |
| // an additional log. |
| const auto removed_key = GetPeerConnectionKey(rph_.get(), 0); |
| ASSERT_TRUE(PeerConnectionRemoved(removed_key)); |
| |
| // We now have room for one additional log. |
| const auto last_key = |
| GetPeerConnectionKey(rph_.get(), kMaxActiveRemoteLogFiles); |
| EXPECT_CALL(remote_observer_, OnRemoteLogStarted(last_key, _)).Times(1); |
| ASSERT_TRUE(PeerConnectionAdded(last_key)); |
| ASSERT_TRUE(StartRemoteLogging(last_key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| ActiveLogsForBrowserContextCountedTowardsItsPendingsLogsLimit) { |
| SuppressUploading(); |
| |
| // Produce kMaxPendingRemoteLogFiles pending logs. |
| for (int i = 0; i < kMaxPendingRemoteLogFiles; ++i) { |
| const auto key = GetPeerConnectionKey(rph_.get(), i); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| } |
| |
| // It is now impossible to start another *active* log for that BrowserContext, |
| // because we have too many pending logs (and active logs become pending |
| // once completed). |
| const auto forbidden = |
| GetPeerConnectionKey(rph_.get(), kMaxPendingRemoteLogFiles); |
| ASSERT_TRUE(PeerConnectionAdded(forbidden)); |
| std::string error_message; |
| EXPECT_FALSE(StartRemoteLogging(forbidden, nullptr, &error_message)); |
| EXPECT_EQ(error_message, kStartRemoteLoggingFailureGeneric); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| ObserveLimitOnMaximumPendingLogsPerBrowserContext) { |
| SuppressUploading(); |
| |
| // Create additional BrowserContexts for the test. |
| std::unique_ptr<TestingProfile> browser_contexts[2] = { |
| CreateBrowserContext(), CreateBrowserContext()}; |
| std::unique_ptr<MockRenderProcessHost> rphs[2] = { |
| std::make_unique<MockRenderProcessHost>(browser_contexts[0].get()), |
| std::make_unique<MockRenderProcessHost>(browser_contexts[1].get())}; |
| |
| // Allowed to start kMaxPendingRemoteLogFiles for each BrowserContext. |
| // Specifically, we can do it for the first BrowserContext. |
| for (int i = 0; i < kMaxPendingRemoteLogFiles; ++i) { |
| const auto key = GetPeerConnectionKey(rphs[0].get(), i); |
| // The log could be opened: |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| // The log changes state from ACTIVE to PENDING: |
| EXPECT_TRUE(PeerConnectionRemoved(key)); |
| } |
| |
| // Not allowed to start any more remote-bound logs for the BrowserContext on |
| // which the limit was reached. |
| const auto key0 = |
| GetPeerConnectionKey(rphs[0].get(), kMaxPendingRemoteLogFiles); |
| ASSERT_TRUE(PeerConnectionAdded(key0)); |
| std::string error_message; |
| EXPECT_FALSE(StartRemoteLogging(key0, nullptr, &error_message)); |
| EXPECT_EQ(error_message, kStartRemoteLoggingFailureGeneric); |
| |
| // Other BrowserContexts aren't limit by the previous one's limit. |
| const auto key1 = GetPeerConnectionKey(rphs[1].get(), 0); |
| ASSERT_TRUE(PeerConnectionAdded(key1)); |
| EXPECT_TRUE(StartRemoteLogging(key1)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| LogsFromPreviousSessionBecomePendingLogsWhenBrowserContextInitialized) { |
| // Unload the profile, but remember where it stores its files. |
| const base::FilePath browser_context_path = browser_context_->GetPath(); |
| const base::FilePath remote_logs_dir = |
| RemoteBoundLogsDir(browser_context_.get()); |
| UnloadMainTestProfile(); |
| |
| // Seed the remote logs' directory with log files, simulating the |
| // creation of logs in a previous session. |
| std::list<WebRtcLogFileInfo> expected_files; |
| ASSERT_TRUE(CreateDirectory(remote_logs_dir)); |
| |
| for (size_t i = 0; i < kMaxPendingRemoteBoundWebRtcEventLogs; ++i) { |
| const base::FilePath file_path = remote_logs_dir.Append(IntToStringType(i)) |
| .AddExtension(remote_log_extension_); |
| constexpr int file_flags = base::File::FLAG_CREATE | |
| base::File::FLAG_WRITE | |
| base::File::FLAG_EXCLUSIVE_WRITE; |
| base::File file(file_path, file_flags); |
| ASSERT_TRUE(file.IsValid() && file.created()); |
| expected_files.emplace_back(browser_context_id_, file_path, |
| GetLastModificationTime(file_path)); |
| } |
| |
| // This factory enforces the expectation that the files will be uploaded, |
| // all of them, only them, and in the order expected. |
| base::RunLoop run_loop; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &expected_files, true, &run_loop)); |
| |
| LoadMainTestProfile(); |
| ASSERT_EQ(browser_context_->GetPath(), browser_context_path); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| // It is possible for remote-bound logs to be compressed or uncompressed. |
| // We show that logs from a previous session are captured even if they are |
| // different, with regards to compression, compared to last time. |
| TEST_F(WebRtcEventLogManagerTest, |
| LogsCapturedPreviouslyMadePendingEvenIfDifferentExtensionUsed) { |
| // Unload the profile, but remember where it stores its files. |
| const base::FilePath browser_context_path = browser_context_->GetPath(); |
| const base::FilePath remote_logs_dir = |
| RemoteBoundLogsDir(browser_context_.get()); |
| UnloadMainTestProfile(); |
| |
| // Seed the remote logs' directory with log files, simulating the |
| // creation of logs in a previous session. |
| std::list<WebRtcLogFileInfo> expected_files; |
| ASSERT_TRUE(CreateDirectory(remote_logs_dir)); |
| |
| base::FilePath::StringPieceType extensions[] = { |
| kWebRtcEventLogUncompressedExtension, kWebRtcEventLogGzippedExtension}; |
| ASSERT_LE(base::size(extensions), kMaxPendingRemoteBoundWebRtcEventLogs) |
| << "Lacking test coverage."; |
| |
| for (size_t i = 0, ext = 0; i < kMaxPendingRemoteBoundWebRtcEventLogs; ++i) { |
| const auto& extension = extensions[ext]; |
| ext = (ext + 1) % base::size(extensions); |
| const base::FilePath file_path = |
| remote_logs_dir.Append(IntToStringType(i)).AddExtension(extension); |
| constexpr int file_flags = base::File::FLAG_CREATE | |
| base::File::FLAG_WRITE | |
| base::File::FLAG_EXCLUSIVE_WRITE; |
| base::File file(file_path, file_flags); |
| ASSERT_TRUE(file.IsValid() && file.created()); |
| expected_files.emplace_back(browser_context_id_, file_path, |
| GetLastModificationTime(file_path)); |
| } |
| |
| // This factory enforces the expectation that the files will be uploaded, |
| // all of them, only them, and in the order expected. |
| base::RunLoop run_loop; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &expected_files, true, &run_loop)); |
| |
| LoadMainTestProfile(); |
| ASSERT_EQ(browser_context_->GetPath(), browser_context_path); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| TEST_P(WebRtcEventLogManagerTest, |
| WhenPeerConnectionRemovedFinishedRemoteLogUploadedAndFileDeleted) { |
| // |upload_result| show that the files are deleted independent of the |
| // upload's success / failure. |
| const bool upload_result = GetParam(); |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), 1); |
| base::Optional<base::FilePath> log_file; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&log_file))); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ASSERT_TRUE(log_file); |
| |
| base::RunLoop run_loop; |
| std::list<WebRtcLogFileInfo> expected_files = {WebRtcLogFileInfo( |
| browser_context_id_, *log_file, GetLastModificationTime(*log_file))}; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &expected_files, upload_result, &run_loop)); |
| |
| // Peer connection removal triggers next upload. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| WaitForPendingTasks(&run_loop); |
| |
| EXPECT_TRUE( |
| base::IsDirectoryEmpty(RemoteBoundLogsDir(browser_context_.get()))); |
| } |
| |
| TEST_P(WebRtcEventLogManagerTest, DestroyedRphTriggersLogUpload) { |
| // |upload_result| show that the files are deleted independent of the |
| // upload's success / failure. |
| const bool upload_result = GetParam(); |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), 1); |
| base::Optional<base::FilePath> log_file; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&log_file))); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ASSERT_TRUE(log_file); |
| |
| base::RunLoop run_loop; |
| std::list<WebRtcLogFileInfo> expected_files = {WebRtcLogFileInfo( |
| browser_context_id_, *log_file, GetLastModificationTime(*log_file))}; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &expected_files, upload_result, &run_loop)); |
| |
| // RPH destruction stops all active logs and triggers next upload. |
| rph_.reset(); |
| |
| WaitForPendingTasks(&run_loop); |
| |
| EXPECT_TRUE( |
| base::IsDirectoryEmpty(RemoteBoundLogsDir(browser_context_.get()))); |
| } |
| |
| // Note that SuppressUploading() and UnSuppressUploading() use the behavior |
| // guaranteed by this test. |
| TEST_F(WebRtcEventLogManagerTest, UploadOnlyWhenNoActivePeerConnections) { |
| const auto untracked = GetPeerConnectionKey(rph_.get(), 0); |
| const auto tracked = GetPeerConnectionKey(rph_.get(), 1); |
| |
| // Suppresses the uploading of the "tracked" peer connection's log. |
| ASSERT_TRUE(PeerConnectionAdded(untracked)); |
| |
| // The tracked peer connection's log is not uploaded when finished, because |
| // another peer connection is still active. |
| base::Optional<base::FilePath> log_file; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(tracked, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&log_file))); |
| ASSERT_TRUE(PeerConnectionAdded(tracked)); |
| ASSERT_TRUE(StartRemoteLogging(tracked)); |
| ASSERT_TRUE(log_file); |
| ASSERT_TRUE(PeerConnectionRemoved(tracked)); |
| |
| // Perform another action synchronously, so that we may be assured that the |
| // observer's lack of callbacks was not a timing fluke. |
| OnWebRtcEventLogWrite(untracked, "Ook!"); |
| |
| // Having been convinced that |tracked|'s log was not uploded while |
| // |untracked| was active, close |untracked| and see that |tracked|'s log |
| // is now uploaded. |
| base::RunLoop run_loop; |
| std::list<WebRtcLogFileInfo> expected_uploads = {WebRtcLogFileInfo( |
| browser_context_id_, *log_file, GetLastModificationTime(*log_file))}; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &expected_uploads, true, &run_loop)); |
| ASSERT_TRUE(PeerConnectionRemoved(untracked)); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, UploadOrderDependsOnLastModificationTime) { |
| constexpr size_t kProfilesNum = 3; |
| const std::string profile_names[kProfilesNum] = {"a", "b", "c"}; |
| |
| // Create profiles. This creates their directories. |
| base::FilePath remote_logs_dirs[kProfilesNum]; |
| std::unique_ptr<BrowserContext> browser_contexts[kProfilesNum]; |
| for (size_t i = 0; i < kProfilesNum; ++i) { |
| browser_contexts[i] = CreateBrowserContext(profile_names[i]); |
| remote_logs_dirs[i] = RemoteBoundLogsDir(browser_contexts[i].get()); |
| } |
| |
| // Unload the profiles, so that whatever files we add into their directory |
| // could be discovered by EnableForBrowserContext when we reload them. |
| for (size_t i = 0; i < kProfilesNum; ++i) { |
| browser_contexts[i].reset(); |
| } |
| |
| // Seed the directories with log files. |
| base::FilePath file_paths[kProfilesNum]; |
| for (size_t i = 0; i < kProfilesNum; ++i) { |
| ASSERT_TRUE(base::DirectoryExists(remote_logs_dirs[i])); |
| file_paths[i] = remote_logs_dirs[i].AppendASCII("file").AddExtension( |
| remote_log_extension_); |
| ASSERT_TRUE(!base::PathExists(file_paths[i])); |
| constexpr int file_flags = base::File::FLAG_CREATE | |
| base::File::FLAG_WRITE | |
| base::File::FLAG_EXCLUSIVE_WRITE; |
| base::File file(file_paths[i], file_flags); |
| ASSERT_TRUE(file.IsValid() && file.created()); |
| } |
| |
| // Touch() requires setting the last access time as well. Keep it the same |
| // for all files, showing that the difference between them lies elsewhere. |
| base::File::Info file_info; |
| ASSERT_TRUE(base::GetFileInfo(file_paths[0], &file_info)); |
| const base::Time shared_last_accessed = file_info.last_accessed; |
| |
| // Set the files' last modification time according to a non-trivial |
| // permutation (not the order of creation or its reverse). |
| const size_t permutation[kProfilesNum] = {2, 0, 1}; |
| std::list<WebRtcLogFileInfo> expected_files; |
| base::Time mod_time = |
| base::Time::Now() - base::TimeDelta::FromSeconds(kProfilesNum); |
| for (size_t i = 0; i < kProfilesNum; ++i) { |
| mod_time += base::TimeDelta::FromSeconds(1); // Back to the future. |
| const base::FilePath& path = file_paths[permutation[i]]; |
| ASSERT_TRUE(base::TouchFile(path, shared_last_accessed, mod_time)); |
| expected_files.emplace_back(GetBrowserContextId(browser_contexts[i].get()), |
| path, GetLastModificationTime(path)); |
| } |
| |
| // Recognize the files as pending files by initializing their BrowserContexts. |
| // We keep uploading suppressed so as to avoid them being uploaded in order of |
| // loading, rather than in order of date. |
| SuppressUploading(); |
| for (size_t i = 0; i < kProfilesNum; ++i) { |
| browser_contexts[i] = CreateBrowserContext(profile_names[i]); |
| } |
| |
| // Show that the files are uploaded by order of modification. |
| base::RunLoop run_loop; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &expected_files, true, &run_loop)); |
| |
| UnsuppressUploading(); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, ExpiredFilesArePrunedRatherThanUploaded) { |
| constexpr size_t kExpired = 0; |
| constexpr size_t kFresh = 1; |
| DCHECK_GE(kMaxPendingRemoteBoundWebRtcEventLogs, 2u) |
| << "Please restructure the test to use separate browser contexts."; |
| |
| const base::FilePath remote_logs_dir = |
| RemoteBoundLogsDir(browser_context_.get()); |
| |
| UnloadMainTestProfile(); |
| |
| base::FilePath file_paths[2]; |
| for (size_t i = 0; i < 2; ++i) { |
| file_paths[i] = remote_logs_dir.Append(IntToStringType(i)) |
| .AddExtension(remote_log_extension_); |
| constexpr int file_flags = base::File::FLAG_CREATE | |
| base::File::FLAG_WRITE | |
| base::File::FLAG_EXCLUSIVE_WRITE; |
| base::File file(file_paths[i], file_flags); |
| ASSERT_TRUE(file.IsValid() && file.created()); |
| } |
| |
| // Touch() requires setting the last access time as well. Keep it current, |
| // showing that only the last modification time matters. |
| base::File::Info file_info; |
| ASSERT_TRUE(base::GetFileInfo(file_paths[0], &file_info)); |
| |
| // Set the expired file's last modification time to past max retention. |
| const base::Time expired_mod_time = base::Time::Now() - |
| kRemoteBoundWebRtcEventLogsMaxRetention - |
| base::TimeDelta::FromSeconds(1); |
| ASSERT_TRUE(base::TouchFile(file_paths[kExpired], file_info.last_accessed, |
| expired_mod_time)); |
| |
| // Show that the expired file is not uploaded. |
| base::RunLoop run_loop; |
| std::list<WebRtcLogFileInfo> expected_files = { |
| WebRtcLogFileInfo(browser_context_id_, file_paths[kFresh], |
| GetLastModificationTime(file_paths[kFresh]))}; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &expected_files, true, &run_loop)); |
| |
| // Recognize the files as pending by initializing their BrowserContext. |
| LoadMainTestProfile(); |
| |
| WaitForPendingTasks(&run_loop); |
| |
| // Both the uploaded file as well as the expired file have no been removed |
| // from local disk. |
| EXPECT_TRUE( |
| base::IsDirectoryEmpty(RemoteBoundLogsDir(browser_context_.get()))); |
| } |
| |
| // TODO(crbug.com/775415): Add a test showing that a file expiring while another |
| // is being uploaded, is not uploaded after the current upload is completed. |
| // This is significant because Chrome might stay up for a long time. |
| |
| TEST_F(WebRtcEventLogManagerTest, RemoteLogEmptyStringHandledGracefully) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| // By writing a log after the empty string, we show that no odd behavior is |
| // encountered, such as closing the file (an actual bug from WebRTC). |
| const std::vector<std::string> logs = {"<setup>", "", "<encore>"}; |
| |
| base::Optional<base::FilePath> file_path; |
| |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_path))); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ASSERT_TRUE(file_path); |
| ASSERT_FALSE(file_path->empty()); |
| |
| for (size_t i = 0; i < logs.size(); ++i) { |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, logs[i]), std::make_pair(false, true)); |
| } |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| ExpectRemoteFileContents( |
| *file_path, |
| std::accumulate(std::begin(logs), std::end(logs), std::string())); |
| } |
| |
| #if defined(OS_POSIX) |
| TEST_F(WebRtcEventLogManagerTest, |
| UnopenedRemoteLogFilesNotCountedTowardsActiveLogsLimit) { |
| std::unique_ptr<TestingProfile> browser_contexts[2]; |
| std::unique_ptr<MockRenderProcessHost> rphs[2]; |
| for (size_t i = 0; i < 2; ++i) { |
| browser_contexts[i] = CreateBrowserContext(); |
| rphs[i] = |
| std::make_unique<MockRenderProcessHost>(browser_contexts[i].get()); |
| } |
| |
| constexpr size_t without_permissions = 0; |
| constexpr size_t with_permissions = 1; |
| |
| // Remove write permissions from one directory. |
| const base::FilePath permissions_lacking_remote_logs_path = |
| RemoteBoundLogsDir(browser_contexts[without_permissions].get()); |
| ASSERT_TRUE(base::DirectoryExists(permissions_lacking_remote_logs_path)); |
| RemoveWritePermissions(permissions_lacking_remote_logs_path); |
| |
| // Fail to start a log associated with the permission-lacking directory. |
| const auto without_permissions_key = |
| GetPeerConnectionKey(rphs[without_permissions].get(), 0); |
| ASSERT_TRUE(PeerConnectionAdded(without_permissions_key)); |
| std::string error; |
| ASSERT_FALSE(StartRemoteLogging(without_permissions_key, nullptr, &error)); |
| EXPECT_EQ(error, kStartRemoteLoggingFailureGeneric); |
| |
| // Show that this was not counted towards the limit of active files. |
| for (int i = 0; i < kMaxActiveRemoteLogFiles; ++i) { |
| const auto with_permissions_key = |
| GetPeerConnectionKey(rphs[with_permissions].get(), i); |
| ASSERT_TRUE(PeerConnectionAdded(with_permissions_key)); |
| EXPECT_TRUE(StartRemoteLogging(with_permissions_key)); |
| } |
| } |
| #endif // defined(OS_POSIX) |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| NoStartWebRtcSendingEventLogsWhenLocalEnabledWithoutPeerConnection) { |
| SetPeerConnectionTrackerProxyForTesting( |
| std::make_unique<PeerConnectionTrackerProxyForTesting>(this)); |
| ASSERT_TRUE(EnableLocalLogging()); |
| EXPECT_TRUE(webrtc_state_change_instructions_.empty()); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| NoStartWebRtcSendingEventLogsWhenPeerConnectionButNoLoggingEnabled) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| SetPeerConnectionTrackerProxyForTesting( |
| std::make_unique<PeerConnectionTrackerProxyForTesting>(this)); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| EXPECT_TRUE(webrtc_state_change_instructions_.empty()); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartWebRtcSendingEventLogsWhenLocalEnabledThenPeerConnectionAdded) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| SetPeerConnectionTrackerProxyForTesting( |
| std::make_unique<PeerConnectionTrackerProxyForTesting>(this)); |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ExpectWebRtcStateChangeInstruction(key, true); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartWebRtcSendingEventLogsWhenPeerConnectionAddedThenLocalEnabled) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| SetPeerConnectionTrackerProxyForTesting( |
| std::make_unique<PeerConnectionTrackerProxyForTesting>(this)); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(EnableLocalLogging()); |
| ExpectWebRtcStateChangeInstruction(key, true); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartWebRtcSendingEventLogsWhenRemoteLoggingEnabled) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| SetPeerConnectionTrackerProxyForTesting( |
| std::make_unique<PeerConnectionTrackerProxyForTesting>(this)); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ExpectWebRtcStateChangeInstruction(key, true); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| InstructWebRtcToStopSendingEventLogsWhenLocalLoggingStopped) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| // Setup |
| SetPeerConnectionTrackerProxyForTesting( |
| std::make_unique<PeerConnectionTrackerProxyForTesting>(this)); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(EnableLocalLogging()); |
| ExpectWebRtcStateChangeInstruction(key, true); |
| |
| // Test |
| ASSERT_TRUE(DisableLocalLogging()); |
| ExpectWebRtcStateChangeInstruction(key, false); |
| } |
| |
| // #1 - Local logging was the cause of the logs. |
| TEST_F(WebRtcEventLogManagerTest, |
| InstructWebRtcToStopSendingEventLogsWhenPeerConnectionRemoved1) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| // Setup |
| SetPeerConnectionTrackerProxyForTesting( |
| std::make_unique<PeerConnectionTrackerProxyForTesting>(this)); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(EnableLocalLogging()); |
| ExpectWebRtcStateChangeInstruction(key, true); |
| |
| // Test |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| ExpectWebRtcStateChangeInstruction(key, false); |
| } |
| |
| // #2 - Remote logging was the cause of the logs. |
| TEST_F(WebRtcEventLogManagerTest, |
| InstructWebRtcToStopSendingEventLogsWhenPeerConnectionRemoved2) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| // Setup |
| SetPeerConnectionTrackerProxyForTesting( |
| std::make_unique<PeerConnectionTrackerProxyForTesting>(this)); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ExpectWebRtcStateChangeInstruction(key, true); |
| |
| // Test |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| ExpectWebRtcStateChangeInstruction(key, false); |
| } |
| |
| // #1 - Local logging added first. |
| TEST_F(WebRtcEventLogManagerTest, |
| SecondLoggingTargetDoesNotInitiateWebRtcLogging1) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| // Setup |
| SetPeerConnectionTrackerProxyForTesting( |
| std::make_unique<PeerConnectionTrackerProxyForTesting>(this)); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(EnableLocalLogging()); |
| ExpectWebRtcStateChangeInstruction(key, true); |
| |
| // Test |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| EXPECT_TRUE(webrtc_state_change_instructions_.empty()); |
| } |
| |
| // #2 - Remote logging added first. |
| TEST_F(WebRtcEventLogManagerTest, |
| SecondLoggingTargetDoesNotInitiateWebRtcLogging2) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| // Setup |
| SetPeerConnectionTrackerProxyForTesting( |
| std::make_unique<PeerConnectionTrackerProxyForTesting>(this)); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ExpectWebRtcStateChangeInstruction(key, true); |
| |
| // Test |
| ASSERT_TRUE(EnableLocalLogging()); |
| EXPECT_TRUE(webrtc_state_change_instructions_.empty()); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| DisablingLocalLoggingWhenRemoteLoggingEnabledDoesNotStopWebRtcLogging) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| // Setup |
| SetPeerConnectionTrackerProxyForTesting( |
| std::make_unique<PeerConnectionTrackerProxyForTesting>(this)); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ExpectWebRtcStateChangeInstruction(key, true); |
| |
| // Test |
| ASSERT_TRUE(DisableLocalLogging()); |
| EXPECT_TRUE(webrtc_state_change_instructions_.empty()); |
| |
| // Cleanup |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| ExpectWebRtcStateChangeInstruction(key, false); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| DisablingLocalLoggingAfterPcRemovalHasNoEffectOnWebRtcLogging) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| // Setup |
| SetPeerConnectionTrackerProxyForTesting( |
| std::make_unique<PeerConnectionTrackerProxyForTesting>(this)); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ExpectWebRtcStateChangeInstruction(key, true); |
| |
| // Test |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| ExpectWebRtcStateChangeInstruction(key, false); |
| ASSERT_TRUE(DisableLocalLogging()); |
| EXPECT_TRUE(webrtc_state_change_instructions_.empty()); |
| } |
| |
| // Once a peer connection with a given key was removed, it may not again be |
| // added. But, if this impossible case occurs, WebRtcEventLogManager will |
| // not crash. |
| TEST_F(WebRtcEventLogManagerTest, SanityOverRecreatingTheSamePeerConnection) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| OnWebRtcEventLogWrite(key, "log1"); |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| OnWebRtcEventLogWrite(key, "log2"); |
| } |
| |
| // The logs would typically be binary. However, the other tests only cover ASCII |
| // characters, for readability. This test shows that this is not a problem. |
| TEST_F(WebRtcEventLogManagerTest, LogAllPossibleCharacters) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| base::Optional<base::FilePath> local_log_file_path; |
| ON_CALL(local_observer_, OnLocalLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&local_log_file_path))); |
| |
| base::Optional<base::FilePath> remote_log_file_path; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&remote_log_file_path))); |
| |
| ASSERT_TRUE(EnableLocalLogging()); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ASSERT_TRUE(local_log_file_path); |
| ASSERT_FALSE(local_log_file_path->empty()); |
| ASSERT_TRUE(remote_log_file_path); |
| ASSERT_FALSE(remote_log_file_path->empty()); |
| |
| std::string all_chars; |
| for (size_t i = 0; i < 256; ++i) { |
| all_chars += static_cast<uint8_t>(i); |
| } |
| ASSERT_EQ(OnWebRtcEventLogWrite(key, all_chars), std::make_pair(true, true)); |
| |
| // Make sure the file would be closed, so that we could safely read it. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| ExpectLocalFileContents(*local_log_file_path, all_chars); |
| ExpectRemoteFileContents(*remote_log_file_path, all_chars); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, LocalLogsClosedWhenRenderProcessHostExits) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(EnableLocalLogging()); |
| |
| // The expectation for OnLocalLogStopped() will be saturated by this |
| // destruction of the RenderProcessHost, which triggers an implicit |
| // removal of all PeerConnections associated with it. |
| EXPECT_CALL(local_observer_, OnLocalLogStopped(key)).Times(1); |
| rph_.reset(); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, RemoteLogsClosedWhenRenderProcessHostExits) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| |
| // The expectation for OnRemoteLogStopped() will be saturated by this |
| // destruction of the RenderProcessHost, which triggers an implicit |
| // removal of all PeerConnections associated with it. |
| EXPECT_CALL(remote_observer_, OnRemoteLogStopped(key)).Times(1); |
| rph_.reset(); |
| } |
| |
| // Once a RenderProcessHost exits/crashes, its PeerConnections are removed, |
| // which means that they can no longer suppress an upload. |
| TEST_F(WebRtcEventLogManagerTest, |
| RenderProcessHostExitCanRemoveUploadSuppression) { |
| SuppressUploading(); |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| base::Optional<base::FilePath> file_path; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&file_path))); |
| |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| ASSERT_TRUE(file_path); |
| ASSERT_FALSE(file_path->empty()); |
| |
| // The above removal is not sufficient to trigger an upload (so the test will |
| // not be flaky). It's only once we destroy the RPH with which the suppressing |
| // PeerConnection is associated, that upload will take place. |
| base::RunLoop run_loop; |
| std::list<WebRtcLogFileInfo> expected_files = {WebRtcLogFileInfo( |
| browser_context_id_, *file_path, GetLastModificationTime(*file_path))}; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &expected_files, true, &run_loop)); |
| |
| // We destroy the RPH without explicitly removing its PeerConnection (unlike |
| // a call to UnsuppressUploading()). |
| upload_suppressing_rph_.reset(); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| PeerConnectionAddedOverDestroyedRphReturnsFalse) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| rph_.reset(); |
| EXPECT_FALSE(PeerConnectionAdded(key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| PeerConnectionRemovedOverDestroyedRphReturnsFalse) { |
| // Setup - make sure the |false| returned by the function being tested is |
| // related to the RPH being dead, and not due other restrictions. |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| |
| // Test |
| rph_.reset(); |
| EXPECT_FALSE(PeerConnectionRemoved(key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| PeerConnectionStoppedOverDestroyedRphReturnsFalse) { |
| // Setup - make sure the |false| returned by the function being tested is |
| // related to the RPH being dead, and not due other restrictions. |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| |
| // Test |
| rph_.reset(); |
| EXPECT_FALSE(PeerConnectionStopped(key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| StartRemoteLoggingOverDestroyedRphReturnsFalse) { |
| // Setup - make sure the |false| returned by the function being tested is |
| // related to the RPH being dead, and not due other restrictions. |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| |
| // Test |
| rph_.reset(); |
| std::string error_message; |
| EXPECT_FALSE(StartRemoteLogging(key, nullptr, &error_message)); |
| EXPECT_EQ(error_message, kStartRemoteLoggingFailureGeneric); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, |
| OnWebRtcEventLogWriteOverDestroyedRphReturnsFalseAndFalse) { |
| // Setup - make sure the |false| returned by the function being tested is |
| // related to the RPH being dead, and not due other restrictions. |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(EnableLocalLogging()); |
| |
| // Test |
| rph_.reset(); |
| EXPECT_EQ(OnWebRtcEventLogWrite(key, "log"), std::make_pair(false, false)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTest, DifferentProfilesCanHaveDifferentPolicies) { |
| auto policy_disabled_profile = CreateBrowserContext("disabled", false); |
| auto policy_disabled_rph = |
| std::make_unique<MockRenderProcessHost>(policy_disabled_profile.get()); |
| const auto disabled_key = |
| GetPeerConnectionKey(policy_disabled_rph.get(), kLid); |
| |
| auto policy_enabled_profile = CreateBrowserContext("enabled", true); |
| auto policy_enabled_rph = |
| std::make_unique<MockRenderProcessHost>(policy_enabled_profile.get()); |
| const auto enabled_key = GetPeerConnectionKey(policy_enabled_rph.get(), kLid); |
| |
| ASSERT_TRUE(PeerConnectionAdded(disabled_key)); |
| ASSERT_TRUE(PeerConnectionAdded(enabled_key)); |
| |
| EXPECT_FALSE(StartRemoteLogging(disabled_key)); |
| EXPECT_TRUE(StartRemoteLogging(enabled_key)); |
| } |
| |
| INSTANTIATE_TEST_CASE_P(UploadCompleteResult, |
| WebRtcEventLogManagerTest, |
| ::testing::Bool()); |
| |
| TEST_F(WebRtcEventLogManagerTestCacheClearing, |
| ClearCacheForBrowserContextRemovesPendingFilesInRange) { |
| SuppressUploading(); |
| |
| auto browser_context = CreateBrowserContext("name"); |
| CreatePendingLogFiles(browser_context.get()); |
| auto& elements = *(pending_logs_[browser_context.get()]); |
| |
| const base::Time earliest_mod = pending_earliest_mod_ - kEpsion; |
| const base::Time latest_mod = pending_latest_mod_ + kEpsion; |
| |
| // Test - ClearCacheForBrowserContext() removed all of the files in the range. |
| ClearCacheForBrowserContext(browser_context.get(), earliest_mod, latest_mod); |
| for (size_t i = 0; i < elements.file_paths.size(); ++i) { |
| EXPECT_FALSE(base::PathExists(*elements.file_paths[i])); |
| } |
| |
| ClearPendingLogFiles(); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestCacheClearing, |
| ClearCacheForBrowserContextCancelsActiveLogFilesIfInRange) { |
| SuppressUploading(); |
| |
| // Setup |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| base::Optional<base::FilePath> file_path; |
| EXPECT_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .Times(1) |
| .WillOnce(Invoke(SaveFilePathTo(&file_path))); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ASSERT_TRUE(file_path); |
| ASSERT_TRUE(base::PathExists(*file_path)); |
| |
| // Test |
| EXPECT_CALL(remote_observer_, OnRemoteLogStopped(key)).Times(1); |
| ClearCacheForBrowserContext( |
| browser_context_.get(), base::Time::Now() - base::TimeDelta::FromHours(1), |
| base::Time::Now() + base::TimeDelta::FromHours(1)); |
| EXPECT_FALSE(base::PathExists(*file_path)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestCacheClearing, |
| ClearCacheForBrowserContextCancelsFileUploadIfInRange) { |
| // This factory will enforce the expectation that the upload is cancelled. |
| // WebRtcEventLogUploaderImplTest.CancelOnOngoingUploadDeletesFile is in |
| // charge of making sure that when the upload is cancelled, the file is |
| // removed from disk. |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<NullWebRtcEventLogUploader::Factory>(true)); |
| |
| // Set up and trigger the uploading of a file. |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| base::Optional<base::FilePath> file_path = CreatePendingRemoteLogFile(key); |
| |
| ASSERT_TRUE(file_path); |
| ASSERT_TRUE(base::PathExists(*file_path)); |
| const base::Time mod_time = GetLastModificationTime(*file_path); |
| |
| // Main part of test - the expectation set up in the the uploader factory |
| // should now be satisfied. |
| ClearCacheForBrowserContext(browser_context_.get(), mod_time - kEpsion, |
| mod_time + kEpsion); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestCacheClearing, |
| ClearCacheForBrowserContextDoesNotRemovePendingFilesOutOfRange) { |
| SuppressUploading(); |
| |
| auto browser_context = CreateBrowserContext("name"); |
| CreatePendingLogFiles(browser_context.get()); |
| auto& elements = *(pending_logs_[browser_context.get()]); |
| |
| // Get a range whose intersection with the files' range is empty. |
| const base::Time earliest_mod = |
| pending_earliest_mod_ - base::TimeDelta::FromHours(2); |
| const base::Time latest_mod = |
| pending_earliest_mod_ - base::TimeDelta::FromHours(1); |
| ASSERT_LT(latest_mod, pending_latest_mod_); |
| |
| // Test - ClearCacheForBrowserContext() does not remove files not in range. |
| // (Range chosen to be earlier than the oldest file |
| ClearCacheForBrowserContext(browser_context.get(), earliest_mod, latest_mod); |
| for (size_t i = 0; i < elements.file_paths.size(); ++i) { |
| EXPECT_TRUE(base::PathExists(*elements.file_paths[i])); |
| } |
| |
| ClearPendingLogFiles(); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestCacheClearing, |
| ClearCacheForBrowserContextDoesNotCancelActiveLogFilesIfOutOfRange) { |
| SuppressUploading(); |
| |
| // Setup |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| base::Optional<base::FilePath> file_path; |
| EXPECT_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .Times(1) |
| .WillOnce(Invoke(SaveFilePathTo(&file_path))); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ASSERT_TRUE(file_path); |
| ASSERT_TRUE(base::PathExists(*file_path)); |
| |
| // Test |
| EXPECT_CALL(remote_observer_, OnRemoteLogStopped(_)).Times(0); |
| ClearCacheForBrowserContext( |
| browser_context_.get(), base::Time::Now() - base::TimeDelta::FromHours(2), |
| base::Time::Now() - base::TimeDelta::FromHours(1)); |
| EXPECT_TRUE(base::PathExists(*file_path)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestCacheClearing, |
| ClearCacheForBrowserContextDoesNotCancelFileUploadIfOutOfRange) { |
| // This factory will enforce the expectation that the upload is not cancelled. |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<NullWebRtcEventLogUploader::Factory>(false)); |
| |
| // Set up and trigger the uploading of a file. |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| base::Optional<base::FilePath> file_path = CreatePendingRemoteLogFile(key); |
| |
| ASSERT_TRUE(file_path); |
| ASSERT_TRUE(base::PathExists(*file_path)); |
| const base::Time mod_time = GetLastModificationTime(*file_path); |
| |
| // Main part of test - the expectation set up in the the uploader factory, |
| // that the upload will not be cancelled, should be shown to hold true. |
| // should now be satisfied. |
| ClearCacheForBrowserContext(browser_context_.get(), mod_time + kEpsion, |
| mod_time + 2 * kEpsion); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestCacheClearing, |
| ClearCacheForBrowserContextDoesNotRemovePendingFilesFromOtherProfiles) { |
| SuppressUploading(); |
| |
| auto cleared_browser_context = CreateBrowserContext("cleared"); |
| CreatePendingLogFiles(cleared_browser_context.get()); |
| auto& cleared_elements = *(pending_logs_[cleared_browser_context.get()]); |
| |
| auto const uncleared_browser_context = CreateBrowserContext("pristine"); |
| CreatePendingLogFiles(uncleared_browser_context.get()); |
| auto& uncleared_elements = *(pending_logs_[uncleared_browser_context.get()]); |
| |
| ASSERT_EQ(cleared_elements.file_paths.size(), |
| uncleared_elements.file_paths.size()); |
| const size_t kFileCount = cleared_elements.file_paths.size(); |
| |
| const base::Time earliest_mod = pending_earliest_mod_ - kEpsion; |
| const base::Time latest_mod = pending_latest_mod_ + kEpsion; |
| |
| // Test - ClearCacheForBrowserContext() only removes the files which belong |
| // to the cleared context. |
| ClearCacheForBrowserContext(cleared_browser_context.get(), earliest_mod, |
| latest_mod); |
| for (size_t i = 0; i < kFileCount; ++i) { |
| EXPECT_FALSE(base::PathExists(*cleared_elements.file_paths[i])); |
| EXPECT_TRUE(base::PathExists(*uncleared_elements.file_paths[i])); |
| } |
| |
| ClearPendingLogFiles(); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestCacheClearing, |
| ClearCacheForBrowserContextDoesNotCancelActiveLogsFromOtherProfiles) { |
| SuppressUploading(); |
| |
| // Remote-bound active log file that *will* be cleared. |
| auto cleared_browser_context = CreateBrowserContext("cleared"); |
| auto cleared_rph = |
| std::make_unique<MockRenderProcessHost>(cleared_browser_context.get()); |
| const auto cleared_key = GetPeerConnectionKey(cleared_rph.get(), kLid); |
| base::Optional<base::FilePath> cleared_file_path = |
| CreateActiveRemoteLogFile(cleared_key); |
| |
| // Remote-bound active log file that will *not* be cleared. |
| auto uncleared_browser_context = CreateBrowserContext("pristine"); |
| auto uncleared_rph = |
| std::make_unique<MockRenderProcessHost>(uncleared_browser_context.get()); |
| const auto uncleared_key = GetPeerConnectionKey(uncleared_rph.get(), kLid); |
| base::Optional<base::FilePath> uncleared_file_path = |
| CreateActiveRemoteLogFile(uncleared_key); |
| |
| // Test - ClearCacheForBrowserContext() only removes the files which belong |
| // to the cleared context. |
| EXPECT_CALL(remote_observer_, OnRemoteLogStopped(cleared_key)).Times(1); |
| EXPECT_CALL(remote_observer_, OnRemoteLogStopped(uncleared_key)).Times(0); |
| ClearCacheForBrowserContext(cleared_browser_context.get(), base::Time::Min(), |
| base::Time::Max()); |
| EXPECT_FALSE(base::PathExists(*cleared_file_path)); |
| EXPECT_TRUE(base::PathExists(*uncleared_file_path)); |
| |
| // Cleanup - uncleared_file_path will be closed as part of the shutdown. It |
| // is time to clear its expectation. |
| testing::Mock::VerifyAndClearExpectations(&remote_observer_); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestCacheClearing, |
| ClearCacheForBrowserContextDoesNotCancelFileUploadFromOtherProfiles) { |
| // This factory will enforce the expectation that the upload is not cancelled. |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<NullWebRtcEventLogUploader::Factory>(false)); |
| |
| // Set up and trigger the uploading of a file. |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| base::Optional<base::FilePath> file_path = CreatePendingRemoteLogFile(key); |
| |
| ASSERT_TRUE(file_path); |
| ASSERT_TRUE(base::PathExists(*file_path)); |
| const base::Time mod_time = GetLastModificationTime(*file_path); |
| |
| // Main part of test - the expectation set up in the the uploader factory, |
| // that the upload will not be cancelled, should be shown to hold true. |
| // should now be satisfied. |
| auto const different_browser_context = CreateBrowserContext(); |
| ClearCacheForBrowserContext(different_browser_context.get(), |
| mod_time - kEpsion, mod_time + kEpsion); |
| } |
| |
| // Show that clearing browser cache, while it removes remote-bound logs, does |
| // not interfere with local-bound logging, even if that happens on the same PC. |
| TEST_F(WebRtcEventLogManagerTestCacheClearing, |
| ClearCacheForBrowserContextDoesNotInterfereWithLocalLogs) { |
| SuppressUploading(); |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| |
| base::Optional<base::FilePath> local_log; |
| ON_CALL(local_observer_, OnLocalLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&local_log))); |
| ASSERT_TRUE(EnableLocalLogging()); |
| |
| // This adds a peer connection for |key|, which also triggers |
| // OnLocalLogStarted() on |local_observer_|. |
| auto pending_remote_log = CreatePendingRemoteLogFile(key); |
| |
| // Test focus - local logging is uninterrupted. |
| EXPECT_CALL(local_observer_, OnLocalLogStopped(_)).Times(0); |
| ClearCacheForBrowserContext(browser_context_.get(), base::Time::Min(), |
| base::Time::Max()); |
| EXPECT_TRUE(base::PathExists(*local_log)); |
| |
| // Sanity on the test itself; the remote log should have been cleared. |
| ASSERT_FALSE(base::PathExists(*pending_remote_log)); |
| } |
| |
| // When cache clearing cancels the active upload, the next (non-deleted) pending |
| // file becomes eligible for upload. |
| TEST_F(WebRtcEventLogManagerTestCacheClearing, |
| UploadCancellationTriggersUploadOfNextPendingFile) { |
| // The first created file will start being uploaded, but then cancelled. |
| // The second file will never be uploaded (deleted while pending). |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<NullWebRtcEventLogUploader::Factory>(true)); |
| |
| // Create the files that will be deleted when cache is cleared. |
| CreatePendingRemoteLogFile(GetPeerConnectionKey(rph_.get(), 0)); |
| CreatePendingRemoteLogFile(GetPeerConnectionKey(rph_.get(), 1)); |
| |
| // Create the not-deleted file under a different profile, to easily make sure |
| // it does not fit in the ClearCacheForBrowserContext range (less fiddly than |
| // a time range). |
| auto other_browser_context = CreateBrowserContext(); |
| auto other_rph = |
| std::make_unique<MockRenderProcessHost>(other_browser_context.get()); |
| const auto key = GetPeerConnectionKey(other_rph.get(), kLid); |
| base::Optional<base::FilePath> other_file = CreatePendingRemoteLogFile(key); |
| ASSERT_TRUE(other_file); |
| |
| // Switch the uploader factory to one that will allow us to ensure that the |
| // new file, which is not deleted, is uploaded. |
| base::RunLoop run_loop; |
| std::list<WebRtcLogFileInfo> expected_files = { |
| WebRtcLogFileInfo(GetBrowserContextId(other_browser_context.get()), |
| *other_file, GetLastModificationTime(*other_file))}; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &expected_files, true, &run_loop)); |
| |
| // Clearing the cache for the first profile, should now trigger the upload |
| // of the last remaining unclear pending log file - |other_file|. |
| ClearCacheForBrowserContext(browser_context_.get(), base::Time::Min(), |
| base::Time::Max()); |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| TEST_P(WebRtcEventLogManagerTestWithRemoteLoggingDisabled, |
| SanityPeerConnectionAdded) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| EXPECT_TRUE(PeerConnectionAdded(key)); |
| } |
| |
| TEST_P(WebRtcEventLogManagerTestWithRemoteLoggingDisabled, |
| SanityPeerConnectionRemoved) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| EXPECT_TRUE(PeerConnectionRemoved(key)); |
| } |
| |
| TEST_P(WebRtcEventLogManagerTestWithRemoteLoggingDisabled, |
| SanityPeerConnectionStopped) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| PeerConnectionStopped(key); // No crash. |
| } |
| |
| TEST_P(WebRtcEventLogManagerTestWithRemoteLoggingDisabled, |
| SanityEnableLocalLogging) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(EnableLocalLogging()); |
| } |
| |
| TEST_P(WebRtcEventLogManagerTestWithRemoteLoggingDisabled, |
| SanityDisableLocalLogging) { |
| ASSERT_TRUE(EnableLocalLogging()); |
| EXPECT_TRUE(DisableLocalLogging()); |
| } |
| |
| TEST_P(WebRtcEventLogManagerTestWithRemoteLoggingDisabled, |
| SanityStartRemoteLogging) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| std::string error_message; |
| EXPECT_FALSE(StartRemoteLogging(key, nullptr, &error_message)); |
| EXPECT_EQ(error_message, kStartRemoteLoggingFailureFeatureDisabled); |
| } |
| |
| TEST_P(WebRtcEventLogManagerTestWithRemoteLoggingDisabled, |
| SanityOnWebRtcEventLogWrite) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_FALSE(StartRemoteLogging(key)); |
| EXPECT_EQ(OnWebRtcEventLogWrite(key, "log"), std::make_pair(false, false)); |
| } |
| |
| INSTANTIATE_TEST_CASE_P(, |
| WebRtcEventLogManagerTestWithRemoteLoggingDisabled, |
| ::testing::Bool()); |
| |
| // This test is redundant; it is provided for completeness; see following tests. |
| TEST_F(WebRtcEventLogManagerTestPolicy, StartsEnabledAllowsRemoteLogging) { |
| SetUp(true); // Feature generally enabled (kill-switch not engaged). |
| |
| const bool allow_remote_logging = true; |
| auto browser_context = CreateBrowserContext("name", allow_remote_logging); |
| |
| auto rph = std::make_unique<MockRenderProcessHost>(browser_context.get()); |
| const auto key = GetPeerConnectionKey(rph.get(), kLid); |
| |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| EXPECT_EQ(StartRemoteLogging(key), allow_remote_logging); |
| } |
| |
| // This test is redundant; it is provided for completeness; see following tests. |
| TEST_F(WebRtcEventLogManagerTestPolicy, StartsDisabledRejectsRemoteLogging) { |
| SetUp(true); // Feature generally enabled (kill-switch not engaged). |
| |
| const bool allow_remote_logging = false; |
| auto browser_context = CreateBrowserContext("name", allow_remote_logging); |
| |
| auto rph = std::make_unique<MockRenderProcessHost>(browser_context.get()); |
| const auto key = GetPeerConnectionKey(rph.get(), kLid); |
| |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| EXPECT_EQ(StartRemoteLogging(key), allow_remote_logging); |
| } |
| |
| // #1 and #2 differ in the order of AddPeerConnection and the changing of |
| // the pref value. |
| TEST_F(WebRtcEventLogManagerTestPolicy, |
| StartsEnabledThenDisabledRejectsRemoteLogging1) { |
| SetUp(true); // Feature generally enabled (kill-switch not engaged). |
| |
| bool allow_remote_logging = true; |
| auto profile = CreateBrowserContext("name", allow_remote_logging); |
| |
| auto rph = std::make_unique<MockRenderProcessHost>(profile.get()); |
| const auto key = GetPeerConnectionKey(rph.get(), kLid); |
| |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| |
| allow_remote_logging = !allow_remote_logging; |
| profile->GetPrefs()->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed, |
| allow_remote_logging); |
| |
| EXPECT_EQ(StartRemoteLogging(key), allow_remote_logging); |
| } |
| |
| // #1 and #2 differ in the order of AddPeerConnection and the changing of |
| // the pref value. |
| TEST_F(WebRtcEventLogManagerTestPolicy, |
| StartsEnabledThenDisabledRejectsRemoteLogging2) { |
| SetUp(true); // Feature generally enabled (kill-switch not engaged). |
| |
| bool allow_remote_logging = true; |
| auto profile = CreateBrowserContext("name", allow_remote_logging); |
| |
| auto rph = std::make_unique<MockRenderProcessHost>(profile.get()); |
| const auto key = GetPeerConnectionKey(rph.get(), kLid); |
| |
| allow_remote_logging = !allow_remote_logging; |
| profile->GetPrefs()->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed, |
| allow_remote_logging); |
| |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| |
| EXPECT_EQ(StartRemoteLogging(key), allow_remote_logging); |
| } |
| |
| // #1 and #2 differ in the order of AddPeerConnection and the changing of |
| // the pref value. |
| TEST_F(WebRtcEventLogManagerTestPolicy, |
| StartsDisabledThenEnabledAllowsRemoteLogging1) { |
| SetUp(true); // Feature generally enabled (kill-switch not engaged). |
| |
| bool allow_remote_logging = false; |
| auto profile = CreateBrowserContext("name", allow_remote_logging); |
| |
| auto rph = std::make_unique<MockRenderProcessHost>(profile.get()); |
| const auto key = GetPeerConnectionKey(rph.get(), kLid); |
| |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| |
| allow_remote_logging = !allow_remote_logging; |
| profile->GetPrefs()->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed, |
| allow_remote_logging); |
| |
| EXPECT_EQ(StartRemoteLogging(key), allow_remote_logging); |
| } |
| |
| // #1 and #2 differ in the order of AddPeerConnection and the changing of |
| // the pref value. |
| TEST_F(WebRtcEventLogManagerTestPolicy, |
| StartsDisabledThenEnabledAllowsRemoteLogging2) { |
| SetUp(true); // Feature generally enabled (kill-switch not engaged). |
| |
| bool allow_remote_logging = false; |
| auto profile = CreateBrowserContext("name", allow_remote_logging); |
| |
| auto rph = std::make_unique<MockRenderProcessHost>(profile.get()); |
| const auto key = GetPeerConnectionKey(rph.get(), kLid); |
| |
| allow_remote_logging = !allow_remote_logging; |
| profile->GetPrefs()->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed, |
| allow_remote_logging); |
| |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| |
| EXPECT_EQ(StartRemoteLogging(key), allow_remote_logging); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestPolicy, |
| StartsDisabledThenEnabledUploadsPendingLogFiles) { |
| SetUp(true); // Feature generally enabled (kill-switch not engaged). |
| |
| bool allow_remote_logging = false; |
| auto profile = CreateBrowserContext("name", allow_remote_logging); |
| |
| auto rph = std::make_unique<MockRenderProcessHost>(profile.get()); |
| const auto key = GetPeerConnectionKey(rph.get(), kLid); |
| |
| allow_remote_logging = !allow_remote_logging; |
| profile->GetPrefs()->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed, |
| allow_remote_logging); |
| |
| base::Optional<base::FilePath> log_file; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&log_file))); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(allow_remote_logging) |
| << "Must turn on before StartRemoteLogging, to test the right thing."; |
| ASSERT_EQ(StartRemoteLogging(key), allow_remote_logging); |
| ASSERT_TRUE(log_file); |
| |
| base::RunLoop run_loop; |
| std::list<WebRtcLogFileInfo> expected_files = {WebRtcLogFileInfo( |
| browser_context_id_, *log_file, GetLastModificationTime(*log_file))}; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &expected_files, true, &run_loop)); |
| |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestPolicy, |
| StartsEnabledThenDisabledDoesNotUploadPendingLogFiles) { |
| SetUp(true); // Feature generally enabled (kill-switch not engaged). |
| |
| SuppressUploading(); |
| |
| std::list<WebRtcLogFileInfo> empty_list; |
| base::RunLoop run_loop; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &empty_list, true, &run_loop)); |
| |
| bool allow_remote_logging = true; |
| auto profile = CreateBrowserContext("name", allow_remote_logging); |
| |
| auto rph = std::make_unique<MockRenderProcessHost>(profile.get()); |
| const auto key = GetPeerConnectionKey(rph.get(), kLid); |
| |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(allow_remote_logging) |
| << "Must turn off after StartRemoteLogging, to test the right thing."; |
| ASSERT_EQ(StartRemoteLogging(key), allow_remote_logging); |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| allow_remote_logging = !allow_remote_logging; |
| profile->GetPrefs()->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed, |
| allow_remote_logging); |
| |
| UnsuppressUploading(); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestPolicy, |
| StartsEnabledThenDisabledDeletesPendingLogFiles) { |
| SetUp(true); // Feature generally enabled (kill-switch not engaged). |
| |
| SuppressUploading(); |
| |
| std::list<WebRtcLogFileInfo> empty_list; |
| base::RunLoop run_loop; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &empty_list, true, &run_loop)); |
| |
| bool allow_remote_logging = true; |
| auto profile = CreateBrowserContext("name", allow_remote_logging); |
| |
| auto rph = std::make_unique<MockRenderProcessHost>(profile.get()); |
| const auto key = GetPeerConnectionKey(rph.get(), kLid); |
| |
| base::Optional<base::FilePath> log_file; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&log_file))); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(allow_remote_logging) |
| << "Must turn off after StartRemoteLogging, to test the right thing."; |
| ASSERT_EQ(StartRemoteLogging(key), allow_remote_logging); |
| ASSERT_TRUE(log_file); |
| |
| // Make the file PENDING. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| ASSERT_TRUE(base::PathExists(*log_file)); // Test sanity; exists before. |
| |
| allow_remote_logging = !allow_remote_logging; |
| profile->GetPrefs()->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed, |
| allow_remote_logging); |
| |
| WaitForPendingTasks(&run_loop); |
| |
| // Test focus - file deleted without being uploaded. |
| EXPECT_FALSE(base::PathExists(*log_file)); |
| |
| // Still not uploaded. |
| UnsuppressUploading(); |
| WaitForPendingTasks(); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestPolicy, |
| StartsEnabledThenDisabledCancelsAndDeletesCurrentlyUploadedLogFile) { |
| SetUp(true); // Feature generally enabled (kill-switch not engaged). |
| |
| // This factory expects exactly one log to be created, then cancelled. |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<NullWebRtcEventLogUploader::Factory>(true, 1)); |
| |
| bool allow_remote_logging = true; |
| auto profile = CreateBrowserContext("name", allow_remote_logging); |
| |
| auto rph = std::make_unique<MockRenderProcessHost>(profile.get()); |
| const auto key = GetPeerConnectionKey(rph.get(), kLid); |
| |
| base::Optional<base::FilePath> log_file; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&log_file))); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(allow_remote_logging) |
| << "Must turn off after StartRemoteLogging, to test the right thing."; |
| ASSERT_EQ(StartRemoteLogging(key), allow_remote_logging); |
| ASSERT_TRUE(log_file); |
| |
| // Log file's upload commences. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| ASSERT_TRUE(base::PathExists(*log_file)); // Test sanity; exists before. |
| |
| allow_remote_logging = !allow_remote_logging; |
| profile->GetPrefs()->SetBoolean(prefs::kWebRtcEventLogCollectionAllowed, |
| allow_remote_logging); |
| |
| WaitForPendingTasks(); |
| |
| // Test focus - file deleted without being uploaded. |
| // When the test terminates, the NullWebRtcEventLogUploader::Factory's |
| // expectation that one log file was uploaded, and that the upload was |
| // cancelled, is enforced. |
| // Deletion of the file not performed by NullWebRtcEventLogUploader; instead, |
| // WebRtcEventLogUploaderImplTest.CancelOnOngoingUploadDeletesFile tests that. |
| } |
| |
| // This test makes sure that if the policy was enabled in the past, but was |
| // disabled while Chrome was not running, pending logs created during the |
| // earlier session will be deleted from disk. |
| TEST_F(WebRtcEventLogManagerTestPolicy, |
| PendingLogsFromPreviousSessionRemovedIfPolicyDisabledAtNewSessionStart) { |
| SetUp(true); // Feature generally enabled (kill-switch not engaged). |
| |
| SuppressUploading(); |
| |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<NullWebRtcEventLogUploader::Factory>(true, 0)); |
| |
| bool allow_remote_logging = true; |
| auto browser_context = CreateBrowserContext("name", allow_remote_logging); |
| |
| const base::FilePath browser_context_dir = |
| RemoteBoundLogsDir(browser_context.get()); |
| ASSERT_TRUE(base::DirectoryExists(browser_context_dir)); |
| |
| auto rph = std::make_unique<MockRenderProcessHost>(browser_context.get()); |
| const auto key = GetPeerConnectionKey(rph.get(), kLid); |
| |
| // Produce an empty log file in the BrowserContext. It's not uploaded |
| // because uploading is suppressed. |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(allow_remote_logging) |
| << "Must turn off after StartRemoteLogging, to test the right thing."; |
| ASSERT_EQ(StartRemoteLogging(key), allow_remote_logging); |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| // Reload the BrowserContext, but this time with the policy disabling |
| // the feature. |
| rph.reset(); |
| browser_context.reset(); |
| ASSERT_TRUE(base::DirectoryExists(browser_context_dir)); // Test sanity |
| allow_remote_logging = false; |
| browser_context = CreateBrowserContext("name", allow_remote_logging); |
| |
| // Test focus - pending log files removed, as well as any potential metadata |
| // associated with remote-bound logging for |browser_context|. |
| ASSERT_FALSE(base::DirectoryExists(browser_context_dir)); |
| |
| // When NullWebRtcEventLogUploader::Factory is destroyed, it will show that |
| // the deleted log file was never uploaded. |
| UnsuppressUploading(); |
| WaitForPendingTasks(); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestPolicy, |
| PendingLogsFromPreviousSessionRemovedIfRemoteLoggingKillSwitchEngaged) { |
| SetUp(false); // Feature generally disabled (kill-switch engaged). |
| |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<NullWebRtcEventLogUploader::Factory>(true, 0)); |
| |
| const std::string name = "name"; |
| const base::FilePath browser_context_dir = |
| profiles_dir_.GetPath().AppendASCII(name); |
| const base::FilePath remote_bound_dir = |
| RemoteBoundLogsDir(browser_context_dir); |
| ASSERT_FALSE(base::PathExists(remote_bound_dir)); |
| |
| base::FilePath file_path; |
| base::File file; |
| ASSERT_TRUE(base::CreateDirectory(remote_bound_dir)); |
| ASSERT_TRUE(CreateRemoteBoundLogFile(remote_bound_dir, remote_log_extension_, |
| &file_path, &file)); |
| file.Close(); |
| |
| const bool allow_remote_logging = true; |
| auto browser_context = CreateBrowserContext(name, allow_remote_logging); |
| ASSERT_EQ(browser_context->GetPath(), browser_context_dir); // Test sanity |
| |
| WaitForPendingTasks(); |
| |
| EXPECT_FALSE(base::PathExists(remote_bound_dir)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestUploadSuppressionDisablingFlag, |
| UploadingNotSuppressedByActivePeerConnections) { |
| SuppressUploading(); |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| |
| base::Optional<base::FilePath> log_file; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&log_file))); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ASSERT_TRUE(log_file); |
| |
| base::RunLoop run_loop; |
| std::list<WebRtcLogFileInfo> expected_files = {WebRtcLogFileInfo( |
| browser_context_id_, *log_file, GetLastModificationTime(*log_file))}; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &expected_files, true, &run_loop)); |
| |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| TEST_P(WebRtcEventLogManagerTestForNetworkConnectivity, |
| DoNotUploadPendingLogsIfConnectedToUnsupportedNetworkType) { |
| WebRtcEventLogManagerTestBase::SetUp( |
| std::make_unique<network::TestNetworkConnectionTracker>( |
| get_conn_type_is_sync_, unsupported_type_)); |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), 1); |
| base::Optional<base::FilePath> log_file; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&log_file))); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ASSERT_TRUE(log_file); |
| |
| std::list<WebRtcLogFileInfo> empty_expected_files_list; |
| base::RunLoop run_loop; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &empty_expected_files_list, true, &run_loop)); |
| |
| // Peer connection removal MAY trigger upload, depending on network. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| TEST_P(WebRtcEventLogManagerTestForNetworkConnectivity, |
| UploadPendingLogsIfConnectedToSupportedNetworkType) { |
| WebRtcEventLogManagerTestBase::SetUp( |
| std::make_unique<network::TestNetworkConnectionTracker>( |
| get_conn_type_is_sync_, supported_type_)); |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), 1); |
| base::Optional<base::FilePath> log_file; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&log_file))); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ASSERT_TRUE(log_file); |
| |
| base::RunLoop run_loop; |
| std::list<WebRtcLogFileInfo> expected_files = {WebRtcLogFileInfo( |
| browser_context_id_, *log_file, GetLastModificationTime(*log_file))}; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &expected_files, true, &run_loop)); |
| |
| // Peer connection removal MAY trigger upload, depending on network. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| TEST_P(WebRtcEventLogManagerTestForNetworkConnectivity, |
| UploadPendingLogsIfConnectionTypeChangesFromUnsupportedToSupported) { |
| auto tracker = std::make_unique<network::TestNetworkConnectionTracker>( |
| get_conn_type_is_sync_, unsupported_type_); |
| network::TestNetworkConnectionTracker* mock = tracker.get(); |
| WebRtcEventLogManagerTestBase::SetUp(std::move(tracker)); |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), 1); |
| base::Optional<base::FilePath> log_file; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&log_file))); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ASSERT_TRUE(log_file); |
| |
| // That a peer connection upload is not initiated by this point, is verified |
| // by previous tests. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| WaitForPendingTasks(); |
| |
| // Test focus - an upload will be initiated after changing the network type. |
| base::RunLoop run_loop; |
| std::list<WebRtcLogFileInfo> expected_files = {WebRtcLogFileInfo( |
| browser_context_id_, *log_file, GetLastModificationTime(*log_file))}; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &expected_files, true, &run_loop)); |
| mock->SetConnectionType(supported_type_); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| TEST_P(WebRtcEventLogManagerTestForNetworkConnectivity, |
| DoNotUploadPendingLogsAtStartupIfConnectedToUnsupportedNetworkType) { |
| WebRtcEventLogManagerTestBase::SetUp( |
| std::make_unique<network::TestNetworkConnectionTracker>( |
| get_conn_type_is_sync_, unsupported_type_)); |
| |
| UnloadProfileAndSeedPendingLog(); |
| |
| // This factory enforces the expectation that the files will be uploaded, |
| // all of them, only them, and in the order expected. |
| std::list<WebRtcLogFileInfo> empty_expected_files_list; |
| base::RunLoop run_loop; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &empty_expected_files_list, true, &run_loop)); |
| |
| LoadMainTestProfile(); |
| ASSERT_EQ(browser_context_->GetPath(), browser_context_path_); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| TEST_P(WebRtcEventLogManagerTestForNetworkConnectivity, |
| UploadPendingLogsAtStartupIfConnectedToSupportedNetworkType) { |
| WebRtcEventLogManagerTestBase::SetUp( |
| std::make_unique<network::TestNetworkConnectionTracker>( |
| get_conn_type_is_sync_, supported_type_)); |
| |
| UnloadProfileAndSeedPendingLog(); |
| |
| // This factory enforces the expectation that the files will be uploaded, |
| // all of them, only them, and in the order expected. |
| base::RunLoop run_loop; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &expected_files_, true, &run_loop)); |
| |
| LoadMainTestProfile(); |
| ASSERT_EQ(browser_context_->GetPath(), browser_context_path_); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| INSTANTIATE_TEST_CASE_P( |
| UploadSupportingConnectionTypes, |
| WebRtcEventLogManagerTestForNetworkConnectivity, |
| ::testing::Combine( |
| // Wehther GetConnectionType() responds synchronously. |
| ::testing::Bool(), |
| // The upload-supporting network type to be used. |
| ::testing::Values(network::mojom::ConnectionType::CONNECTION_ETHERNET, |
| network::mojom::ConnectionType::CONNECTION_WIFI), |
| // The upload-unsupporting network type to be used. |
| ::testing::Values(network::mojom::ConnectionType::CONNECTION_NONE, |
| network::mojom::ConnectionType::CONNECTION_4G))); |
| |
| TEST_F(WebRtcEventLogManagerTestUploadDelay, DoNotInitiateUploadBeforeDelay) { |
| SetUp(kIntentionallyExcessiveDelayMs); |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), 1); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| |
| std::list<WebRtcLogFileInfo> empty_list; |
| base::RunLoop run_loop; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &empty_list, true, &run_loop)); |
| |
| // Change log file from ACTIVE to PENDING. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| // Wait a bit and see that the upload was not initiated. (Due to technical |
| // constraints, we cannot wait forever.) |
| base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL, |
| base::WaitableEvent::InitialState::NOT_SIGNALED); |
| event.TimedWait(base::TimeDelta::FromMilliseconds(500)); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| // WhenPeerConnectionRemovedFinishedRemoteLogUploadedAndFileDeleted has some |
| // overlap with this, but we still include this test for explicitness and |
| // clarity. |
| TEST_F(WebRtcEventLogManagerTestUploadDelay, InitiateUploadAfterDelay) { |
| SetUp(kDefaultUploadDelayMs); |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), 1); |
| base::Optional<base::FilePath> log_file; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&log_file))); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| ASSERT_TRUE(log_file); |
| |
| base::RunLoop run_loop; |
| std::list<WebRtcLogFileInfo> expected_files = {WebRtcLogFileInfo( |
| browser_context_id_, *log_file, GetLastModificationTime(*log_file))}; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &expected_files, true, &run_loop)); |
| |
| // Change log file from ACTIVE to PENDING. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestUploadDelay, |
| PeerConnectionAddedDuringDelaySuppressesUpload) { |
| SetUp(kIntentionallyExcessiveDelayMs); |
| |
| const auto key1 = GetPeerConnectionKey(rph_.get(), 1); |
| const auto key2 = GetPeerConnectionKey(rph_.get(), 2); |
| |
| ASSERT_TRUE(PeerConnectionAdded(key1)); |
| ASSERT_TRUE(StartRemoteLogging(key1)); |
| |
| std::list<WebRtcLogFileInfo> empty_list; |
| base::RunLoop run_loop; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &empty_list, true, &run_loop)); |
| |
| // Change log file from ACTIVE to PENDING. |
| ASSERT_TRUE(PeerConnectionRemoved(key1)); |
| |
| // Test focus - after adding a peer connection, the conditions for the upload |
| // are no longer considered to hold. |
| // (Test implemented with a glimpse into the black box due to technical |
| // limitations and the desire to avoid flakiness.) |
| ASSERT_TRUE(PeerConnectionAdded(key2)); |
| EXPECT_FALSE(UploadConditionsHold()); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestUploadDelay, |
| ClearCacheForBrowserContextDuringDelayCancelsItsUpload) { |
| SetUp(kIntentionallyExcessiveDelayMs); |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), 1); |
| |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key)); |
| |
| std::list<WebRtcLogFileInfo> empty_list; |
| base::RunLoop run_loop; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &empty_list, true, &run_loop)); |
| |
| // Change log file from ACTIVE to PENDING. |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| // Test focus - after clearing browser cache, the conditions for the upload |
| // are no longer considered to hold, because the file about to be uploaded |
| // was deleted. |
| // (Test implemented with a glimpse into the black box due to technical |
| // limitations and the desire to avoid flakiness.) |
| ClearCacheForBrowserContext(browser_context_.get(), base::Time::Min(), |
| base::Time::Max()); |
| EXPECT_FALSE(UploadConditionsHold()); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestCompression, |
| ErroredFilesDueToBadEstimationDeletedRatherThanUploaded) { |
| Init(Compression::GZIP_NULL_ESTIMATION); |
| |
| const std::string log = "It's better than bad; it's good."; |
| |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| base::Optional<base::FilePath> log_file; |
| ON_CALL(remote_observer_, OnRemoteLogStarted(key, _)) |
| .WillByDefault(Invoke(SaveFilePathTo(&log_file))); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_TRUE(StartRemoteLogging(key, GzippedSize(log) - 1)); |
| ASSERT_TRUE(log_file); |
| |
| std::list<WebRtcLogFileInfo> empty_list; |
| base::RunLoop run_loop; |
| SetWebRtcEventLogUploaderFactoryForTesting( |
| std::make_unique<FileListExpectingWebRtcEventLogUploader::Factory>( |
| &empty_list, true, &run_loop)); |
| |
| // Writing fails because the budget is exceeded. |
| EXPECT_EQ(OnWebRtcEventLogWrite(key, log), std::make_pair(false, false)); |
| |
| // The file was deleted due to the error we've instigated (by using an |
| // intentionally over-optimistic estimation). |
| EXPECT_FALSE(base::PathExists(*log_file)); |
| |
| // If the file is incorrectly still eligible for an upload, this will trigger |
| // the upload (which will be a test failure). |
| ASSERT_TRUE(PeerConnectionRemoved(key)); |
| |
| WaitForPendingTasks(&run_loop); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestIncognito, |
| NoRemoteBoundLogsDirectoryCreatedWhenProfileLoaded) { |
| const base::FilePath remote_logs_path = |
| RemoteBoundLogsDir(incognito_profile_); |
| EXPECT_FALSE(base::DirectoryExists(remote_logs_path)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestIncognito, StartRemoteLoggingFails) { |
| const auto key = GetPeerConnectionKey(incognito_rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| EXPECT_FALSE(StartRemoteLogging(key)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestIncognito, |
| StartRemoteLoggingDoesNotCreateDirectoryOrFiles) { |
| const auto key = GetPeerConnectionKey(incognito_rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_FALSE(StartRemoteLogging(key)); |
| |
| const base::FilePath remote_logs_path = |
| RemoteBoundLogsDir(incognito_profile_); |
| EXPECT_FALSE(base::DirectoryExists(remote_logs_path)); |
| } |
| |
| TEST_F(WebRtcEventLogManagerTestIncognito, |
| OnWebRtcEventLogWriteReturnsFalseForRemotePart) { |
| const auto key = GetPeerConnectionKey(incognito_rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| ASSERT_FALSE(StartRemoteLogging(key)); |
| EXPECT_EQ(OnWebRtcEventLogWrite(key, "log"), std::make_pair(false, false)); |
| } |
| |
| #else // defined(OS_ANDROID) |
| |
| class WebRtcEventLogManagerTestOnMobileDevices |
| : public WebRtcEventLogManagerTestBase { |
| public: |
| WebRtcEventLogManagerTestOnMobileDevices() { |
| // features::kWebRtcRemoteEventLog not defined on mobile, and can therefore |
| // not be forced on. This test is here to make sure that when the feature |
| // is changed to be on by default, it will still be off for mobile devices. |
| CreateWebRtcEventLogManager(); |
| } |
| }; |
| |
| TEST_F(WebRtcEventLogManagerTestOnMobileDevices, RemoteBoundLoggingDisabled) { |
| const auto key = GetPeerConnectionKey(rph_.get(), kLid); |
| ASSERT_TRUE(PeerConnectionAdded(key)); |
| EXPECT_FALSE(StartRemoteLogging(key)); |
| } |
| |
| #endif |