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 at\n " | |
374 + (new Throwable()).getStackTrace()[1] + "\n for: " | |
AlexG
2015/09/25 18:49:25
Why "[1]" here? May be use Throwable.printStackTra
Taylor Brandstetter
2015/09/25 19:44:03
I assume because waitForAllExpectationsToBeSatisfi
| |
375 + Arrays.toString(stillWaitingForExpectations.toArray())); | |
376 return false; | |
377 } | |
370 try { | 378 try { |
371 Thread.sleep(10); | 379 Thread.sleep(10); |
372 } catch (InterruptedException e) { | 380 } catch (InterruptedException e) { |
373 throw new RuntimeException(e); | 381 throw new RuntimeException(e); |
374 } | 382 } |
375 prev = stillWaitingForExpectations; | 383 prev = stillWaitingForExpectations; |
376 stillWaitingForExpectations = unsatisfiedExpectations(); | 384 stillWaitingForExpectations = unsatisfiedExpectations(); |
377 } | 385 } |
378 if (prev == null) { | 386 if (prev == null) { |
379 System.out.println(name + " didn't need to wait at\n " + | 387 System.out.println(name + " didn't need to wait at\n " + |
380 (new Throwable()).getStackTrace()[1]); | 388 (new Throwable()).getStackTrace()[1]); |
381 } | 389 } |
390 return true; | |
382 } | 391 } |
383 | 392 |
384 // This methods return a list of all currently gathered ice candidates or wa its until | 393 // This methods return a list of all currently gathered ice candidates or wa its until |
385 // 1 candidate have been gathered. | 394 // 1 candidate have been gathered. |
386 public List<IceCandidate> getAtLeastOneIceCandidate() throws InterruptedExce ption { | 395 public List<IceCandidate> getAtLeastOneIceCandidate() throws InterruptedExce ption { |
387 synchronized (gotIceCandidates) { | 396 synchronized (gotIceCandidates) { |
388 while (gotIceCandidates.isEmpty()) { | 397 while (gotIceCandidates.isEmpty()) { |
389 gotIceCandidates.wait(); | 398 gotIceCandidates.wait(); |
390 } | 399 } |
391 return new LinkedList<IceCandidate>(gotIceCandidates); | 400 return new LinkedList<IceCandidate>(gotIceCandidates); |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
654 for (IceCandidate candidate : offeringExpectations.getAtLeastOneIceCandidate ()) { | 663 for (IceCandidate candidate : offeringExpectations.getAtLeastOneIceCandidate ()) { |
655 answeringPC.addIceCandidate(candidate); | 664 answeringPC.addIceCandidate(candidate); |
656 } | 665 } |
657 | 666 |
658 // Wait for at least one ice candidate from the answering PC and forward the m to the offering | 667 // Wait for at least one ice candidate from the answering PC and forward the m to the offering |
659 // PC. | 668 // PC. |
660 for (IceCandidate candidate : answeringExpectations.getAtLeastOneIceCandidat e()) { | 669 for (IceCandidate candidate : answeringExpectations.getAtLeastOneIceCandidat e()) { |
661 offeringPC.addIceCandidate(candidate); | 670 offeringPC.addIceCandidate(candidate); |
662 } | 671 } |
663 | 672 |
664 offeringExpectations.waitForAllExpectationsToBeSatisfied(); | 673 assertTrue(offeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_ SECONDS)); |
665 answeringExpectations.waitForAllExpectationsToBeSatisfied(); | 674 assertTrue(answeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT _SECONDS)); |
666 | 675 |
667 assertEquals( | 676 assertEquals( |
668 PeerConnection.SignalingState.STABLE, offeringPC.signalingState()); | 677 PeerConnection.SignalingState.STABLE, offeringPC.signalingState()); |
669 assertEquals( | 678 assertEquals( |
670 PeerConnection.SignalingState.STABLE, answeringPC.signalingState()); | 679 PeerConnection.SignalingState.STABLE, answeringPC.signalingState()); |
671 | 680 |
672 // Test send & receive UTF-8 text. | 681 // Test send & receive UTF-8 text. |
673 answeringExpectations.expectMessage( | 682 answeringExpectations.expectMessage( |
674 ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false); | 683 ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false); |
675 DataChannel.Buffer buffer = new DataChannel.Buffer( | 684 DataChannel.Buffer buffer = new DataChannel.Buffer( |
676 ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false); | 685 ByteBuffer.wrap("hello!".getBytes(Charset.forName("UTF-8"))), false); |
677 assertTrue(offeringExpectations.dataChannel.send(buffer)); | 686 assertTrue(offeringExpectations.dataChannel.send(buffer)); |
678 answeringExpectations.waitForAllExpectationsToBeSatisfied(); | 687 assertTrue(answeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT _SECONDS)); |
679 | 688 |
680 // Construct this binary message two different ways to ensure no | 689 // Construct this binary message two different ways to ensure no |
681 // shortcuts are taken. | 690 // shortcuts are taken. |
682 ByteBuffer expectedBinaryMessage = ByteBuffer.allocateDirect(5); | 691 ByteBuffer expectedBinaryMessage = ByteBuffer.allocateDirect(5); |
683 for (byte i = 1; i < 6; ++i) { | 692 for (byte i = 1; i < 6; ++i) { |
684 expectedBinaryMessage.put(i); | 693 expectedBinaryMessage.put(i); |
685 } | 694 } |
686 expectedBinaryMessage.flip(); | 695 expectedBinaryMessage.flip(); |
687 offeringExpectations.expectMessage(expectedBinaryMessage, true); | 696 offeringExpectations.expectMessage(expectedBinaryMessage, true); |
688 assertTrue(answeringExpectations.dataChannel.send( | 697 assertTrue(answeringExpectations.dataChannel.send( |
689 new DataChannel.Buffer( | 698 new DataChannel.Buffer( |
690 ByteBuffer.wrap(new byte[] { 1, 2, 3, 4, 5 }), true))); | 699 ByteBuffer.wrap(new byte[] { 1, 2, 3, 4, 5 }), true))); |
691 offeringExpectations.waitForAllExpectationsToBeSatisfied(); | 700 assertTrue(offeringExpectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_ SECONDS)); |
692 | 701 |
693 offeringExpectations.expectStateChange(DataChannel.State.CLOSING); | 702 offeringExpectations.expectStateChange(DataChannel.State.CLOSING); |
694 answeringExpectations.expectStateChange(DataChannel.State.CLOSING); | 703 answeringExpectations.expectStateChange(DataChannel.State.CLOSING); |
695 offeringExpectations.expectStateChange(DataChannel.State.CLOSED); | 704 offeringExpectations.expectStateChange(DataChannel.State.CLOSED); |
696 answeringExpectations.expectStateChange(DataChannel.State.CLOSED); | 705 answeringExpectations.expectStateChange(DataChannel.State.CLOSED); |
697 answeringExpectations.dataChannel.close(); | 706 answeringExpectations.dataChannel.close(); |
698 offeringExpectations.dataChannel.close(); | 707 offeringExpectations.dataChannel.close(); |
699 | 708 |
700 if (RENDER_TO_GUI) { | 709 if (RENDER_TO_GUI) { |
701 try { | 710 try { |
(...skipping 25 matching lines...) Expand all Loading... | |
727 factory.dispose(); | 736 factory.dispose(); |
728 System.gc(); | 737 System.gc(); |
729 } | 738 } |
730 | 739 |
731 private static void shutdownPC( | 740 private static void shutdownPC( |
732 PeerConnection pc, ObserverExpectations expectations) { | 741 PeerConnection pc, ObserverExpectations expectations) { |
733 expectations.dataChannel.unregisterObserver(); | 742 expectations.dataChannel.unregisterObserver(); |
734 expectations.dataChannel.dispose(); | 743 expectations.dataChannel.dispose(); |
735 expectations.expectStatsCallback(); | 744 expectations.expectStatsCallback(); |
736 assertTrue(pc.getStats(expectations, null)); | 745 assertTrue(pc.getStats(expectations, null)); |
737 expectations.waitForAllExpectationsToBeSatisfied(); | 746 assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS) ); |
738 expectations.expectIceConnectionChange(IceConnectionState.CLOSED); | 747 expectations.expectIceConnectionChange(IceConnectionState.CLOSED); |
739 expectations.expectSignalingChange(SignalingState.CLOSED); | 748 expectations.expectSignalingChange(SignalingState.CLOSED); |
740 pc.close(); | 749 pc.close(); |
741 expectations.waitForAllExpectationsToBeSatisfied(); | 750 assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS) ); |
742 expectations.expectStatsCallback(); | 751 expectations.expectStatsCallback(); |
743 assertTrue(pc.getStats(expectations, null)); | 752 assertTrue(pc.getStats(expectations, null)); |
744 expectations.waitForAllExpectationsToBeSatisfied(); | 753 assertTrue(expectations.waitForAllExpectationsToBeSatisfied(TIMEOUT_SECONDS) ); |
745 | 754 |
746 System.out.println("FYI stats: "); | 755 System.out.println("FYI stats: "); |
747 int reportIndex = -1; | 756 int reportIndex = -1; |
748 for (StatsReport[] reports : expectations.takeStatsReports()) { | 757 for (StatsReport[] reports : expectations.takeStatsReports()) { |
749 System.out.println(" Report #" + (++reportIndex)); | 758 System.out.println(" Report #" + (++reportIndex)); |
750 for (int i = 0; i < reports.length; ++i) { | 759 for (int i = 0; i < reports.length; ++i) { |
751 System.out.println(" " + reports[i].toString()); | 760 System.out.println(" " + reports[i].toString()); |
752 } | 761 } |
753 } | 762 } |
754 assertEquals(1, reportIndex); | 763 assertEquals(1, reportIndex); |
755 System.out.println("End stats."); | 764 System.out.println("End stats."); |
756 | 765 |
757 pc.dispose(); | 766 pc.dispose(); |
758 } | 767 } |
759 | 768 |
760 // Returns a set of thread IDs belonging to this process, as Strings. | 769 // Returns a set of thread IDs belonging to this process, as Strings. |
761 private static TreeSet<String> allThreads() { | 770 private static TreeSet<String> allThreads() { |
762 TreeSet<String> threads = new TreeSet<String>(); | 771 TreeSet<String> threads = new TreeSet<String>(); |
763 // This pokes at /proc instead of using the Java APIs because we're also | 772 // 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 | 773 // looking for libjingle/webrtc native threads, most of which won't have |
765 // attached to the JVM. | 774 // attached to the JVM. |
766 for (String threadId : (new File("/proc/self/task")).list()) { | 775 for (String threadId : (new File("/proc/self/task")).list()) { |
767 threads.add(threadId); | 776 threads.add(threadId); |
768 } | 777 } |
769 return threads; | 778 return threads; |
770 } | 779 } |
771 } | 780 } |
OLD | NEW |