OLD | NEW |
1 /* | 1 /* |
2 * libjingle | 2 * libjingle |
3 * Copyright 2013 Google Inc. | 3 * Copyright 2013 Google Inc. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are met: | 6 * modification, are permitted provided that the following conditions are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright notice, | 8 * 1. Redistributions of source code must retain the above copyright notice, |
9 * this list of conditions and the following disclaimer. | 9 * this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
43 import java.util.TreeSet; | 43 import java.util.TreeSet; |
44 import java.util.concurrent.CountDownLatch; | 44 import java.util.concurrent.CountDownLatch; |
45 import java.util.concurrent.TimeUnit; | 45 import java.util.concurrent.TimeUnit; |
46 | 46 |
47 import static junit.framework.Assert.*; | 47 import static junit.framework.Assert.*; |
48 | 48 |
49 /** End-to-end tests for PeerConnection.java. */ | 49 /** End-to-end tests for PeerConnection.java. */ |
50 public class PeerConnectionTest { | 50 public class PeerConnectionTest { |
51 // Set to true to render video. | 51 // Set to true to render video. |
52 private static final boolean RENDER_TO_GUI = false; | 52 private static final boolean RENDER_TO_GUI = false; |
| 53 private static final int TIMEOUT_SECONDS = 20; |
53 private TreeSet<String> threadsBeforeTest = null; | 54 private TreeSet<String> threadsBeforeTest = null; |
54 | 55 |
55 private static class ObserverExpectations implements PeerConnection.Observer, | 56 private static class ObserverExpectations implements PeerConnection.Observer, |
56 VideoRenderer.Callbacks, | 57 VideoRenderer.Callbacks, |
57 DataChannel.Observer, | 58 DataChannel.Observer, |
58 StatsObserver { | 59 StatsObserver { |
59 private final String name; | 60 private final String name; |
60 private int expectedIceCandidates = 0; | 61 private int expectedIceCandidates = 0; |
61 private int expectedErrors = 0; | 62 private int expectedErrors = 0; |
62 private int expectedRenegotiations = 0; | 63 private int expectedRenegotiations = 0; |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 stillWaitingForExpectations.add("expectedRemoteDataChannelLabels: " + | 341 stillWaitingForExpectations.add("expectedRemoteDataChannelLabels: " + |
341 expectedRemoteDataChannelLabels.size()); | 342 expectedRemoteDataChannelLabels.size()); |
342 } | 343 } |
343 if (expectedStatsCallbacks != 0) { | 344 if (expectedStatsCallbacks != 0) { |
344 stillWaitingForExpectations.add( | 345 stillWaitingForExpectations.add( |
345 "expectedStatsCallbacks: " + expectedStatsCallbacks); | 346 "expectedStatsCallbacks: " + expectedStatsCallbacks); |
346 } | 347 } |
347 return stillWaitingForExpectations; | 348 return stillWaitingForExpectations; |
348 } | 349 } |
349 | 350 |
350 public void waitForAllExpectationsToBeSatisfied() { | 351 public boolean waitForAllExpectationsToBeSatisfied(int timeoutSeconds) { |
351 // TODO(fischman): problems with this approach: | 352 // TODO(fischman): problems with this approach: |
352 // - come up with something better than a poll loop | 353 // - come up with something better than a poll loop |
353 // - avoid serializing expectations explicitly; the test is not as robust | 354 // - avoid serializing expectations explicitly; the test is not as robust |
354 // as it could be because it must place expectations between wait | 355 // as it could be because it must place expectations between wait |
355 // statements very precisely (e.g. frame must not arrive before its | 356 // statements very precisely (e.g. frame must not arrive before its |
356 // expectation, and expectation must not be registered so early as to | 357 // expectation, and expectation must not be registered so early as to |
357 // stall a wait). Use callbacks to fire off dependent steps instead of | 358 // stall a wait). Use callbacks to fire off dependent steps instead of |
358 // explicitly waiting, so there can be just a single wait at the end of | 359 // explicitly waiting, so there can be just a single wait at the end of |
359 // the test. | 360 // the test. |
| 361 long endTime = System.currentTimeMillis() + 1000 * timeoutSeconds; |
360 TreeSet<String> prev = null; | 362 TreeSet<String> prev = null; |
361 TreeSet<String> stillWaitingForExpectations = unsatisfiedExpectations(); | 363 TreeSet<String> stillWaitingForExpectations = unsatisfiedExpectations(); |
362 while (!stillWaitingForExpectations.isEmpty()) { | 364 while (!stillWaitingForExpectations.isEmpty()) { |
363 if (!stillWaitingForExpectations.equals(prev)) { | 365 if (!stillWaitingForExpectations.equals(prev)) { |
364 System.out.println( | 366 System.out.println( |
365 name + " still waiting at\n " + | 367 name + " still waiting at\n " + |
366 (new Throwable()).getStackTrace()[1] + | 368 (new Throwable()).getStackTrace()[1] + |
367 "\n for: " + | 369 "\n for: " + |
368 Arrays.toString(stillWaitingForExpectations.toArray())); | 370 Arrays.toString(stillWaitingForExpectations.toArray())); |
369 } | 371 } |
| 372 if (endTime < System.currentTimeMillis()) { |
| 373 System.out.println(name + " timed out waiting for: " |
| 374 + Arrays.toString(stillWaitingForExpectations.toArray())); |
| 375 return false; |
| 376 } |
370 try { | 377 try { |
371 Thread.sleep(10); | 378 Thread.sleep(10); |
372 } catch (InterruptedException e) { | 379 } catch (InterruptedException e) { |
373 throw new RuntimeException(e); | 380 throw new RuntimeException(e); |
374 } | 381 } |
375 prev = stillWaitingForExpectations; | 382 prev = stillWaitingForExpectations; |
376 stillWaitingForExpectations = unsatisfiedExpectations(); | 383 stillWaitingForExpectations = unsatisfiedExpectations(); |
377 } | 384 } |
378 if (prev == null) { | 385 if (prev == null) { |
379 System.out.println(name + " didn't need to wait at\n " + | 386 System.out.println(name + " didn't need to wait at\n " + |
380 (new Throwable()).getStackTrace()[1]); | 387 (new Throwable()).getStackTrace()[1]); |
381 } | 388 } |
| 389 return true; |
382 } | 390 } |
383 | 391 |
384 // This methods return a list of all currently gathered ice candidates or wa
its until | 392 // This methods return a list of all currently gathered ice candidates or wa
its until |
385 // 1 candidate have been gathered. | 393 // 1 candidate have been gathered. |
386 public List<IceCandidate> getAtLeastOneIceCandidate() throws InterruptedExce
ption { | 394 public List<IceCandidate> getAtLeastOneIceCandidate() throws InterruptedExce
ption { |
387 synchronized (gotIceCandidates) { | 395 synchronized (gotIceCandidates) { |
388 while (gotIceCandidates.isEmpty()) { | 396 while (gotIceCandidates.isEmpty()) { |
389 gotIceCandidates.wait(); | 397 gotIceCandidates.wait(); |
390 } | 398 } |
391 return new LinkedList<IceCandidate>(gotIceCandidates); | 399 return new LinkedList<IceCandidate>(gotIceCandidates); |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
654 for (IceCandidate candidate : offeringExpectations.getAtLeastOneIceCandidate
()) { | 662 for (IceCandidate candidate : offeringExpectations.getAtLeastOneIceCandidate
()) { |
655 answeringPC.addIceCandidate(candidate); | 663 answeringPC.addIceCandidate(candidate); |
656 } | 664 } |
657 | 665 |
658 // Wait for at least one ice candidate from the answering PC and forward the
m to the offering | 666 // Wait for at least one ice candidate from the answering PC and forward the
m to the offering |
659 // PC. | 667 // PC. |
660 for (IceCandidate candidate : answeringExpectations.getAtLeastOneIceCandidat
e()) { | 668 for (IceCandidate candidate : answeringExpectations.getAtLeastOneIceCandidat
e()) { |
661 offeringPC.addIceCandidate(candidate); | 669 offeringPC.addIceCandidate(candidate); |
662 } | 670 } |
663 | 671 |
664 offeringExpectations.waitForAllExpectationsToBeSatisfied(); | 672 assertTrue(offeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_
SECONDS)); |
665 answeringExpectations.waitForAllExpectationsToBeSatisfied(); | 673 assertTrue(answeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT
_SECONDS)); |
666 | 674 |
667 assertEquals( | 675 assertEquals( |
668 PeerConnection.SignalingState.STABLE, offeringPC.signalingState()); | 676 PeerConnection.SignalingState.STABLE, offeringPC.signalingState()); |
669 assertEquals( | 677 assertEquals( |
670 PeerConnection.SignalingState.STABLE, answeringPC.signalingState()); | 678 PeerConnection.SignalingState.STABLE, answeringPC.signalingState()); |
671 | 679 |
672 // Test send & receive UTF-8 text. | 680 // Test send & receive UTF-8 text. |
673 answeringExpectations.expectMessage( | 681 answeringExpectations.expectMessage( |
674 ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false); | 682 ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false); |
675 DataChannel.Buffer buffer = new DataChannel.Buffer( | 683 DataChannel.Buffer buffer = new DataChannel.Buffer( |
676 ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false); | 684 ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false); |
677 assertTrue(offeringExpectations.dataChannel.send(buffer)); | 685 assertTrue(offeringExpectations.dataChannel.send(buffer)); |
678 answeringExpectations.waitForAllExpectationsToBeSatisfied(); | 686 assertTrue(answeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT
_SECONDS)); |
679 | 687 |
680 // Construct this binary message two different ways to ensure no | 688 // Construct this binary message two different ways to ensure no |
681 // shortcuts are taken. | 689 // shortcuts are taken. |
682 ByteBuffer expectedBinaryMessage = ByteBuffer.allocateDirect(5); | 690 ByteBuffer expectedBinaryMessage = ByteBuffer.allocateDirect(5); |
683 for (byte i = 1; i < 6; ++i) { | 691 for (byte i = 1; i < 6; ++i) { |
684 expectedBinaryMessage.put(i); | 692 expectedBinaryMessage.put(i); |
685 } | 693 } |
686 expectedBinaryMessage.flip(); | 694 expectedBinaryMessage.flip(); |
687 offeringExpectations.expectMessage(expectedBinaryMessage, true); | 695 offeringExpectations.expectMessage(expectedBinaryMessage, true); |
688 assertTrue(answeringExpectations.dataChannel.send( | 696 assertTrue(answeringExpectations.dataChannel.send( |
689 new DataChannel.Buffer( | 697 new DataChannel.Buffer( |
690 ByteBuffer.wrap(new byte[] { 1, 2, 3, 4, 5 }), true))); | 698 ByteBuffer.wrap(new byte[] { 1, 2, 3, 4, 5 }), true))); |
691 offeringExpectations.waitForAllExpectationsToBeSatisfied(); | 699 assertTrue(offeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_
SECONDS)); |
692 | 700 |
693 offeringExpectations.expectStateChange(DataChannel.State.CLOSING); | 701 offeringExpectations.expectStateChange(DataChannel.State.CLOSING); |
694 answeringExpectations.expectStateChange(DataChannel.State.CLOSING); | 702 answeringExpectations.expectStateChange(DataChannel.State.CLOSING); |
695 offeringExpectations.expectStateChange(DataChannel.State.CLOSED); | 703 offeringExpectations.expectStateChange(DataChannel.State.CLOSED); |
696 answeringExpectations.expectStateChange(DataChannel.State.CLOSED); | 704 answeringExpectations.expectStateChange(DataChannel.State.CLOSED); |
697 answeringExpectations.dataChannel.close(); | 705 answeringExpectations.dataChannel.close(); |
698 offeringExpectations.dataChannel.close(); | 706 offeringExpectations.dataChannel.close(); |
699 | 707 |
700 if (RENDER_TO_GUI) { | 708 if (RENDER_TO_GUI) { |
701 try { | 709 try { |
(...skipping 25 matching lines...) Expand all Loading... |
727 factory.dispose(); | 735 factory.dispose(); |
728 System.gc(); | 736 System.gc(); |
729 } | 737 } |
730 | 738 |
731 private static void shutdownPC( | 739 private static void shutdownPC( |
732 PeerConnection pc, ObserverExpectations expectations) { | 740 PeerConnection pc, ObserverExpectations expectations) { |
733 expectations.dataChannel.unregisterObserver(); | 741 expectations.dataChannel.unregisterObserver(); |
734 expectations.dataChannel.dispose(); | 742 expectations.dataChannel.dispose(); |
735 expectations.expectStatsCallback(); | 743 expectations.expectStatsCallback(); |
736 assertTrue(pc.getStats(expectations, null)); | 744 assertTrue(pc.getStats(expectations, null)); |
737 expectations.waitForAllExpectationsToBeSatisfied(); | 745 assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS)
); |
738 expectations.expectIceConnectionChange(IceConnectionState.CLOSED); | 746 expectations.expectIceConnectionChange(IceConnectionState.CLOSED); |
739 expectations.expectSignalingChange(SignalingState.CLOSED); | 747 expectations.expectSignalingChange(SignalingState.CLOSED); |
740 pc.close(); | 748 pc.close(); |
741 expectations.waitForAllExpectationsToBeSatisfied(); | 749 assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS)
); |
742 expectations.expectStatsCallback(); | 750 expectations.expectStatsCallback(); |
743 assertTrue(pc.getStats(expectations, null)); | 751 assertTrue(pc.getStats(expectations, null)); |
744 expectations.waitForAllExpectationsToBeSatisfied(); | 752 assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS)
); |
745 | 753 |
746 System.out.println("FYI stats: "); | 754 System.out.println("FYI stats: "); |
747 int reportIndex = -1; | 755 int reportIndex = -1; |
748 for (StatsReport[] reports : expectations.takeStatsReports()) { | 756 for (StatsReport[] reports : expectations.takeStatsReports()) { |
749 System.out.println(" Report #" + (++reportIndex)); | 757 System.out.println(" Report #" + (++reportIndex)); |
750 for (int i = 0; i < reports.length; ++i) { | 758 for (int i = 0; i < reports.length; ++i) { |
751 System.out.println(" " + reports[i].toString()); | 759 System.out.println(" " + reports[i].toString()); |
752 } | 760 } |
753 } | 761 } |
754 assertEquals(1, reportIndex); | 762 assertEquals(1, reportIndex); |
755 System.out.println("End stats."); | 763 System.out.println("End stats."); |
756 | 764 |
757 pc.dispose(); | 765 pc.dispose(); |
758 } | 766 } |
759 | 767 |
760 // Returns a set of thread IDs belonging to this process, as Strings. | 768 // Returns a set of thread IDs belonging to this process, as Strings. |
761 private static TreeSet<String> allThreads() { | 769 private static TreeSet<String> allThreads() { |
762 TreeSet<String> threads = new TreeSet<String>(); | 770 TreeSet<String> threads = new TreeSet<String>(); |
763 // This pokes at /proc instead of using the Java APIs because we're also | 771 // This pokes at /proc instead of using the Java APIs because we're also |
764 // looking for libjingle/webrtc native threads, most of which won't have | 772 // looking for libjingle/webrtc native threads, most of which won't have |
765 // attached to the JVM. | 773 // attached to the JVM. |
766 for (String threadId : (new File("/proc/self/task")).list()) { | 774 for (String threadId : (new File("/proc/self/task")).list()) { |
767 threads.add(threadId); | 775 threads.add(threadId); |
768 } | 776 } |
769 return threads; | 777 return threads; |
770 } | 778 } |
771 } | 779 } |
OLD | NEW |