1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/media/webrtc/webrtc_event_log_uploader.h"
6
7 #include <memory>
8 #include <string>
9
10 #include "base/bind.h"
11 #include "base/callback_forward.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/files/scoped_temp_dir.h"
15 #include "base/memory/scoped_refptr.h"
16 #include "base/run_loop.h"
17 #include "build/build_config.h"
18 #include "chrome/browser/media/webrtc/webrtc_event_log_manager_common.h"
19 #include "chrome/test/base/testing_browser_process.h"
20 #include "chrome/test/base/testing_profile_manager.h"
21 #include "content/public/test/browser_task_environment.h"
22 #include "net/http/http_status_code.h"
23 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
24 #include "services/network/test/test_url_loader_factory.h"
25 #include "services/network/test/test_utils.h"
26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28
29 namespace webrtc_event_logging {
30
31 using ::testing::StrictMock;
32 using BrowserContextId = WebRtcEventLogPeerConnectionKey::BrowserContextId;
33
34 namespace {
35 class UploadObserver {
36 public:
UploadObserver(base::OnceClosure on_complete_callback)37 explicit UploadObserver(base::OnceClosure on_complete_callback)
38 : on_complete_callback_(std::move(on_complete_callback)) {}
39
40 // Combines the mock functionality via a helper (CompletionCallback),
41 // as well as unblocks its owner through |on_complete_callback_|.
OnWebRtcEventLogUploadComplete(const base::FilePath & log_file,bool upload_successful)42 void OnWebRtcEventLogUploadComplete(const base::FilePath& log_file,
43 bool upload_successful) {
44 CompletionCallback(log_file, upload_successful);
45 std::move(on_complete_callback_).Run();
46 }
47
48 MOCK_METHOD2(CompletionCallback, void(const base::FilePath&, bool));
49
50 private:
51 base::OnceClosure on_complete_callback_;
52 };
53
54 #if defined(OS_POSIX)
RemovePermissions(const base::FilePath & path,int removed_permissions)55 void RemovePermissions(const base::FilePath& path, int removed_permissions) {
56 int permissions;
57 ASSERT_TRUE(base::GetPosixFilePermissions(path, &permissions));
58 permissions &= ~removed_permissions;
59 ASSERT_TRUE(base::SetPosixFilePermissions(path, permissions));
60 }
61
RemoveReadPermissions(const base::FilePath & path)62 void RemoveReadPermissions(const base::FilePath& path) {
63 constexpr int read_permissions = base::FILE_PERMISSION_READ_BY_USER |
64 base::FILE_PERMISSION_READ_BY_GROUP |
65 base::FILE_PERMISSION_READ_BY_OTHERS;
66 RemovePermissions(path, read_permissions);
67 }
68 #endif // defined(OS_POSIX)
69 } // namespace
70
71 class WebRtcEventLogUploaderImplTest : public ::testing::Test {
72 public:
WebRtcEventLogUploaderImplTest()73 WebRtcEventLogUploaderImplTest()
74 : test_shared_url_loader_factory_(
75 base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
76 &test_url_loader_factory_)),
77 observer_run_loop_(),
78 observer_(observer_run_loop_.QuitWhenIdleClosure()) {
79 TestingBrowserProcess::GetGlobal()->SetSharedURLLoaderFactory(
80 test_shared_url_loader_factory_);
81
82 EXPECT_TRUE(base::Time::FromString("30 Dec 1983", &kReasonableTime));
83
84 uploader_factory_ = std::make_unique<WebRtcEventLogUploaderImpl::Factory>();
85 }
86
~WebRtcEventLogUploaderImplTest()87 ~WebRtcEventLogUploaderImplTest() override {
88 task_environment_.RunUntilIdle();
89 }
90
SetUp()91 void SetUp() override {
92 testing_profile_manager_ = std::make_unique<TestingProfileManager>(
93 TestingBrowserProcess::GetGlobal());
94 EXPECT_TRUE(profiles_dir_.CreateUniqueTempDir());
95 EXPECT_TRUE(testing_profile_manager_->SetUp(profiles_dir_.GetPath()));
96
97 testing_profile_ =
98 testing_profile_manager_->CreateTestingProfile("arbitrary_name");
99
100 browser_context_id_ = GetBrowserContextId(testing_profile_);
101
102 // Create the sub-dir for the remote-bound logs that would have been set
103 // up by WebRtcEventLogManager, if WebRtcEventLogManager were instantiated.
104 // Note that the testing profile's overall directory is a temporary one.
105 const base::FilePath logs_dir =
106 GetRemoteBoundWebRtcEventLogsDir(testing_profile_->GetPath());
107 ASSERT_TRUE(base::CreateDirectory(logs_dir));
108
109 // Create a log file and put some arbitrary data in it.
110 // Note that the testing profile's overall directory is a temporary one.
111 ASSERT_TRUE(base::CreateTemporaryFileInDir(logs_dir, &log_file_));
112 constexpr size_t kLogFileSizeBytes = 100u;
113 const std::string file_contents(kLogFileSizeBytes, 'A');
114 ASSERT_EQ(
115 base::WriteFile(log_file_, file_contents.c_str(), file_contents.size()),
116 static_cast<int>(file_contents.size()));
117 }
118
119 // For tests which imitate a response (or several).
SetURLLoaderResponse(net::HttpStatusCode http_code,int net_error)120 void SetURLLoaderResponse(net::HttpStatusCode http_code, int net_error) {
121 DCHECK(test_shared_url_loader_factory_);
122 const std::string kResponseId = "ec1ed029734b8f7e"; // Arbitrary.
123 test_url_loader_factory_.AddResponse(
124 GURL(WebRtcEventLogUploaderImpl::kUploadURL),
125 network::CreateURLResponseHead(http_code), kResponseId,
126 network::URLLoaderCompletionStatus(net_error));
127 }
128
StartAndWaitForUpload(BrowserContextId browser_context_id=BrowserContextId (),base::Time last_modified_time=base::Time ())129 void StartAndWaitForUpload(
130 BrowserContextId browser_context_id = BrowserContextId(),
131 base::Time last_modified_time = base::Time()) {
132 DCHECK(test_shared_url_loader_factory_);
133
134 if (last_modified_time.is_null()) {
135 last_modified_time = kReasonableTime;
136 }
137
138 const WebRtcLogFileInfo log_file_info(browser_context_id, log_file_,
139 last_modified_time);
140
141 uploader_ = uploader_factory_->Create(log_file_info, ResultCallback());
142
143 observer_run_loop_.Run(); // Observer was given quit-closure by ctor.
144 }
145
StartAndWaitForUploadWithCustomMaxSize(size_t max_log_size_bytes,BrowserContextId browser_context_id=BrowserContextId (),base::Time last_modified_time=base::Time ())146 void StartAndWaitForUploadWithCustomMaxSize(
147 size_t max_log_size_bytes,
148 BrowserContextId browser_context_id = BrowserContextId(),
149 base::Time last_modified_time = base::Time()) {
150 DCHECK(test_shared_url_loader_factory_);
151
152 if (last_modified_time.is_null()) {
153 last_modified_time = kReasonableTime;
154 }
155
156 const WebRtcLogFileInfo log_file_info(browser_context_id, log_file_,
157 last_modified_time);
158
159 uploader_ = uploader_factory_->CreateWithCustomMaxSizeForTesting(
160 log_file_info, ResultCallback(), max_log_size_bytes);
161
162 observer_run_loop_.Run(); // Observer was given quit-closure by ctor.
163 }
164
StartUploadThatWillNotTerminate(BrowserContextId browser_context_id=BrowserContextId (),base::Time last_modified_time=base::Time ())165 void StartUploadThatWillNotTerminate(
166 BrowserContextId browser_context_id = BrowserContextId(),
167 base::Time last_modified_time = base::Time()) {
168 DCHECK(test_shared_url_loader_factory_);
169
170 if (last_modified_time.is_null()) {
171 last_modified_time = kReasonableTime;
172 }
173
174 const WebRtcLogFileInfo log_file_info(browser_context_id, log_file_,
175 last_modified_time);
176
177 uploader_ = uploader_factory_->Create(log_file_info, ResultCallback());
178 }
179
ResultCallback()180 WebRtcEventLogUploader::UploadResultCallback ResultCallback() {
181 return base::BindOnce(&UploadObserver::OnWebRtcEventLogUploadComplete,
182 base::Unretained(&observer_));
183 }
184
185 content::BrowserTaskEnvironment task_environment_;
186
187 base::Time kReasonableTime;
188
189 network::TestURLLoaderFactory test_url_loader_factory_;
190 scoped_refptr<network::SharedURLLoaderFactory>
191 test_shared_url_loader_factory_;
192
193 base::RunLoop observer_run_loop_;
194
195 base::ScopedTempDir profiles_dir_;
196 std::unique_ptr<TestingProfileManager> testing_profile_manager_;
197 TestingProfile* testing_profile_; // |testing_profile_manager_| owns.
198 BrowserContextId browser_context_id_;
199
200 base::FilePath log_file_;
201
202 StrictMock<UploadObserver> observer_;
203
204 // These (uploader-factory and uploader) are the units under test.
205 std::unique_ptr<WebRtcEventLogUploaderImpl::Factory> uploader_factory_;
206 std::unique_ptr<WebRtcEventLogUploader> uploader_;
207 };
208
TEST_F(WebRtcEventLogUploaderImplTest,SuccessfulUploadReportedToObserver)209 TEST_F(WebRtcEventLogUploaderImplTest, SuccessfulUploadReportedToObserver) {
210 SetURLLoaderResponse(net::HTTP_OK, net::OK);
211 EXPECT_CALL(observer_, CompletionCallback(log_file_, true)).Times(1);
212 StartAndWaitForUpload();
213 EXPECT_FALSE(base::PathExists(log_file_));
214 }
215
216 // Version #1 - request reported as successful, but got an error (404) as the
217 // HTTP return code.
218 // Due to the simplicitly of both tests, this also tests the scenario
219 // FileDeletedAfterUnsuccessfulUpload, rather than giving each its own test.
TEST_F(WebRtcEventLogUploaderImplTest,UnsuccessfulUploadReportedToObserver1)220 TEST_F(WebRtcEventLogUploaderImplTest, UnsuccessfulUploadReportedToObserver1) {
221 SetURLLoaderResponse(net::HTTP_NOT_FOUND, net::OK);
222 EXPECT_CALL(observer_, CompletionCallback(log_file_, false)).Times(1);
223 StartAndWaitForUpload();
224 EXPECT_FALSE(base::PathExists(log_file_));
225 }
226
227 // Version #2 - request reported as failed; HTTP return code ignored, even
228 // if it's a purported success.
TEST_F(WebRtcEventLogUploaderImplTest,UnsuccessfulUploadReportedToObserver2)229 TEST_F(WebRtcEventLogUploaderImplTest, UnsuccessfulUploadReportedToObserver2) {
230 SetURLLoaderResponse(net::HTTP_NOT_FOUND, net::ERR_FAILED);
231 EXPECT_CALL(observer_, CompletionCallback(log_file_, false)).Times(1);
232 StartAndWaitForUpload();
233 EXPECT_FALSE(base::PathExists(log_file_));
234 }
235
236 #if defined(OS_POSIX)
TEST_F(WebRtcEventLogUploaderImplTest,FailureToReadFileReportedToObserver)237 TEST_F(WebRtcEventLogUploaderImplTest, FailureToReadFileReportedToObserver) {
238 // Show the failure was independent of the URLLoaderFactory's primed return
239 // value.
240 SetURLLoaderResponse(net::HTTP_OK, net::OK);
241
242 RemoveReadPermissions(log_file_);
243 EXPECT_CALL(observer_, CompletionCallback(log_file_, false)).Times(1);
244 StartAndWaitForUpload();
245 }
246
TEST_F(WebRtcEventLogUploaderImplTest,NonExistentFileReportedToObserver)247 TEST_F(WebRtcEventLogUploaderImplTest, NonExistentFileReportedToObserver) {
248 // Show the failure was independent of the URLLoaderFactory's primed return
249 // value.
250 SetURLLoaderResponse(net::HTTP_OK, net::OK);
251
252 log_file_ = log_file_.Append(FILE_PATH_LITERAL("garbage"));
253 EXPECT_CALL(observer_, CompletionCallback(log_file_, false)).Times(1);
254 StartAndWaitForUpload();
255 }
256 #endif // defined(OS_POSIX)
257
TEST_F(WebRtcEventLogUploaderImplTest,FilesUpToMaxSizeUploaded)258 TEST_F(WebRtcEventLogUploaderImplTest, FilesUpToMaxSizeUploaded) {
259 int64_t log_file_size_bytes;
260 ASSERT_TRUE(base::GetFileSize(log_file_, &log_file_size_bytes));
261
262 SetURLLoaderResponse(net::HTTP_OK, net::OK);
263 EXPECT_CALL(observer_, CompletionCallback(log_file_, true)).Times(1);
264 StartAndWaitForUploadWithCustomMaxSize(log_file_size_bytes);
265 EXPECT_FALSE(base::PathExists(log_file_));
266 }
267
TEST_F(WebRtcEventLogUploaderImplTest,ExcessivelyLargeFilesNotUploaded)268 TEST_F(WebRtcEventLogUploaderImplTest, ExcessivelyLargeFilesNotUploaded) {
269 int64_t log_file_size_bytes;
270 ASSERT_TRUE(base::GetFileSize(log_file_, &log_file_size_bytes));
271
272 SetURLLoaderResponse(net::HTTP_OK, net::OK);
273 EXPECT_CALL(observer_, CompletionCallback(log_file_, false)).Times(1);
274 StartAndWaitForUploadWithCustomMaxSize(log_file_size_bytes - 1);
275 EXPECT_FALSE(base::PathExists(log_file_));
276 }
277
TEST_F(WebRtcEventLogUploaderImplTest,CancelBeforeUploadCompletionReturnsTrue)278 TEST_F(WebRtcEventLogUploaderImplTest,
279 CancelBeforeUploadCompletionReturnsTrue) {
280 const base::Time last_modified = base::Time::Now();
281 StartUploadThatWillNotTerminate(browser_context_id_, last_modified);
282
283 EXPECT_TRUE(uploader_->Cancel());
284 }
285
TEST_F(WebRtcEventLogUploaderImplTest,CancelOnCancelledUploadReturnsFalse)286 TEST_F(WebRtcEventLogUploaderImplTest, CancelOnCancelledUploadReturnsFalse) {
287 const base::Time last_modified = base::Time::Now();
288 StartUploadThatWillNotTerminate(browser_context_id_, last_modified);
289
290 ASSERT_TRUE(uploader_->Cancel());
291 EXPECT_FALSE(uploader_->Cancel());
292 }
293
TEST_F(WebRtcEventLogUploaderImplTest,CancelAfterUploadCompletionReturnsFalse)294 TEST_F(WebRtcEventLogUploaderImplTest,
295 CancelAfterUploadCompletionReturnsFalse) {
296 SetURLLoaderResponse(net::HTTP_OK, net::OK);
297 EXPECT_CALL(observer_, CompletionCallback(log_file_, true)).Times(1);
298 StartAndWaitForUpload();
299
300 EXPECT_FALSE(uploader_->Cancel());
301 }
302
TEST_F(WebRtcEventLogUploaderImplTest,CancelOnAbortedUploadReturnsFalse)303 TEST_F(WebRtcEventLogUploaderImplTest, CancelOnAbortedUploadReturnsFalse) {
304 // Show the failure was independent of the URLLoaderFactory's primed return
305 // value.
306 SetURLLoaderResponse(net::HTTP_OK, net::OK);
307
308 log_file_ = log_file_.Append(FILE_PATH_LITERAL("garbage"));
309 EXPECT_CALL(observer_, CompletionCallback(log_file_, false)).Times(1);
310 StartAndWaitForUpload();
311
312 EXPECT_FALSE(uploader_->Cancel());
313 }
314
TEST_F(WebRtcEventLogUploaderImplTest,CancelOnOngoingUploadDeletesFile)315 TEST_F(WebRtcEventLogUploaderImplTest, CancelOnOngoingUploadDeletesFile) {
316 const base::Time last_modified = base::Time::Now();
317 StartUploadThatWillNotTerminate(browser_context_id_, last_modified);
318 ASSERT_TRUE(uploader_->Cancel());
319
320 EXPECT_FALSE(base::PathExists(log_file_));
321 }
322
TEST_F(WebRtcEventLogUploaderImplTest,GetWebRtcLogFileInfoReturnsCorrectInfoBeforeUploadDone)323 TEST_F(WebRtcEventLogUploaderImplTest,
324 GetWebRtcLogFileInfoReturnsCorrectInfoBeforeUploadDone) {
325 const base::Time last_modified = base::Time::Now();
326 StartUploadThatWillNotTerminate(browser_context_id_, last_modified);
327
328 const WebRtcLogFileInfo info = uploader_->GetWebRtcLogFileInfo();
329 EXPECT_EQ(info.browser_context_id, browser_context_id_);
330 EXPECT_EQ(info.path, log_file_);
331 EXPECT_EQ(info.last_modified, last_modified);
332
333 // Test tear-down.
334 ASSERT_TRUE(uploader_->Cancel());
335 }
336
TEST_F(WebRtcEventLogUploaderImplTest,GetWebRtcLogFileInfoReturnsCorrectInfoAfterUploadSucceeded)337 TEST_F(WebRtcEventLogUploaderImplTest,
338 GetWebRtcLogFileInfoReturnsCorrectInfoAfterUploadSucceeded) {
339 SetURLLoaderResponse(net::HTTP_OK, net::OK);
340 EXPECT_CALL(observer_, CompletionCallback(log_file_, true)).Times(1);
341
342 const base::Time last_modified = base::Time::Now();
343 StartAndWaitForUpload(browser_context_id_, last_modified);
344
345 const WebRtcLogFileInfo info = uploader_->GetWebRtcLogFileInfo();
346 EXPECT_EQ(info.browser_context_id, browser_context_id_);
347 EXPECT_EQ(info.path, log_file_);
348 EXPECT_EQ(info.last_modified, last_modified);
349 }
350
TEST_F(WebRtcEventLogUploaderImplTest,GetWebRtcLogFileInfoReturnsCorrectInfoWhenCalledOnCancelledUpload)351 TEST_F(WebRtcEventLogUploaderImplTest,
352 GetWebRtcLogFileInfoReturnsCorrectInfoWhenCalledOnCancelledUpload) {
353 const base::Time last_modified = base::Time::Now();
354 StartUploadThatWillNotTerminate(browser_context_id_, last_modified);
355 ASSERT_TRUE(uploader_->Cancel());
356
357 const WebRtcLogFileInfo info = uploader_->GetWebRtcLogFileInfo();
358 EXPECT_EQ(info.browser_context_id, browser_context_id_);
359 EXPECT_EQ(info.path, log_file_);
360 EXPECT_EQ(info.last_modified, last_modified);
361 }
362
363 // TODO(crbug.com/775415): Add a unit test that shows that files with
364 // non-ASCII filenames are discard. (Or, alternatively, add support for them.)
365
366 } // namespace webrtc_event_logging
367