mirror of
https://github.com/pion/ice.git
synced 2025-09-27 03:45:54 +08:00
299 lines
8.6 KiB
Go
299 lines
8.6 KiB
Go
// SPDX-FileCopyrightText: 2025 The Pion community <https://pion.ly>
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package ice
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/pion/stun/v3"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// testBooleanOption is a helper function to test boolean agent options.
|
|
type booleanOptionTest struct {
|
|
optionFunc func() AgentOption
|
|
getValue func(*Agent) bool
|
|
configSetter func(*AgentConfig, bool)
|
|
}
|
|
|
|
func testBooleanOption(t *testing.T, test booleanOptionTest, optionName string) {
|
|
t.Helper()
|
|
|
|
t.Run("enables "+optionName, func(t *testing.T) {
|
|
agent, err := NewAgentWithOptions(test.optionFunc())
|
|
assert.NoError(t, err)
|
|
defer agent.Close() //nolint:errcheck
|
|
|
|
assert.True(t, test.getValue(agent))
|
|
})
|
|
|
|
t.Run("default is false", func(t *testing.T) {
|
|
agent, err := NewAgentWithOptions()
|
|
assert.NoError(t, err)
|
|
defer agent.Close() //nolint:errcheck
|
|
|
|
assert.False(t, test.getValue(agent))
|
|
})
|
|
|
|
t.Run("works with config", func(t *testing.T) {
|
|
config := &AgentConfig{
|
|
NetworkTypes: []NetworkType{NetworkTypeUDP4},
|
|
}
|
|
test.configSetter(config, true)
|
|
|
|
agent, err := NewAgent(config)
|
|
assert.NoError(t, err)
|
|
defer agent.Close() //nolint:errcheck
|
|
|
|
assert.True(t, test.getValue(agent))
|
|
})
|
|
}
|
|
|
|
func TestDefaultNominationValueGenerator(t *testing.T) {
|
|
t.Run("generates incrementing values", func(t *testing.T) {
|
|
generator := DefaultNominationValueGenerator()
|
|
|
|
// Should generate incrementing values starting from 1
|
|
assert.Equal(t, uint32(1), generator())
|
|
assert.Equal(t, uint32(2), generator())
|
|
assert.Equal(t, uint32(3), generator())
|
|
})
|
|
|
|
t.Run("each generator has independent counter", func(t *testing.T) {
|
|
gen1 := DefaultNominationValueGenerator()
|
|
gen2 := DefaultNominationValueGenerator()
|
|
|
|
assert.Equal(t, uint32(1), gen1())
|
|
assert.Equal(t, uint32(1), gen2()) // Should also start at 1
|
|
assert.Equal(t, uint32(2), gen1())
|
|
assert.Equal(t, uint32(2), gen2())
|
|
})
|
|
}
|
|
|
|
func TestWithRenomination(t *testing.T) {
|
|
t.Run("enables renomination with custom generator", func(t *testing.T) {
|
|
counter := uint32(0)
|
|
customGen := func() uint32 {
|
|
counter++
|
|
|
|
return counter * 10
|
|
}
|
|
|
|
agent, err := NewAgentWithOptions(WithRenomination(customGen))
|
|
assert.NoError(t, err)
|
|
defer agent.Close() //nolint:errcheck
|
|
|
|
assert.True(t, agent.enableRenomination)
|
|
assert.NotNil(t, agent.nominationValueGenerator)
|
|
assert.Equal(t, uint32(10), agent.getNominationValue())
|
|
assert.Equal(t, uint32(20), agent.getNominationValue())
|
|
})
|
|
|
|
t.Run("enables renomination with default generator", func(t *testing.T) {
|
|
agent, err := NewAgentWithOptions(WithRenomination(DefaultNominationValueGenerator()))
|
|
assert.NoError(t, err)
|
|
defer agent.Close() //nolint:errcheck
|
|
|
|
assert.True(t, agent.enableRenomination)
|
|
assert.NotNil(t, agent.nominationValueGenerator)
|
|
assert.Equal(t, uint32(1), agent.getNominationValue())
|
|
assert.Equal(t, uint32(2), agent.getNominationValue())
|
|
})
|
|
|
|
t.Run("rejects nil generator", func(t *testing.T) {
|
|
_, err := NewAgentWithOptions(WithRenomination(nil))
|
|
assert.ErrorIs(t, err, ErrInvalidNominationValueGenerator)
|
|
})
|
|
|
|
t.Run("default agent has renomination disabled", func(t *testing.T) {
|
|
config := &AgentConfig{
|
|
NetworkTypes: []NetworkType{NetworkTypeUDP4},
|
|
}
|
|
|
|
agent, err := NewAgent(config)
|
|
assert.NoError(t, err)
|
|
defer agent.Close() //nolint:errcheck
|
|
|
|
assert.False(t, agent.enableRenomination)
|
|
assert.Nil(t, agent.nominationValueGenerator)
|
|
assert.Equal(t, uint32(0), agent.getNominationValue())
|
|
})
|
|
}
|
|
|
|
func TestWithNominationAttribute(t *testing.T) {
|
|
t.Run("sets custom nomination attribute", func(t *testing.T) {
|
|
agent, err := NewAgentWithOptions(WithNominationAttribute(0x0045))
|
|
assert.NoError(t, err)
|
|
defer agent.Close() //nolint:errcheck
|
|
|
|
assert.Equal(t, stun.AttrType(0x0045), agent.nominationAttribute)
|
|
})
|
|
|
|
t.Run("rejects invalid attribute 0x0000", func(t *testing.T) {
|
|
_, err := NewAgentWithOptions(WithNominationAttribute(0x0000))
|
|
assert.ErrorIs(t, err, ErrInvalidNominationAttribute)
|
|
})
|
|
|
|
t.Run("default value when no option", func(t *testing.T) {
|
|
config := &AgentConfig{
|
|
NetworkTypes: []NetworkType{NetworkTypeUDP4},
|
|
}
|
|
|
|
agent, err := NewAgent(config)
|
|
assert.NoError(t, err)
|
|
defer agent.Close() //nolint:errcheck
|
|
|
|
// Should use default value 0x0030
|
|
assert.Equal(t, stun.AttrType(0x0030), agent.nominationAttribute)
|
|
})
|
|
}
|
|
|
|
func TestWithIncludeLoopback(t *testing.T) {
|
|
testBooleanOption(t, booleanOptionTest{
|
|
optionFunc: WithIncludeLoopback,
|
|
getValue: func(a *Agent) bool { return a.includeLoopback },
|
|
configSetter: func(c *AgentConfig, v bool) { c.IncludeLoopback = v },
|
|
}, "loopback addresses")
|
|
}
|
|
|
|
func TestWithTCPPriorityOffset(t *testing.T) {
|
|
t.Run("sets custom TCP priority offset", func(t *testing.T) {
|
|
customOffset := uint16(50)
|
|
agent, err := NewAgentWithOptions(WithTCPPriorityOffset(customOffset))
|
|
assert.NoError(t, err)
|
|
defer agent.Close() //nolint:errcheck
|
|
|
|
assert.Equal(t, customOffset, agent.tcpPriorityOffset)
|
|
})
|
|
|
|
t.Run("default is 27", func(t *testing.T) {
|
|
agent, err := NewAgentWithOptions()
|
|
assert.NoError(t, err)
|
|
defer agent.Close() //nolint:errcheck
|
|
|
|
// The default is set via initWithDefaults
|
|
assert.Equal(t, uint16(27), agent.tcpPriorityOffset)
|
|
})
|
|
|
|
t.Run("works with config", func(t *testing.T) {
|
|
customOffset := uint16(100)
|
|
config := &AgentConfig{
|
|
NetworkTypes: []NetworkType{NetworkTypeUDP4},
|
|
TCPPriorityOffset: &customOffset,
|
|
}
|
|
|
|
agent, err := NewAgent(config)
|
|
assert.NoError(t, err)
|
|
defer agent.Close() //nolint:errcheck
|
|
|
|
assert.Equal(t, customOffset, agent.tcpPriorityOffset)
|
|
})
|
|
}
|
|
|
|
func TestWithDisableActiveTCP(t *testing.T) {
|
|
testBooleanOption(t, booleanOptionTest{
|
|
optionFunc: WithDisableActiveTCP,
|
|
getValue: func(a *Agent) bool { return a.disableActiveTCP },
|
|
configSetter: func(c *AgentConfig, v bool) { c.DisableActiveTCP = v },
|
|
}, "active TCP disabling")
|
|
}
|
|
|
|
func TestWithBindingRequestHandler(t *testing.T) {
|
|
t.Run("sets binding request handler", func(t *testing.T) {
|
|
handlerCalled := false
|
|
handler := func(m *stun.Message, local, remote Candidate, pair *CandidatePair) bool {
|
|
handlerCalled = true
|
|
|
|
return true
|
|
}
|
|
|
|
agent, err := NewAgentWithOptions(WithBindingRequestHandler(handler))
|
|
assert.NoError(t, err)
|
|
defer agent.Close() //nolint:errcheck
|
|
|
|
assert.NotNil(t, agent.userBindingRequestHandler)
|
|
|
|
// Test that the handler is actually the one we set
|
|
// We can't directly compare functions, but we can call it
|
|
if agent.userBindingRequestHandler != nil {
|
|
agent.userBindingRequestHandler(nil, nil, nil, nil)
|
|
assert.True(t, handlerCalled)
|
|
}
|
|
})
|
|
|
|
t.Run("default is nil", func(t *testing.T) {
|
|
agent, err := NewAgentWithOptions()
|
|
assert.NoError(t, err)
|
|
defer agent.Close() //nolint:errcheck
|
|
|
|
assert.Nil(t, agent.userBindingRequestHandler)
|
|
})
|
|
|
|
t.Run("works with config", func(t *testing.T) {
|
|
handlerCalled := false
|
|
handler := func(m *stun.Message, local, remote Candidate, pair *CandidatePair) bool {
|
|
handlerCalled = true
|
|
|
|
return true
|
|
}
|
|
|
|
config := &AgentConfig{
|
|
NetworkTypes: []NetworkType{NetworkTypeUDP4},
|
|
BindingRequestHandler: handler,
|
|
}
|
|
|
|
agent, err := NewAgent(config)
|
|
assert.NoError(t, err)
|
|
defer agent.Close() //nolint:errcheck
|
|
|
|
assert.NotNil(t, agent.userBindingRequestHandler)
|
|
|
|
if agent.userBindingRequestHandler != nil {
|
|
agent.userBindingRequestHandler(nil, nil, nil, nil)
|
|
assert.True(t, handlerCalled)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestWithEnableUseCandidateCheckPriority(t *testing.T) {
|
|
testBooleanOption(t, booleanOptionTest{
|
|
optionFunc: WithEnableUseCandidateCheckPriority,
|
|
getValue: func(a *Agent) bool { return a.enableUseCandidateCheckPriority },
|
|
configSetter: func(c *AgentConfig, v bool) { c.EnableUseCandidateCheckPriority = v },
|
|
}, "use candidate check priority")
|
|
}
|
|
|
|
func TestMultipleConfigOptions(t *testing.T) {
|
|
t.Run("can apply multiple options", func(t *testing.T) {
|
|
customOffset := uint16(100)
|
|
handlerCalled := false
|
|
handler := func(m *stun.Message, local, remote Candidate, pair *CandidatePair) bool {
|
|
handlerCalled = true
|
|
|
|
return true
|
|
}
|
|
|
|
agent, err := NewAgentWithOptions(
|
|
WithIncludeLoopback(),
|
|
WithTCPPriorityOffset(customOffset),
|
|
WithDisableActiveTCP(),
|
|
WithBindingRequestHandler(handler),
|
|
WithEnableUseCandidateCheckPriority(),
|
|
)
|
|
assert.NoError(t, err)
|
|
defer agent.Close() //nolint:errcheck
|
|
|
|
assert.True(t, agent.includeLoopback)
|
|
assert.Equal(t, customOffset, agent.tcpPriorityOffset)
|
|
assert.True(t, agent.disableActiveTCP)
|
|
assert.NotNil(t, agent.userBindingRequestHandler)
|
|
assert.True(t, agent.enableUseCandidateCheckPriority)
|
|
|
|
if agent.userBindingRequestHandler != nil {
|
|
agent.userBindingRequestHandler(nil, nil, nil, nil)
|
|
assert.True(t, handlerCalled)
|
|
}
|
|
})
|
|
}
|