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