// +build !js package webrtc import ( "testing" "time" "github.com/pion/transport/test" "github.com/stretchr/testify/assert" ) func TestPeerConnection_Close(t *testing.T) { // Limit runtime in case of deadlocks lim := test.TimeOut(time.Second * 20) defer lim.Stop() report := test.CheckRoutines(t) defer report() pcOffer, pcAnswer, err := newPair() if err != nil { t.Fatal(err) } awaitSetup := make(chan struct{}) pcAnswer.OnDataChannel(func(d *DataChannel) { // Make sure this is the data channel we were looking for. (Not the one // created in signalPair). if d.Label() != "data" { return } close(awaitSetup) }) awaitICEClosed := make(chan struct{}) pcAnswer.OnICEConnectionStateChange(func(i ICEConnectionState) { if i == ICEConnectionStateClosed { close(awaitICEClosed) } }) _, err = pcOffer.CreateDataChannel("data", nil) if err != nil { t.Fatal(err) } err = signalPair(pcOffer, pcAnswer) if err != nil { t.Fatal(err) } <-awaitSetup assert.NoError(t, pcOffer.Close()) assert.NoError(t, pcAnswer.Close()) <-awaitICEClosed } // Assert that a PeerConnection that is shutdown before ICE starts doesn't leak func TestPeerConnection_Close_PreICE(t *testing.T) { // Limit runtime in case of deadlocks lim := test.TimeOut(time.Second * 30) defer lim.Stop() report := test.CheckRoutines(t) defer report() pcOffer, pcAnswer, err := newPair() if err != nil { t.Fatal(err) } answer, err := pcOffer.CreateOffer(nil) if err != nil { t.Fatal(err) } assert.NoError(t, pcOffer.Close()) if err = pcAnswer.SetRemoteDescription(answer); err != nil { t.Fatal(err) } for { if pcAnswer.iceTransport.State() == ICETransportStateChecking { break } time.Sleep(time.Second) } assert.NoError(t, pcAnswer.Close()) // Assert that ICETransport is shutdown, test timeout will prevent deadlock for { if pcAnswer.iceTransport.State() == ICETransportStateClosed { time.Sleep(time.Second * 3) return } time.Sleep(time.Second) } } func TestPeerConnection_Close_DuringICE(t *testing.T) { // Limit runtime in case of deadlocks lim := test.TimeOut(time.Second * 30) defer lim.Stop() report := test.CheckRoutines(t) defer report() pcOffer, pcAnswer, err := newPair() if err != nil { t.Fatal(err) } closedOffer := make(chan struct{}) closedAnswer := make(chan struct{}) pcAnswer.OnICEConnectionStateChange(func(iceState ICEConnectionState) { if iceState == ICEConnectionStateConnected { go func() { if err2 := pcAnswer.Close(); err2 != nil { t.Errorf("pcAnswer.Close() failed: %v", err2) } close(closedAnswer) if err2 := pcOffer.Close(); err2 != nil { t.Errorf("pcOffer.Close() failed: %v", err2) } close(closedOffer) }() } }) offer, err := pcOffer.CreateOffer(nil) if err != nil { t.Fatal(err) } if err = pcOffer.SetLocalDescription(offer); err != nil { t.Fatal(err) } if err = pcAnswer.SetRemoteDescription(offer); err != nil { t.Fatal(err) } answer, err := pcAnswer.CreateAnswer(nil) if err != nil { t.Fatal(err) } if err = pcAnswer.SetLocalDescription(answer); err != nil { t.Fatal(err) } if err = pcOffer.SetRemoteDescription(answer); err != nil { t.Fatal(err) } select { case <-closedAnswer: case <-time.After(5 * time.Second): t.Error("pcAnswer.Close() Timeout") } select { case <-closedOffer: case <-time.After(5 * time.Second): t.Error("pcOffer.Close() Timeout") } }