github.com/pion/webrtc/v3@v3.2.24/peerconnection_close_test.go (about)

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