OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/bind.h" | 5 #include "base/bind.h" |
6 #include "base/file_path.h" | 6 #include "base/file_path.h" |
7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
8 #include "base/path_service.h" | 8 #include "base/path_service.h" |
9 #include "base/time.h" | 9 #include "base/time.h" |
10 #include "base/test/test_timeouts.h" | 10 #include "base/test/test_timeouts.h" |
11 #include "crypto/nss_util.h" | 11 #include "crypto/nss_util.h" |
12 #include "net/base/completion_callback.h" | 12 #include "net/base/completion_callback.h" |
13 #include "net/base/io_buffer.h" | 13 #include "net/base/io_buffer.h" |
14 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
15 #include "net/socket/socket.h" | 15 #include "net/socket/socket.h" |
16 #include "net/socket/stream_socket.h" | |
16 #include "remoting/protocol/jingle_session.h" | 17 #include "remoting/protocol/jingle_session.h" |
17 #include "remoting/protocol/jingle_session_manager.h" | 18 #include "remoting/protocol/jingle_session_manager.h" |
18 #include "remoting/jingle_glue/jingle_thread.h" | 19 #include "remoting/jingle_glue/jingle_thread.h" |
19 #include "remoting/jingle_glue/fake_signal_strategy.h" | 20 #include "remoting/jingle_glue/fake_signal_strategy.h" |
20 #include "testing/gmock/include/gmock/gmock.h" | 21 #include "testing/gmock/include/gmock/gmock.h" |
21 #include "testing/gtest/include/gtest/gtest.h" | 22 #include "testing/gtest/include/gtest/gtest.h" |
22 #include "third_party/libjingle/source/talk/p2p/client/basicportallocator.h" | 23 #include "third_party/libjingle/source/talk/p2p/client/basicportallocator.h" |
23 | 24 |
24 using testing::_; | 25 using testing::_; |
25 using testing::AtMost; | 26 using testing::AtMost; |
(...skipping 20 matching lines...) Expand all Loading... | |
46 | 47 |
47 namespace { | 48 namespace { |
48 | 49 |
49 // Send 100 messages 1024 bytes each. UDP messages are sent with 10ms delay | 50 // Send 100 messages 1024 bytes each. UDP messages are sent with 10ms delay |
50 // between messages (about 1 second for 100 messages). | 51 // between messages (about 1 second for 100 messages). |
51 const int kMessageSize = 1024; | 52 const int kMessageSize = 1024; |
52 const int kMessages = 100; | 53 const int kMessages = 100; |
53 const int kTestDataSize = kMessages * kMessageSize; | 54 const int kTestDataSize = kMessages * kMessageSize; |
54 const int kUdpWriteDelayMs = 10; | 55 const int kUdpWriteDelayMs = 10; |
55 const char kTestToken[] = "a_dummy_token"; | 56 const char kTestToken[] = "a_dummy_token"; |
57 const char kChannelName[] = "test_channel"; | |
56 | 58 |
57 const char kHostJid[] = "host1@gmail.com/123"; | 59 const char kHostJid[] = "host1@gmail.com/123"; |
58 const char kClientJid[] = "host2@gmail.com/321"; | 60 const char kClientJid[] = "host2@gmail.com/321"; |
59 | 61 |
60 const char kTestHostPublicKey[] = | 62 const char kTestHostPublicKey[] = |
61 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3nk/8ILc0JBqHgOS0UCOIl4m" | 63 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3nk/8ILc0JBqHgOS0UCOIl4m" |
62 "0GUd2FIiZ/6Fc9D/iiyUgli+FIY5dwsrSoNJ87sYGifVDh8a5fdZNV5y58CcrapI5fJI" | 64 "0GUd2FIiZ/6Fc9D/iiyUgli+FIY5dwsrSoNJ87sYGifVDh8a5fdZNV5y58CcrapI5fJI" |
63 "FpXviSW4g8d/t1gcZkoz1ppmjzbgXm6ckw9Td0yRD0cHu732Ijs+eo8wT0pt4KiHkbyR" | 65 "FpXviSW4g8d/t1gcZkoz1ppmjzbgXm6ckw9Td0yRD0cHu732Ijs+eo8wT0pt4KiHkbyR" |
64 "iAvjrvkNDlfiEk7tiY7YzD9zTi3146GX6KLz5GQAd/3I8I5QW3ftF1s/m93AHuc383GZ" | 66 "iAvjrvkNDlfiEk7tiY7YzD9zTi3146GX6KLz5GQAd/3I8I5QW3ftF1s/m93AHuc383GZ" |
65 "A78Oi+IbcJf/jJUZO119VNnRKGiPsf5GZIoHyXX8O5OUQk5soKdQPeK1FwWkeZu6fuXl" | 67 "A78Oi+IbcJf/jJUZO119VNnRKGiPsf5GZIoHyXX8O5OUQk5soKdQPeK1FwWkeZu6fuXl" |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
285 MockSessionManagerListener client_server_listener_; | 287 MockSessionManagerListener client_server_listener_; |
286 | 288 |
287 scoped_ptr<Session> host_session_; | 289 scoped_ptr<Session> host_session_; |
288 MockSessionCallback host_connection_callback_; | 290 MockSessionCallback host_connection_callback_; |
289 scoped_ptr<Session> client_session_; | 291 scoped_ptr<Session> client_session_; |
290 MockSessionCallback client_connection_callback_; | 292 MockSessionCallback client_connection_callback_; |
291 }; | 293 }; |
292 | 294 |
293 class ChannelTesterBase : public base::RefCountedThreadSafe<ChannelTesterBase> { | 295 class ChannelTesterBase : public base::RefCountedThreadSafe<ChannelTesterBase> { |
294 public: | 296 public: |
295 enum ChannelType { | |
296 CONTROL, | |
297 EVENT, | |
298 VIDEO, | |
299 VIDEO_RTP, | |
300 VIDEO_RTCP, | |
301 }; | |
302 | |
303 ChannelTesterBase(Session* host_session, | 297 ChannelTesterBase(Session* host_session, |
304 Session* client_session) | 298 Session* client_session) |
305 : host_session_(host_session), | 299 : host_session_(host_session), |
306 client_session_(client_session), | 300 client_session_(client_session), |
301 socket_1_(NULL), | |
302 socket_2_(NULL), | |
307 done_(false) { | 303 done_(false) { |
308 } | 304 } |
309 | 305 |
310 virtual ~ChannelTesterBase() { } | 306 virtual ~ChannelTesterBase() { } |
311 | 307 |
312 void Start(ChannelType channel) { | 308 void Start() { |
313 MessageLoop::current()->PostTask( | 309 MessageLoop::current()->PostTask( |
314 FROM_HERE, NewRunnableMethod(this, &ChannelTesterBase::DoStart, | 310 FROM_HERE, NewRunnableMethod(this, &ChannelTesterBase::DoStart)); |
315 channel)); | |
316 } | 311 } |
317 | 312 |
318 bool WaitFinished() { | 313 bool WaitFinished() { |
319 return RunMessageLoopWithTimeout(TestTimeouts::action_max_timeout_ms()); | 314 return RunMessageLoopWithTimeout(TestTimeouts::action_max_timeout_ms()); |
320 } | 315 } |
321 | 316 |
322 virtual void CheckResults() = 0; | 317 virtual void CheckResults() = 0; |
323 | 318 |
324 protected: | 319 protected: |
325 void DoStart(ChannelType channel) { | 320 void DoStart() { |
326 socket_1_ = SelectChannel(host_session_, channel); | 321 InitChannels(); |
327 socket_2_ = SelectChannel(client_session_, channel); | 322 } |
328 | 323 |
329 InitBuffers(); | 324 virtual void InitChannels() = 0; |
330 DoRead(); | |
331 DoWrite(); | |
332 } | |
333 | 325 |
334 void Done() { | 326 void Done() { |
335 done_ = true; | 327 done_ = true; |
336 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&QuitCurrentThread)); | 328 MessageLoop::current()->PostTask(FROM_HERE, base::Bind(&QuitCurrentThread)); |
337 } | 329 } |
338 | 330 |
339 virtual void InitBuffers() = 0; | 331 virtual void InitBuffers() = 0; |
340 virtual void DoWrite() = 0; | 332 virtual void DoWrite() = 0; |
341 virtual void DoRead() = 0; | 333 virtual void DoRead() = 0; |
342 | 334 |
343 net::Socket* SelectChannel(Session* session, | |
344 ChannelType channel) { | |
345 switch (channel) { | |
346 case CONTROL: | |
347 return session->control_channel(); | |
348 case EVENT: | |
349 return session->event_channel(); | |
350 case VIDEO: | |
351 return session->video_channel(); | |
352 case VIDEO_RTP: | |
353 return session->video_rtp_channel(); | |
354 case VIDEO_RTCP: | |
355 return session->video_rtcp_channel(); | |
356 default: | |
357 NOTREACHED(); | |
358 return NULL; | |
359 } | |
360 } | |
361 | |
362 Session* host_session_; | 335 Session* host_session_; |
363 Session* client_session_; | 336 Session* client_session_; |
364 net::Socket* socket_1_; | 337 net::Socket* socket_1_; |
365 net::Socket* socket_2_; | 338 net::Socket* socket_2_; |
366 bool done_; | 339 bool done_; |
367 }; | 340 }; |
368 | 341 |
369 class TCPChannelTester : public ChannelTesterBase { | 342 class TCPChannelTester : public ChannelTesterBase { |
370 public: | 343 public: |
371 TCPChannelTester(Session* host_session, | 344 TCPChannelTester(Session* host_session, |
(...skipping 21 matching lines...) Expand all Loading... | |
393 ASSERT_EQ(test_data_size_, input_buffer_->offset()); | 366 ASSERT_EQ(test_data_size_, input_buffer_->offset()); |
394 | 367 |
395 output_buffer_->SetOffset(0); | 368 output_buffer_->SetOffset(0); |
396 ASSERT_EQ(test_data_size_, output_buffer_->size()); | 369 ASSERT_EQ(test_data_size_, output_buffer_->size()); |
397 | 370 |
398 EXPECT_EQ(0, memcmp(output_buffer_->data(), | 371 EXPECT_EQ(0, memcmp(output_buffer_->data(), |
399 input_buffer_->StartOfBuffer(), test_data_size_)); | 372 input_buffer_->StartOfBuffer(), test_data_size_)); |
400 } | 373 } |
401 | 374 |
402 protected: | 375 protected: |
376 virtual void InitChannels() OVERRIDE { | |
377 host_session_->CreateStreamChannel( | |
378 kChannelName, | |
379 base::Bind(&TCPChannelTester::OnChannelReady, | |
380 base::Unretained(this), 0)); | |
381 client_session_->CreateStreamChannel( | |
382 kChannelName, | |
383 base::Bind(&TCPChannelTester::OnChannelReady, | |
384 base::Unretained(this), 1)); | |
385 } | |
386 | |
387 void OnChannelReady(int id, const std::string name, | |
388 net::StreamSocket* socket) { | |
389 ASSERT_TRUE(socket); | |
390 ASSERT_EQ(name, kChannelName); | |
391 if (!socket) { | |
392 Done(); | |
393 return; | |
394 } | |
395 | |
396 switch (id) { | |
397 case 0: | |
398 socket_1_ = socket; | |
399 break; | |
400 | |
401 case 1: | |
402 socket_2_ = socket; | |
403 break; | |
404 | |
405 default: | |
406 NOTREACHED(); | |
407 } | |
408 | |
409 if (socket_1_ && socket_2_) { | |
410 InitBuffers(); | |
411 DoRead(); | |
412 DoWrite(); | |
413 } | |
414 } | |
415 | |
403 virtual void InitBuffers() { | 416 virtual void InitBuffers() { |
404 output_buffer_ = new net::DrainableIOBuffer( | 417 output_buffer_ = new net::DrainableIOBuffer( |
405 new net::IOBuffer(test_data_size_), test_data_size_); | 418 new net::IOBuffer(test_data_size_), test_data_size_); |
406 memset(output_buffer_->data(), 123, test_data_size_); | 419 memset(output_buffer_->data(), 123, test_data_size_); |
407 | 420 |
408 input_buffer_ = new net::GrowableIOBuffer(); | 421 input_buffer_ = new net::GrowableIOBuffer(); |
409 } | 422 } |
410 | 423 |
411 virtual void DoWrite() { | 424 virtual void DoWrite() { |
412 int result = 1; | 425 int result = 1; |
(...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
529 | 542 |
530 EXPECT_EQ(0, broken_packets_); | 543 EXPECT_EQ(0, broken_packets_); |
531 | 544 |
532 // Verify that we've received at least one packet. | 545 // Verify that we've received at least one packet. |
533 EXPECT_GT(packets_received_, 0); | 546 EXPECT_GT(packets_received_, 0); |
534 LOG(INFO) << "Received " << packets_received_ << " packets out of " | 547 LOG(INFO) << "Received " << packets_received_ << " packets out of " |
535 << kMessages; | 548 << kMessages; |
536 } | 549 } |
537 | 550 |
538 protected: | 551 protected: |
552 virtual void InitChannels() OVERRIDE { | |
553 host_session_->CreateDatagramChannel( | |
554 kChannelName, | |
555 base::Bind(&UDPChannelTester::OnChannelReady, | |
556 base::Unretained(this), 0)); | |
557 client_session_->CreateDatagramChannel( | |
558 kChannelName, | |
559 base::Bind(&UDPChannelTester::OnChannelReady, | |
560 base::Unretained(this), 1)); | |
561 } | |
562 | |
563 void OnChannelReady(int id, const std::string name, net::Socket* socket) { | |
564 ASSERT_TRUE(socket); | |
565 ASSERT_EQ(name, kChannelName); | |
566 if (!socket) { | |
567 Done(); | |
568 return; | |
569 } | |
570 | |
571 switch (id) { | |
572 case 0: | |
573 socket_1_ = socket; | |
Wez
2011/08/04 23:49:52
nit: Simpler to use an array of two sockets, here
Sergey Ulanov
2011/08/09 19:41:10
Done.
| |
574 break; | |
575 | |
576 case 1: | |
577 socket_2_ = socket; | |
578 break; | |
579 | |
580 default: | |
581 NOTREACHED(); | |
582 } | |
583 | |
584 if (socket_1_ && socket_2_) { | |
585 InitBuffers(); | |
586 DoRead(); | |
587 DoWrite(); | |
588 } | |
589 } | |
590 | |
591 | |
539 virtual void InitBuffers() { | 592 virtual void InitBuffers() { |
540 } | 593 } |
541 | 594 |
542 virtual void DoWrite() { | 595 virtual void DoWrite() { |
543 if (packets_sent_ >= kMessages) { | 596 if (packets_sent_ >= kMessages) { |
544 Done(); | 597 Done(); |
545 return; | 598 return; |
546 } | 599 } |
547 | 600 |
548 scoped_refptr<net::IOBuffer> packet(new net::IOBuffer(kMessageSize)); | 601 scoped_refptr<net::IOBuffer> packet(new net::IOBuffer(kMessageSize)); |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
671 ASSERT_TRUE(InitiateConnection(kTestSharedSecret)); | 724 ASSERT_TRUE(InitiateConnection(kTestSharedSecret)); |
672 } | 725 } |
673 | 726 |
674 // Verify that we can't connect two endpoints with mismatched secrets. | 727 // Verify that we can't connect two endpoints with mismatched secrets. |
675 TEST_F(JingleSessionTest, ConnectBadChannelAuth) { | 728 TEST_F(JingleSessionTest, ConnectBadChannelAuth) { |
676 CreateServerPair(); | 729 CreateServerPair(); |
677 ASSERT_TRUE(InitiateConnection(kTestSharedSecretBad)); | 730 ASSERT_TRUE(InitiateConnection(kTestSharedSecretBad)); |
678 } | 731 } |
679 | 732 |
680 // Verify that data can be transmitted over the event channel. | 733 // Verify that data can be transmitted over the event channel. |
681 TEST_F(JingleSessionTest, TestControlChannel) { | 734 TEST_F(JingleSessionTest, TestTcpChannel) { |
682 CreateServerPair(); | 735 CreateServerPair(); |
683 ASSERT_TRUE(InitiateConnection(kTestSharedSecret)); | 736 ASSERT_TRUE(InitiateConnection(kTestSharedSecret)); |
684 scoped_refptr<TCPChannelTester> tester( | 737 scoped_refptr<TCPChannelTester> tester( |
685 new TCPChannelTester(host_session_.get(), client_session_.get(), | 738 new TCPChannelTester(host_session_.get(), client_session_.get(), |
686 kMessageSize, kMessages)); | 739 kMessageSize, kMessages)); |
687 tester->Start(ChannelTesterBase::CONTROL); | 740 tester->Start(); |
688 ASSERT_TRUE(tester->WaitFinished()); | 741 ASSERT_TRUE(tester->WaitFinished()); |
689 tester->CheckResults(); | 742 tester->CheckResults(); |
690 | 743 |
691 // Connections must be closed while |tester| still exists. | |
692 CloseSessions(); | |
693 } | |
694 | |
695 // Verify that data can be transmitted over the video channel. | |
696 TEST_F(JingleSessionTest, TestVideoChannel) { | |
697 CreateServerPair(); | |
698 ASSERT_TRUE(InitiateConnection(kTestSharedSecret)); | |
699 scoped_refptr<TCPChannelTester> tester( | |
700 new TCPChannelTester(host_session_.get(), client_session_.get(), | |
701 kMessageSize, kMessageSize)); | |
702 tester->Start(ChannelTesterBase::VIDEO); | |
703 ASSERT_TRUE(tester->WaitFinished()); | |
704 tester->CheckResults(); | |
705 | |
706 // Connections must be closed while |tester| still exists. | |
707 CloseSessions(); | |
708 } | |
709 | |
710 // Verify that data can be transmitted over the event channel. | |
711 TEST_F(JingleSessionTest, TestEventChannel) { | |
712 CreateServerPair(); | |
713 ASSERT_TRUE(InitiateConnection(kTestSharedSecret)); | |
714 scoped_refptr<TCPChannelTester> tester( | |
715 new TCPChannelTester(host_session_.get(), client_session_.get(), | |
716 kMessageSize, kMessageSize)); | |
717 tester->Start(ChannelTesterBase::EVENT); | |
718 ASSERT_TRUE(tester->WaitFinished()); | |
719 tester->CheckResults(); | |
720 | |
721 // Connections must be closed while |tester| still exists. | 744 // Connections must be closed while |tester| still exists. |
722 CloseSessions(); | 745 CloseSessions(); |
723 } | 746 } |
724 | 747 |
725 // Verify that data can be transmitted over the video RTP channel. | 748 // Verify that data can be transmitted over the video RTP channel. |
726 // Disabled because RTP support is disabled, see crbug.com/91538 . | 749 TEST_F(JingleSessionTest, TestUdpChannel) { |
727 TEST_F(JingleSessionTest, DISABLED_TestVideoRtpChannel) { | |
728 CreateServerPair(); | 750 CreateServerPair(); |
729 ASSERT_TRUE(InitiateConnection(kTestSharedSecret)); | 751 ASSERT_TRUE(InitiateConnection(kTestSharedSecret)); |
730 scoped_refptr<UDPChannelTester> tester( | 752 scoped_refptr<UDPChannelTester> tester( |
731 new UDPChannelTester(host_session_.get(), client_session_.get())); | 753 new UDPChannelTester(host_session_.get(), client_session_.get())); |
732 tester->Start(ChannelTesterBase::VIDEO_RTP); | 754 tester->Start(); |
733 ASSERT_TRUE(tester->WaitFinished()); | 755 ASSERT_TRUE(tester->WaitFinished()); |
734 tester->CheckResults(); | 756 tester->CheckResults(); |
735 | 757 |
736 // Connections must be closed while |tester| still exists. | 758 // Connections must be closed while |tester| still exists. |
737 CloseSessions(); | 759 CloseSessions(); |
738 } | 760 } |
739 | 761 |
740 // Send packets of different size to get the latency for sending data | 762 // Send packets of different size to get the latency for sending data |
741 // using sockets from JingleSession. | 763 // using sockets from JingleSession. |
742 TEST_F(JingleSessionTest, TestSpeed) { | 764 TEST_F(JingleSessionTest, TestSpeed) { |
743 CreateServerPair(); | 765 CreateServerPair(); |
744 ASSERT_TRUE(InitiateConnection(kTestSharedSecret)); | 766 ASSERT_TRUE(InitiateConnection(kTestSharedSecret)); |
745 scoped_refptr<ChannelSpeedTester> tester; | 767 scoped_refptr<ChannelSpeedTester> tester; |
746 | 768 |
747 tester = new ChannelSpeedTester(host_session_.get(), | 769 tester = new ChannelSpeedTester(host_session_.get(), |
748 client_session_.get(), 512); | 770 client_session_.get(), 512); |
749 tester->Start(ChannelTesterBase::VIDEO); | 771 tester->Start(); |
750 ASSERT_TRUE(tester->WaitFinished()); | 772 ASSERT_TRUE(tester->WaitFinished()); |
751 LOG(INFO) << "Time for 512 bytes " | 773 LOG(INFO) << "Time for 512 bytes " |
752 << tester->GetElapsedTime().InMilliseconds() << " ms."; | 774 << tester->GetElapsedTime().InMilliseconds() << " ms."; |
753 | 775 |
776 CloseSessions(); | |
777 ASSERT_TRUE(InitiateConnection(kTestSharedSecret)); | |
778 | |
754 tester = new ChannelSpeedTester(host_session_.get(), | 779 tester = new ChannelSpeedTester(host_session_.get(), |
755 client_session_.get(), 1024); | 780 client_session_.get(), 1024); |
756 tester->Start(ChannelTesterBase::VIDEO); | 781 tester->Start(); |
757 ASSERT_TRUE(tester->WaitFinished()); | 782 ASSERT_TRUE(tester->WaitFinished()); |
758 LOG(INFO) << "Time for 1024 bytes " | 783 LOG(INFO) << "Time for 1024 bytes " |
759 << tester->GetElapsedTime().InMilliseconds() << " ms."; | 784 << tester->GetElapsedTime().InMilliseconds() << " ms."; |
760 | 785 |
786 CloseSessions(); | |
787 ASSERT_TRUE(InitiateConnection(kTestSharedSecret)); | |
788 | |
761 tester = new ChannelSpeedTester(host_session_.get(), | 789 tester = new ChannelSpeedTester(host_session_.get(), |
762 client_session_.get(), 51200); | 790 client_session_.get(), 51200); |
763 tester->Start(ChannelTesterBase::VIDEO); | 791 tester->Start(); |
764 ASSERT_TRUE(tester->WaitFinished()); | 792 ASSERT_TRUE(tester->WaitFinished()); |
765 LOG(INFO) << "Time for 50k bytes " | 793 LOG(INFO) << "Time for 50k bytes " |
766 << tester->GetElapsedTime().InMilliseconds() << " ms."; | 794 << tester->GetElapsedTime().InMilliseconds() << " ms."; |
767 | 795 |
796 CloseSessions(); | |
797 ASSERT_TRUE(InitiateConnection(kTestSharedSecret)); | |
798 | |
768 tester = new ChannelSpeedTester(host_session_.get(), | 799 tester = new ChannelSpeedTester(host_session_.get(), |
769 client_session_.get(), 512000); | 800 client_session_.get(), 512000); |
770 tester->Start(ChannelTesterBase::VIDEO); | 801 tester->Start(); |
771 ASSERT_TRUE(tester->WaitFinished()); | 802 ASSERT_TRUE(tester->WaitFinished()); |
772 LOG(INFO) << "Time for 500k bytes " | 803 LOG(INFO) << "Time for 500k bytes " |
773 << tester->GetElapsedTime().InMilliseconds() << " ms."; | 804 << tester->GetElapsedTime().InMilliseconds() << " ms."; |
774 | 805 |
775 // Connections must be closed while |tester| still exists. | 806 // Connections must be closed while |tester| still exists. |
776 CloseSessions(); | 807 CloseSessions(); |
777 } | 808 } |
778 | 809 |
779 } // namespace protocol | 810 } // namespace protocol |
780 } // namespace remoting | 811 } // namespace remoting |
OLD | NEW |