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/files/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 17 class 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 62 class 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 DeleteDumpHandler() { handler_.reset(); } 83 84 void WriteFakeDumpFiles(const base::FilePath& dir, 85 base::FilePath* incoming_dump, 86 base::FilePath* outgoing_dump) { 87 *incoming_dump = dir.AppendASCII("recv"); 88 *outgoing_dump = dir.AppendASCII("send"); 89 const char dummy[] = "dummy"; 90 EXPECT_GT(base::WriteFile(*incoming_dump, dummy, arraysize(dummy)), 0); 91 EXPECT_GT(base::WriteFile(*outgoing_dump, dummy, arraysize(dummy)), 0); 92 } 93 94 MOCK_METHOD2(OnStopDumpFinished, 95 void(bool success, const std::string& error)); 96 97 MOCK_METHOD0(OnStopOngoingDumpsFinished, void(void)); 98 99 protected: 100 content::TestBrowserThreadBundle thread_bundle_; 101 scoped_ptr<WebRtcRtpDumpHandler> handler_; 102 }; 103 104 TEST_F(WebRtcRtpDumpHandlerTest, StateTransition) { 105 std::string error; 106 107 RtpDumpType types[3]; 108 types[0] = RTP_DUMP_INCOMING; 109 types[1] = RTP_DUMP_OUTGOING; 110 types[2] = RTP_DUMP_BOTH; 111 112 for (size_t i = 0; i < arraysize(types); ++i) { 113 DVLOG(2) << "Verifying state transition: type = " << types[i]; 114 115 // Only StartDump is allowed in STATE_NONE. 116 EXPECT_CALL(*this, OnStopDumpFinished(false, testing::_)); 117 handler_->StopDump(types[i], 118 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished, 119 base::Unretained(this))); 120 121 WebRtcRtpDumpHandler::ReleasedDumps empty_dumps(handler_->ReleaseDumps()); 122 EXPECT_TRUE(empty_dumps.incoming_dump_path.empty()); 123 EXPECT_TRUE(empty_dumps.outgoing_dump_path.empty()); 124 EXPECT_TRUE(handler_->StartDump(types[i], &error)); 125 base::RunLoop().RunUntilIdle(); 126 127 // Only StopDump is allowed in STATE_STARTED. 128 EXPECT_FALSE(handler_->StartDump(types[i], &error)); 129 EXPECT_FALSE(handler_->ReadyToRelease()); 130 131 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_)); 132 handler_->StopDump(types[i], 133 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished, 134 base::Unretained(this))); 135 base::RunLoop().RunUntilIdle(); 136 137 // Only ReleaseDump is allowed in STATE_STOPPED. 138 EXPECT_FALSE(handler_->StartDump(types[i], &error)); 139 140 EXPECT_CALL(*this, OnStopDumpFinished(false, testing::_)); 141 handler_->StopDump(types[i], 142 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished, 143 base::Unretained(this))); 144 EXPECT_TRUE(handler_->ReadyToRelease()); 145 146 WebRtcRtpDumpHandler::ReleasedDumps dumps(handler_->ReleaseDumps()); 147 if (types[i] == RTP_DUMP_INCOMING || types[i] == RTP_DUMP_BOTH) 148 EXPECT_FALSE(dumps.incoming_dump_path.empty()); 149 150 if (types[i] == RTP_DUMP_OUTGOING || types[i] == RTP_DUMP_BOTH) 151 EXPECT_FALSE(dumps.outgoing_dump_path.empty()); 152 153 base::RunLoop().RunUntilIdle(); 154 ResetDumpHandler(base::FilePath(), true); 155 } 156 } 157 158 TEST_F(WebRtcRtpDumpHandlerTest, StoppedWhenMaxSizeReached) { 159 std::string error; 160 161 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_INCOMING, &error)); 162 163 std::vector<uint8> buffer(100, 0); 164 handler_->OnRtpPacket(&buffer[0], buffer.size(), buffer.size(), true); 165 base::RunLoop().RunUntilIdle(); 166 167 // Dumping should have been stopped, so ready to release. 168 WebRtcRtpDumpHandler::ReleasedDumps dumps = handler_->ReleaseDumps(); 169 EXPECT_FALSE(dumps.incoming_dump_path.empty()); 170 } 171 172 TEST_F(WebRtcRtpDumpHandlerTest, PacketIgnoredIfDumpingNotStarted) { 173 std::vector<uint8> buffer(100, 0); 174 handler_->OnRtpPacket(&buffer[0], buffer.size(), buffer.size(), true); 175 handler_->OnRtpPacket(&buffer[0], buffer.size(), buffer.size(), false); 176 base::RunLoop().RunUntilIdle(); 177 } 178 179 TEST_F(WebRtcRtpDumpHandlerTest, PacketIgnoredIfDumpingStopped) { 180 std::string error; 181 182 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_INCOMING, &error)); 183 184 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_)); 185 handler_->StopDump(RTP_DUMP_INCOMING, 186 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished, 187 base::Unretained(this))); 188 189 std::vector<uint8> buffer(100, 0); 190 handler_->OnRtpPacket(&buffer[0], buffer.size(), buffer.size(), true); 191 base::RunLoop().RunUntilIdle(); 192 } 193 194 TEST_F(WebRtcRtpDumpHandlerTest, CannotStartMoreThanFiveDumps) { 195 std::string error; 196 197 handler_.reset(); 198 199 scoped_ptr<WebRtcRtpDumpHandler> handlers[6]; 200 201 for (size_t i = 0; i < arraysize(handlers); ++i) { 202 handlers[i].reset(new WebRtcRtpDumpHandler(base::FilePath())); 203 204 if (i < arraysize(handlers) - 1) { 205 EXPECT_TRUE(handlers[i]->StartDump(RTP_DUMP_INCOMING, &error)); 206 } else { 207 EXPECT_FALSE(handlers[i]->StartDump(RTP_DUMP_INCOMING, &error)); 208 } 209 } 210 } 211 212 TEST_F(WebRtcRtpDumpHandlerTest, StartStopIncomingThenStartStopOutgoing) { 213 std::string error; 214 215 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_)).Times(2); 216 217 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_INCOMING, &error)); 218 handler_->StopDump(RTP_DUMP_INCOMING, 219 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished, 220 base::Unretained(this))); 221 222 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_OUTGOING, &error)); 223 handler_->StopDump(RTP_DUMP_OUTGOING, 224 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished, 225 base::Unretained(this))); 226 227 base::RunLoop().RunUntilIdle(); 228 } 229 230 TEST_F(WebRtcRtpDumpHandlerTest, StartIncomingStartOutgoingThenStopBoth) { 231 std::string error; 232 233 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_)); 234 235 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_INCOMING, &error)); 236 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_OUTGOING, &error)); 237 238 handler_->StopDump(RTP_DUMP_INCOMING, 239 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished, 240 base::Unretained(this))); 241 242 base::RunLoop().RunUntilIdle(); 243 } 244 245 TEST_F(WebRtcRtpDumpHandlerTest, StartBothThenStopIncomingStopOutgoing) { 246 std::string error; 247 248 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_)).Times(2); 249 250 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_BOTH, &error)); 251 252 handler_->StopDump(RTP_DUMP_INCOMING, 253 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished, 254 base::Unretained(this))); 255 handler_->StopDump(RTP_DUMP_OUTGOING, 256 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished, 257 base::Unretained(this))); 258 259 base::RunLoop().RunUntilIdle(); 260 } 261 262 TEST_F(WebRtcRtpDumpHandlerTest, DumpsCleanedUpIfNotReleased) { 263 base::ScopedTempDir temp_dir; 264 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 265 ResetDumpHandler(temp_dir.path(), true); 266 267 base::FilePath incoming_dump, outgoing_dump; 268 WriteFakeDumpFiles(temp_dir.path(), &incoming_dump, &outgoing_dump); 269 270 std::string error; 271 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_BOTH, &error)); 272 273 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_)); 274 handler_->StopDump(RTP_DUMP_BOTH, 275 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished, 276 base::Unretained(this))); 277 base::RunLoop().RunUntilIdle(); 278 279 handler_.reset(); 280 base::RunLoop().RunUntilIdle(); 281 282 EXPECT_FALSE(base::PathExists(incoming_dump)); 283 EXPECT_FALSE(base::PathExists(outgoing_dump)); 284 } 285 286 TEST_F(WebRtcRtpDumpHandlerTest, DumpDeletedIfEndDumpFailed) { 287 base::ScopedTempDir temp_dir; 288 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 289 290 // Make the writer return failure on EndStream. 291 ResetDumpHandler(temp_dir.path(), false); 292 293 base::FilePath incoming_dump, outgoing_dump; 294 WriteFakeDumpFiles(temp_dir.path(), &incoming_dump, &outgoing_dump); 295 296 std::string error; 297 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_BOTH, &error)); 298 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_)).Times(2); 299 300 handler_->StopDump(RTP_DUMP_INCOMING, 301 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished, 302 base::Unretained(this))); 303 base::RunLoop().RunUntilIdle(); 304 305 EXPECT_FALSE(base::PathExists(incoming_dump)); 306 EXPECT_TRUE(base::PathExists(outgoing_dump)); 307 308 handler_->StopDump(RTP_DUMP_OUTGOING, 309 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished, 310 base::Unretained(this))); 311 base::RunLoop().RunUntilIdle(); 312 EXPECT_FALSE(base::PathExists(outgoing_dump)); 313 } 314 315 TEST_F(WebRtcRtpDumpHandlerTest, StopOngoingDumpsWhileStoppingDumps) { 316 std::string error; 317 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_BOTH, &error)); 318 319 testing::InSequence s; 320 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_)); 321 EXPECT_CALL(*this, OnStopOngoingDumpsFinished()); 322 323 handler_->StopDump(RTP_DUMP_BOTH, 324 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished, 325 base::Unretained(this))); 326 327 handler_->StopOngoingDumps( 328 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopOngoingDumpsFinished, 329 base::Unretained(this))); 330 331 base::RunLoop().RunUntilIdle(); 332 333 WebRtcRtpDumpHandler::ReleasedDumps dumps(handler_->ReleaseDumps()); 334 EXPECT_FALSE(dumps.incoming_dump_path.empty()); 335 EXPECT_FALSE(dumps.outgoing_dump_path.empty()); 336 } 337 338 TEST_F(WebRtcRtpDumpHandlerTest, StopOngoingDumpsWhileDumping) { 339 std::string error; 340 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_BOTH, &error)); 341 342 EXPECT_CALL(*this, OnStopOngoingDumpsFinished()); 343 344 handler_->StopOngoingDumps( 345 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopOngoingDumpsFinished, 346 base::Unretained(this))); 347 348 base::RunLoop().RunUntilIdle(); 349 350 WebRtcRtpDumpHandler::ReleasedDumps dumps(handler_->ReleaseDumps()); 351 EXPECT_FALSE(dumps.incoming_dump_path.empty()); 352 EXPECT_FALSE(dumps.outgoing_dump_path.empty()); 353 } 354 355 TEST_F(WebRtcRtpDumpHandlerTest, StopOngoingDumpsWhenAlreadyStopped) { 356 std::string error; 357 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_BOTH, &error)); 358 359 { 360 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_)); 361 362 handler_->StopDump(RTP_DUMP_BOTH, 363 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished, 364 base::Unretained(this))); 365 base::RunLoop().RunUntilIdle(); 366 } 367 368 EXPECT_CALL(*this, OnStopOngoingDumpsFinished()); 369 handler_->StopOngoingDumps( 370 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopOngoingDumpsFinished, 371 base::Unretained(this))); 372 } 373 374 TEST_F(WebRtcRtpDumpHandlerTest, StopOngoingDumpsWhileStoppingOneDump) { 375 std::string error; 376 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_BOTH, &error)); 377 378 testing::InSequence s; 379 EXPECT_CALL(*this, OnStopDumpFinished(true, testing::_)); 380 EXPECT_CALL(*this, OnStopOngoingDumpsFinished()); 381 382 handler_->StopDump(RTP_DUMP_INCOMING, 383 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopDumpFinished, 384 base::Unretained(this))); 385 386 handler_->StopOngoingDumps( 387 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopOngoingDumpsFinished, 388 base::Unretained(this))); 389 390 base::RunLoop().RunUntilIdle(); 391 392 WebRtcRtpDumpHandler::ReleasedDumps dumps(handler_->ReleaseDumps()); 393 EXPECT_FALSE(dumps.incoming_dump_path.empty()); 394 EXPECT_FALSE(dumps.outgoing_dump_path.empty()); 395 } 396 397 TEST_F(WebRtcRtpDumpHandlerTest, DeleteHandlerBeforeStopCallback) { 398 std::string error; 399 400 EXPECT_CALL(*this, OnStopOngoingDumpsFinished()) 401 .WillOnce(testing::InvokeWithoutArgs( 402 this, &WebRtcRtpDumpHandlerTest::DeleteDumpHandler)); 403 404 EXPECT_TRUE(handler_->StartDump(RTP_DUMP_BOTH, &error)); 405 406 handler_->StopOngoingDumps( 407 base::Bind(&WebRtcRtpDumpHandlerTest::OnStopOngoingDumpsFinished, 408 base::Unretained(this))); 409 410 base::RunLoop().RunUntilIdle(); 411 } 412