peerconnection_close_test.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. //go:build !js
  4. // +build !js
  5. package webrtc
  6. import (
  7. "testing"
  8. "time"
  9. "github.com/pion/transport/v2/test"
  10. "github.com/stretchr/testify/assert"
  11. )
  12. func TestPeerConnection_Close(t *testing.T) {
  13. // Limit runtime in case of deadlocks
  14. lim := test.TimeOut(time.Second * 20)
  15. defer lim.Stop()
  16. report := test.CheckRoutines(t)
  17. defer report()
  18. pcOffer, pcAnswer, err := newPair()
  19. if err != nil {
  20. t.Fatal(err)
  21. }
  22. awaitSetup := make(chan struct{})
  23. pcAnswer.OnDataChannel(func(d *DataChannel) {
  24. // Make sure this is the data channel we were looking for. (Not the one
  25. // created in signalPair).
  26. if d.Label() != "data" {
  27. return
  28. }
  29. close(awaitSetup)
  30. })
  31. awaitICEClosed := make(chan struct{})
  32. pcAnswer.OnICEConnectionStateChange(func(i ICEConnectionState) {
  33. if i == ICEConnectionStateClosed {
  34. close(awaitICEClosed)
  35. }
  36. })
  37. _, err = pcOffer.CreateDataChannel("data", nil)
  38. if err != nil {
  39. t.Fatal(err)
  40. }
  41. err = signalPair(pcOffer, pcAnswer)
  42. if err != nil {
  43. t.Fatal(err)
  44. }
  45. <-awaitSetup
  46. closePairNow(t, pcOffer, pcAnswer)
  47. <-awaitICEClosed
  48. }
  49. // Assert that a PeerConnection that is shutdown before ICE starts doesn't leak
  50. func TestPeerConnection_Close_PreICE(t *testing.T) {
  51. // Limit runtime in case of deadlocks
  52. lim := test.TimeOut(time.Second * 30)
  53. defer lim.Stop()
  54. report := test.CheckRoutines(t)
  55. defer report()
  56. pcOffer, pcAnswer, err := newPair()
  57. if err != nil {
  58. t.Fatal(err)
  59. }
  60. _, err = pcOffer.CreateDataChannel("test-channel", nil)
  61. if err != nil {
  62. t.Fatal(err)
  63. }
  64. answer, err := pcOffer.CreateOffer(nil)
  65. if err != nil {
  66. t.Fatal(err)
  67. }
  68. assert.NoError(t, pcOffer.Close())
  69. if err = pcAnswer.SetRemoteDescription(answer); err != nil {
  70. t.Fatal(err)
  71. }
  72. for {
  73. if pcAnswer.iceTransport.State() == ICETransportStateChecking {
  74. break
  75. }
  76. time.Sleep(time.Second / 4)
  77. }
  78. assert.NoError(t, pcAnswer.Close())
  79. // Assert that ICETransport is shutdown, test timeout will prevent deadlock
  80. for {
  81. if pcAnswer.iceTransport.State() == ICETransportStateClosed {
  82. return
  83. }
  84. time.Sleep(time.Second / 4)
  85. }
  86. }
  87. func TestPeerConnection_Close_DuringICE(t *testing.T) {
  88. // Limit runtime in case of deadlocks
  89. lim := test.TimeOut(time.Second * 30)
  90. defer lim.Stop()
  91. report := test.CheckRoutines(t)
  92. defer report()
  93. pcOffer, pcAnswer, err := newPair()
  94. if err != nil {
  95. t.Fatal(err)
  96. }
  97. closedOffer := make(chan struct{})
  98. closedAnswer := make(chan struct{})
  99. pcAnswer.OnICEConnectionStateChange(func(iceState ICEConnectionState) {
  100. if iceState == ICEConnectionStateConnected {
  101. go func() {
  102. assert.NoError(t, pcAnswer.Close())
  103. close(closedAnswer)
  104. assert.NoError(t, pcOffer.Close())
  105. close(closedOffer)
  106. }()
  107. }
  108. })
  109. _, err = pcOffer.CreateDataChannel("test-channel", nil)
  110. if err != nil {
  111. t.Fatal(err)
  112. }
  113. offer, err := pcOffer.CreateOffer(nil)
  114. if err != nil {
  115. t.Fatal(err)
  116. }
  117. offerGatheringComplete := GatheringCompletePromise(pcOffer)
  118. if err = pcOffer.SetLocalDescription(offer); err != nil {
  119. t.Fatal(err)
  120. }
  121. <-offerGatheringComplete
  122. if err = pcAnswer.SetRemoteDescription(*pcOffer.LocalDescription()); err != nil {
  123. t.Fatal(err)
  124. }
  125. answer, err := pcAnswer.CreateAnswer(nil)
  126. if err != nil {
  127. t.Fatal(err)
  128. }
  129. answerGatheringComplete := GatheringCompletePromise(pcAnswer)
  130. if err = pcAnswer.SetLocalDescription(answer); err != nil {
  131. t.Fatal(err)
  132. }
  133. <-answerGatheringComplete
  134. if err = pcOffer.SetRemoteDescription(*pcAnswer.LocalDescription()); err != nil {
  135. t.Fatal(err)
  136. }
  137. select {
  138. case <-closedAnswer:
  139. case <-time.After(5 * time.Second):
  140. t.Error("pcAnswer.Close() Timeout")
  141. }
  142. select {
  143. case <-closedOffer:
  144. case <-time.After(5 * time.Second):
  145. t.Error("pcOffer.Close() Timeout")
  146. }
  147. }