1 // Copyright 2014 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_rtp_dump_handler.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <memory>
11 #include <utility>
12
13 #include "base/bind.h"
14 #include "base/callback_helpers.h"
15 #include "base/files/file_util.h"
16 #include "base/files/scoped_temp_dir.h"
17 #include "base/location.h"
18 #include "base/logging.h"
19 #include "base/run_loop.h"
20 #include "base/sequenced_task_runner.h"
21 #include "base/single_thread_task_runner.h"
22 #include "base/stl_util.h"
23 #include "base/task/thread_pool/thread_pool_instance.h"
24 #include "base/threading/thread_task_runner_handle.h"
25 #include "chrome/browser/media/webrtc/webrtc_rtp_dump_writer.h"
26 #include "content/public/test/browser_task_environment.h"
27 #include "testing/gmock/include/gmock/gmock.h"
28 #include "testing/gtest/include/gtest/gtest.h"
29
30 class FakeDumpWriter : public WebRtcRtpDumpWriter {
31 public:
FakeDumpWriter(size_t max_dump_size,const base::RepeatingClosure & max_size_reached_callback,bool end_dump_success)32 FakeDumpWriter(size_t max_dump_size,
33 const base::RepeatingClosure& max_size_reached_callback,
34 bool end_dump_success)
35 : WebRtcRtpDumpWriter(base::FilePath(),
36 base::FilePath(),
37 max_dump_size,
38 base::NullCallback()),
39 max_dump_size_(max_dump_size),
40 current_dump_size_(0),
41 max_size_reached_callback_(max_size_reached_callback),
42 end_dump_success_(end_dump_success) {}
43
WriteRtpPacket(const uint8_t * packet_header,size_t header_length,size_t packet_length,bool incoming)44 void WriteRtpPacket(const uint8_t* packet_header,
45 size_t header_length,
46 size_t packet_length,
47 bool incoming) override {
48 current_dump_size_ += header_length;
49 if (current_dump_size_ > max_dump_size_)
50 max_size_reached_callback_.Run();
51 }
52
EndDump(RtpDumpType type,EndDumpCallback finished_callback)53 void EndDump(RtpDumpType type, EndDumpCallback finished_callback) override {
54 bool incoming_success = end_dump_success_;
55 bool outgoing_success = end_dump_success_;
56
57 if (type == RTP_DUMP_INCOMING)
58 outgoing_success = false;
59 else if (type == RTP_DUMP_OUTGOING)
60 incoming_success = false;
61
62 base::ThreadTaskRunnerHandle::Get()->PostTask(
63 FROM_HERE, base::BindOnce(std::move(finished_callback),
64 incoming_success, outgoing_success));
65 }
66
67 private:
68 size_t max_dump_size_;
69 size_t current_dump_size_;
70 base::RepeatingClosure max_size_reached_callback_;
71 bool end_dump_success_;
72 };
73
74 class WebRtcRtpDumpHandlerTest : public testing::Test {
75 public:
WebRtcRtpDumpHandlerTest()76 WebRtcRtpDumpHandlerTest()
77 : task_environment_(content::BrowserTaskEnvironment::IO_MAINLOOP) {
78 ResetDumpHandler(base::FilePath(), true);
79 }
80
ResetDumpHandler(const base::FilePath & dir,bool end_dump_success)81 void ResetDumpHandler(const base::FilePath& dir, bool end_dump_success) {
82 handler_.reset(new WebRtcRtpDumpHandler(
83 dir.empty() ? base::FilePath(FILE_PATH_LITERAL("dummy")) : dir));
84
85 std::unique_ptr<WebRtcRtpDumpWriter> writer(new FakeDumpWriter(
86 10,
87 base::BindRepeating(&WebRtcRtpDumpHandler::OnMaxDumpSizeReached,
88 base::Unretained(handler_.get())),
89 end_dump_success));
90
91 handler_->SetDumpWriterForTesting(std::move(writer));
92 }
93
DeleteDumpHandler()94 void DeleteDumpHandler() { handler_.reset(); }
95
WriteFakeDumpFiles(const base::FilePath & dir,base::FilePath * incoming_dump,base::FilePath * outgoing_dump)96 void WriteFakeDumpFiles(const base::FilePath& dir,
97 base::FilePath* incoming_dump,
98 base::FilePath* outgoing_dump) {
99 *incoming_dump = dir.AppendASCII("recv");
100 *outgoing_dump = dir.AppendASCII("send");
101 const char dummy[] = "dummy";
102 EXPECT_GT(base::WriteFile(*incoming_dump, dummy, base::size(dummy)), 0);
103 EXPECT_GT(base::WriteFile(*outgoing_dump, dummy, base::size(dummy)), 0);
104 }
105
FlushTaskRunners()106 void FlushTaskRunners() {
107 base::ThreadPoolInstance::Get()->FlushForTesting();
108 base::RunLoop().RunUntilIdle();
109 }
110
111 MOCK_METHOD2(OnStopDumpFinished,
112 void(bool success, const std::string& error));
113
114 MOCK_METHOD0(OnStopOngoingDumpsFinished, void(void));
115
116 protected:
117 content::BrowserTaskEnvironment task_environment_;
118 std::unique_ptr<WebRtcRtpDumpHandler> handler_;
119 };
120
TEST_F(WebRtcRtpDumpHandlerTest,StateTransition)121 TEST_F(WebRtcRtpDumpHandlerTest, StateTransition) {
122 std::string error;
123
124 RtpDumpType types[3];
125 types[0] = RTP_DUMP_INCOMING;
126 types[1] = RTP_DUMP_OUTGOING;
127 types[2] = RTP_DUMP_BOTH;
128
129 for (size_t i = 0; i < base::size(types); ++i) {
130 DVLOG(2) << "Verifying state transition: type = " << types[i];
131
132 // Only StartDump is allowed in STATE_NONE.
133 EXPECT_CALL(*this, OnStopDumpFinished(false, testing::_));
134 handler_->StopDump(
135 types[i], base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished,
136 base::Unretained(this)));
137
138 WebRtcRtpDumpHandler::ReleasedDumps empty_dumps(handler_->ReleaseDumps());
139 EXPECT_TRUE(empty_dumps.incoming_dump_path.empty());
140 EXPECT_TRUE(empty_dumps.outgoing_dump_path.empty());
141 EXPECT_TRUE(handler_->StartDump(types[i], &error));
142 base::RunLoop().RunUntilIdle();
143
144 // Only StopDump is allowed in STATE_STARTED.
145 EXPECT_FALSE(handler_->StartDump(types[i], &error));
146 EXPECT_FALSE(handler_->ReadyToRelease());
147
148 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_));
149 handler_->StopDump(
150 types[i], base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished,
151 base::Unretained(this)));
152 base::RunLoop().RunUntilIdle();
153
154 // Only ReleaseDump is allowed in STATE_STOPPED.
155 EXPECT_FALSE(handler_->StartDump(types[i], &error));
156
157 EXPECT_CALL(*this, OnStopDumpFinished(false, testing::_));
158 handler_->StopDump(
159 types[i], base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished,
160 base::Unretained(this)));
161 EXPECT_TRUE(handler_->ReadyToRelease());
162
163 WebRtcRtpDumpHandler::ReleasedDumps dumps(handler_->ReleaseDumps());
164 if (types[i] == RTP_DUMP_INCOMING || types[i] == RTP_DUMP_BOTH)
165 EXPECT_FALSE(dumps.incoming_dump_path.empty());
166
167 if (types[i] == RTP_DUMP_OUTGOING || types[i] == RTP_DUMP_BOTH)
168 EXPECT_FALSE(dumps.outgoing_dump_path.empty());
169
170 base::RunLoop().RunUntilIdle();
171 ResetDumpHandler(base::FilePath(), true);
172 }
173 }
174
TEST_F(WebRtcRtpDumpHandlerTest,StoppedWhenMaxSizeReached)175 TEST_F(WebRtcRtpDumpHandlerTest, StoppedWhenMaxSizeReached) {
176 std::string error;
177
178 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_INCOMING, &error));
179
180 std::vector<uint8_t> buffer(100, 0);
181 handler_->OnRtpPacket(&buffer[0], buffer.size(), buffer.size(), true);
182 base::RunLoop().RunUntilIdle();
183
184 // Dumping should have been stopped, so ready to release.
185 WebRtcRtpDumpHandler::ReleasedDumps dumps = handler_->ReleaseDumps();
186 EXPECT_FALSE(dumps.incoming_dump_path.empty());
187 }
188
TEST_F(WebRtcRtpDumpHandlerTest,PacketIgnoredIfDumpingNotStarted)189 TEST_F(WebRtcRtpDumpHandlerTest, PacketIgnoredIfDumpingNotStarted) {
190 std::vector<uint8_t> buffer(100, 0);
191 handler_->OnRtpPacket(&buffer[0], buffer.size(), buffer.size(), true);
192 handler_->OnRtpPacket(&buffer[0], buffer.size(), buffer.size(), false);
193 base::RunLoop().RunUntilIdle();
194 }
195
TEST_F(WebRtcRtpDumpHandlerTest,PacketIgnoredIfDumpingStopped)196 TEST_F(WebRtcRtpDumpHandlerTest, PacketIgnoredIfDumpingStopped) {
197 std::string error;
198
199 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_INCOMING, &error));
200
201 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_));
202 handler_->StopDump(
203 RTP_DUMP_INCOMING,
204 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished,
205 base::Unretained(this)));
206
207 std::vector<uint8_t> buffer(100, 0);
208 handler_->OnRtpPacket(&buffer[0], buffer.size(), buffer.size(), true);
209 base::RunLoop().RunUntilIdle();
210 }
211
TEST_F(WebRtcRtpDumpHandlerTest,CannotStartMoreThanFiveDumps)212 TEST_F(WebRtcRtpDumpHandlerTest, CannotStartMoreThanFiveDumps) {
213 std::string error;
214
215 handler_.reset();
216
217 std::unique_ptr<WebRtcRtpDumpHandler> handlers[6];
218
219 for (size_t i = 0; i < base::size(handlers); ++i) {
220 handlers[i].reset(new WebRtcRtpDumpHandler(base::FilePath()));
221
222 if (i < base::size(handlers) - 1) {
223 EXPECT_TRUE(handlers[i]->StartDump(RTP_DUMP_INCOMING, &error));
224 } else {
225 EXPECT_FALSE(handlers[i]->StartDump(RTP_DUMP_INCOMING, &error));
226 }
227 }
228 }
229
TEST_F(WebRtcRtpDumpHandlerTest,StartStopIncomingThenStartStopOutgoing)230 TEST_F(WebRtcRtpDumpHandlerTest, StartStopIncomingThenStartStopOutgoing) {
231 std::string error;
232
233 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_)).Times(2);
234
235 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_INCOMING, &error));
236 handler_->StopDump(
237 RTP_DUMP_INCOMING,
238 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished,
239 base::Unretained(this)));
240
241 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_OUTGOING, &error));
242 handler_->StopDump(
243 RTP_DUMP_OUTGOING,
244 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished,
245 base::Unretained(this)));
246
247 base::RunLoop().RunUntilIdle();
248 }
249
TEST_F(WebRtcRtpDumpHandlerTest,StartIncomingStartOutgoingThenStopBoth)250 TEST_F(WebRtcRtpDumpHandlerTest, StartIncomingStartOutgoingThenStopBoth) {
251 std::string error;
252
253 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_));
254
255 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_INCOMING, &error));
256 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_OUTGOING, &error));
257
258 handler_->StopDump(
259 RTP_DUMP_INCOMING,
260 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished,
261 base::Unretained(this)));
262
263 base::RunLoop().RunUntilIdle();
264 }
265
TEST_F(WebRtcRtpDumpHandlerTest,StartBothThenStopIncomingStopOutgoing)266 TEST_F(WebRtcRtpDumpHandlerTest, StartBothThenStopIncomingStopOutgoing) {
267 std::string error;
268
269 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_)).Times(2);
270
271 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_BOTH, &error));
272
273 handler_->StopDump(
274 RTP_DUMP_INCOMING,
275 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished,
276 base::Unretained(this)));
277 handler_->StopDump(
278 RTP_DUMP_OUTGOING,
279 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished,
280 base::Unretained(this)));
281
282 base::RunLoop().RunUntilIdle();
283 }
284
TEST_F(WebRtcRtpDumpHandlerTest,DumpsCleanedUpIfNotReleased)285 TEST_F(WebRtcRtpDumpHandlerTest, DumpsCleanedUpIfNotReleased) {
286 base::ScopedTempDir temp_dir;
287 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
288 ResetDumpHandler(temp_dir.GetPath(), true);
289
290 base::FilePath incoming_dump, outgoing_dump;
291 WriteFakeDumpFiles(temp_dir.GetPath(), &incoming_dump, &outgoing_dump);
292
293 std::string error;
294 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_BOTH, &error));
295
296 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_));
297 handler_->StopDump(
298 RTP_DUMP_BOTH,
299 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished,
300 base::Unretained(this)));
301 base::RunLoop().RunUntilIdle();
302 FlushTaskRunners();
303
304 handler_.reset();
305 FlushTaskRunners();
306
307 EXPECT_FALSE(base::PathExists(incoming_dump));
308 EXPECT_FALSE(base::PathExists(outgoing_dump));
309 }
310
TEST_F(WebRtcRtpDumpHandlerTest,DumpDeletedIfEndDumpFailed)311 TEST_F(WebRtcRtpDumpHandlerTest, DumpDeletedIfEndDumpFailed) {
312 base::ScopedTempDir temp_dir;
313 ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
314
315 // Make the writer return failure on EndStream.
316 ResetDumpHandler(temp_dir.GetPath(), false);
317
318 base::FilePath incoming_dump, outgoing_dump;
319 WriteFakeDumpFiles(temp_dir.GetPath(), &incoming_dump, &outgoing_dump);
320
321 std::string error;
322 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_BOTH, &error));
323 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_)).Times(2);
324
325 handler_->StopDump(
326 RTP_DUMP_INCOMING,
327 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished,
328 base::Unretained(this)));
329 base::RunLoop().RunUntilIdle();
330 FlushTaskRunners();
331
332 EXPECT_FALSE(base::PathExists(incoming_dump));
333 EXPECT_TRUE(base::PathExists(outgoing_dump));
334
335 handler_->StopDump(
336 RTP_DUMP_OUTGOING,
337 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished,
338 base::Unretained(this)));
339 base::RunLoop().RunUntilIdle();
340 FlushTaskRunners();
341 EXPECT_FALSE(base::PathExists(outgoing_dump));
342 }
343
TEST_F(WebRtcRtpDumpHandlerTest,StopOngoingDumpsWhileStoppingDumps)344 TEST_F(WebRtcRtpDumpHandlerTest, StopOngoingDumpsWhileStoppingDumps) {
345 std::string error;
346 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_BOTH, &error));
347
348 testing::InSequence s;
349 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_));
350 EXPECT_CALL(*this, OnStopOngoingDumpsFinished());
351
352 handler_->StopDump(
353 RTP_DUMP_BOTH,
354 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished,
355 base::Unretained(this)));
356 base::RunLoop().RunUntilIdle();
357
358 handler_->StopOngoingDumps(
359 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopOngoingDumpsFinished,
360 base::Unretained(this)));
361
362 FlushTaskRunners();
363
364 WebRtcRtpDumpHandler::ReleasedDumps dumps(handler_->ReleaseDumps());
365 EXPECT_FALSE(dumps.incoming_dump_path.empty());
366 EXPECT_FALSE(dumps.outgoing_dump_path.empty());
367 }
368
TEST_F(WebRtcRtpDumpHandlerTest,StopOngoingDumpsWhileDumping)369 TEST_F(WebRtcRtpDumpHandlerTest, StopOngoingDumpsWhileDumping) {
370 std::string error;
371 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_BOTH, &error));
372
373 EXPECT_CALL(*this, OnStopOngoingDumpsFinished());
374
375 handler_->StopOngoingDumps(
376 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopOngoingDumpsFinished,
377 base::Unretained(this)));
378
379 FlushTaskRunners();
380
381 WebRtcRtpDumpHandler::ReleasedDumps dumps(handler_->ReleaseDumps());
382 EXPECT_FALSE(dumps.incoming_dump_path.empty());
383 EXPECT_FALSE(dumps.outgoing_dump_path.empty());
384 }
385
TEST_F(WebRtcRtpDumpHandlerTest,StopOngoingDumpsWhenAlreadyStopped)386 TEST_F(WebRtcRtpDumpHandlerTest, StopOngoingDumpsWhenAlreadyStopped) {
387 std::string error;
388 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_BOTH, &error));
389
390 {
391 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_));
392
393 handler_->StopDump(
394 RTP_DUMP_BOTH,
395 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished,
396 base::Unretained(this)));
397 base::RunLoop().RunUntilIdle();
398 FlushTaskRunners();
399 }
400
401 EXPECT_CALL(*this, OnStopOngoingDumpsFinished());
402 handler_->StopOngoingDumps(
403 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopOngoingDumpsFinished,
404 base::Unretained(this)));
405 }
406
TEST_F(WebRtcRtpDumpHandlerTest,StopOngoingDumpsWhileStoppingOneDump)407 TEST_F(WebRtcRtpDumpHandlerTest, StopOngoingDumpsWhileStoppingOneDump) {
408 std::string error;
409 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_BOTH, &error));
410
411 testing::InSequence s;
412 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_));
413 EXPECT_CALL(*this, OnStopOngoingDumpsFinished());
414
415 handler_->StopDump(
416 RTP_DUMP_INCOMING,
417 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished,
418 base::Unretained(this)));
419 base::RunLoop().RunUntilIdle();
420
421 handler_->StopOngoingDumps(
422 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopOngoingDumpsFinished,
423 base::Unretained(this)));
424
425 FlushTaskRunners();
426
427 WebRtcRtpDumpHandler::ReleasedDumps dumps(handler_->ReleaseDumps());
428 EXPECT_FALSE(dumps.incoming_dump_path.empty());
429 EXPECT_FALSE(dumps.outgoing_dump_path.empty());
430 }
431
TEST_F(WebRtcRtpDumpHandlerTest,DeleteHandlerBeforeStopCallback)432 TEST_F(WebRtcRtpDumpHandlerTest, DeleteHandlerBeforeStopCallback) {
433 std::string error;
434
435 EXPECT_CALL(*this, OnStopOngoingDumpsFinished())
436 .WillOnce(testing::InvokeWithoutArgs(
437 this, &WebRtcRtpDumpHandlerTest::DeleteDumpHandler));
438
439 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_BOTH, &error));
440
441 handler_->StopOngoingDumps(
442 base::BindOnce(&WebRtcRtpDumpHandlerTest::OnStopOngoingDumpsFinished,
443 base::Unretained(this)));
444
445 base::RunLoop().RunUntilIdle();
446 }
447