Repository: pion/turn
Pull request #58 (2019-06-25 02:14:18)

Refactor allocation lefetimeTimer handle function
Add Manager close and Allocation timeout unit test.

codecov-io: # [Codecov](https://codecov.io/gh/pion/turn/pull/58?src=pr&el=h1) Report
> Merging [#58](https://codecov.io/gh/pion/turn/pull/58?src=pr&el=desc) into [master](https://codecov.io/gh/pion/turn/commit/b21ddc24339e4464053bb8aac0864cc291bb93ab?src=pr&el=desc) will **increase** coverage by `5.03%`.
> The diff coverage is `0%`.

[![Impacted file tree graph](https://codecov.io/gh/pion/turn/pull/58/graphs/tree.svg?width=650&token=1UomjQ7lwC&height=150&src=pr)](https://codecov.io/gh/pion/turn/pull/58?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master      #58      +/-   ##
==========================================
+ Coverage   18.51%   23.55%   +5.03%     
==========================================
  Files          16       16              
  Lines         675      675              
==========================================
+ Hits          125      159      +34     
+ Misses        526      490      -36     
- Partials       24       26       +2
```


| [Impacted Files](https://codecov.io/gh/pion/turn/pull/58?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [internal/allocation/allocation\_manager.go](https://codecov.io/gh/pion/turn/pull/58/diff?src=pr&el=tree#diff-aW50ZXJuYWwvYWxsb2NhdGlvbi9hbGxvY2F0aW9uX21hbmFnZXIuZ28=) | `76.27% <0%> (+25.42%)` | :arrow_up: |
| [internal/allocation/allocation.go](https://codecov.io/gh/pion/turn/pull/58/diff?src=pr&el=tree#diff-aW50ZXJuYWwvYWxsb2NhdGlvbi9hbGxvY2F0aW9uLmdv) | `49.09% <0%> (+13.63%)` | :arrow_up: |
| [internal/ipnet/ipv4.go](https://codecov.io/gh/pion/turn/pull/58/diff?src=pr&el=tree#diff-aW50ZXJuYWwvaXBuZXQvaXB2NC5nbw==) | `53.57% <0%> (+14.28%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pion/turn/pull/58?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pion/turn/pull/58?src=pr&el=footer). Last update [b21ddc2...a0da01d](https://codecov.io/gh/pion/turn/pull/58?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

enobufs: @songjiayang #52 has been merged! Hope the conflict wouldn't be too bad for you. We can not live without your tests and love for turn! :) - if you need help, let me know!

Patch:
diff --git a/internal/allocation/allocation.go b/internal/allocation/allocation.go
index 9ef17ca..0aeb6c3 100644
--- a/internal/allocation/allocation.go
+++ b/internal/allocation/allocation.go
@@ -22,7 +22,7 @@ type Allocation struct {
 	RelaySocket         net.PacketConn
 	fiveTuple           *FiveTuple
 	permissionsLock     sync.RWMutex
-	permissions         []*Permission
+	permissions         map[string]*Permission
 	channelBindingsLock sync.RWMutex
 	channelBindings     []*ChannelBind
 	lifetimeTimer       *time.Timer
@@ -30,47 +30,49 @@ type Allocation struct {
 	log                 logging.LeveledLogger
 }
 
-// AddPermission adds a new permission to the allocation
-func (a *Allocation) AddPermission(p *Permission) {
-	a.permissionsLock.Lock()
-	defer a.permissionsLock.Unlock()
-	for _, existingPermission := range a.permissions {
-		if ipnet.AddrEqual(p.Addr, existingPermission.Addr) {
-			existingPermission.refresh()
-			return
-		}
+// NewAllocation creates a new instance of NewAllocation.
+func NewAllocation(turnSocket net.PacketConn, fiveTuple *FiveTuple, log logging.LeveledLogger) *Allocation {
+	return &Allocation{
+		TurnSocket:  turnSocket,
+		fiveTuple:   fiveTuple,
+		permissions: make(map[string]*Permission, 64),
+		closed:      make(chan interface{}),
+		log:         log,
 	}
+}
 
-	p.allocation = a
-	a.permissions = append(a.permissions, p)
-	p.start()
+// GetPermission gets the Permission from the allocation
+func (a *Allocation) GetPermission(fingerprint string) *Permission {
+	a.permissionsLock.RLock()
+	defer a.permissionsLock.RUnlock()
+	return a.permissions[fingerprint]
 }
 
-// RemovePermission removes the net.Addr from the allocation's permissions
-func (a *Allocation) RemovePermission(addr net.Addr) bool {
-	a.permissionsLock.Lock()
-	defer a.permissionsLock.Unlock()
+// AddPermission adds a new permission to the allocation
+func (a *Allocation) AddPermission(p *Permission) {
+	fingerprint := p.Addr.String()
 
-	for i := len(a.permissions) - 1; i >= 0; i-- {
-		if ipnet.AddrEqual(a.permissions[i].Addr, addr) {
-			a.permissions = append(a.permissions[:i], a.permissions[i+1:]...)
-			return true
-		}
+	a.permissionsLock.RLock()
+	existedPermission, ok := a.permissions[fingerprint]
+	a.permissionsLock.RUnlock()
+	if ok {
+		existedPermission.refresh(permissionTimeout)
+		return
 	}
 
-	return false
+	p.allocation = a
+	a.permissionsLock.Lock()
+	a.permissions[fingerprint] = p
+	a.permissionsLock.Unlock()
+
+	p.start(permissionTimeout)
 }
 
-// GetPermission gets the Permission from the allocation
-func (a *Allocation) GetPermission(addr net.Addr) *Permission {
-	a.permissionsLock.RLock()
-	defer a.permissionsLock.RUnlock()
-	for _, p := range a.permissions {
-		if ipnet.AddrEqual(p.Addr, addr) {
-			return p
-		}
-	}
-	return nil
+// RemovePermission removes the net.Addr's fingerprint from the allocation's permissions
+func (a *Allocation) RemovePermission(fingerprint string) {
+	a.permissionsLock.Lock()
+	defer a.permissionsLock.Unlock()
+	delete(a.permissions, fingerprint)
 }
 
 // AddChannelBind adds a new ChannelBind to the allocation, it also updates the
@@ -166,6 +168,8 @@ func (a *Allocation) Close() error {
 	}
 	close(a.closed)
 
+	a.lifetimeTimer.Stop()
+
 	a.permissionsLock.RLock()
 	for _, p := range a.permissions {
 		p.lifetimeTimer.Stop()
@@ -222,9 +226,11 @@ func (a *Allocation) packetHandler(m *Manager) {
 			if _, err = a.TurnSocket.WriteTo(channelData, a.fiveTuple.SrcAddr); err != nil {
 				a.log.Errorf("Failed to send ChannelData from allocation %v %v", srcAddr, err)
 			}
-		} else if p := a.GetPermission(&net.UDPAddr{IP: srcAddr.(*net.UDPAddr).IP, Port: srcAddr.(*net.UDPAddr).Port}); p != nil {
+		} else if p := a.GetPermission(srcAddr.String()); p != nil {
+			udpAddr := srcAddr.(*net.UDPAddr)
+			peerAddressAttr := turn.PeerAddress{IP: udpAddr.IP, Port: udpAddr.Port}
 			dataAttr := turn.Data(buffer[:n])
-			peerAddressAttr := turn.PeerAddress{IP: srcAddr.(*net.UDPAddr).IP, Port: srcAddr.(*net.UDPAddr).Port}
+
 			msg, err := stun.Build(stun.TransactionID, stun.NewType(stun.MethodData, stun.ClassIndication), peerAddressAttr, dataAttr)
 			if err != nil {
 				a.log.Errorf("Failed to send DataIndication from allocation %v %v", srcAddr, err)
diff --git a/internal/allocation/allocation_manager.go b/internal/allocation/allocation_manager.go
index 749c73d..598fc97 100644
--- a/internal/allocation/allocation_manager.go
+++ b/internal/allocation/allocation_manager.go
@@ -79,12 +79,7 @@ func (m *Manager) CreateAllocation(fiveTuple *FiveTuple, turnSocket net.PacketCo
 		return nil, errors.Errorf("Allocations must not be created with a lifetime of 0")
 	}
 
-	a := &Allocation{
-		fiveTuple:  fiveTuple,
-		TurnSocket: turnSocket,
-		closed:     make(chan interface{}),
-		log:        m.log,
-	}
+	a := NewAllocation(turnSocket, fiveTuple, m.log)
 
 	network := "udp4"
 	conn, err := m.net.ListenPacket(network, fmt.Sprintf("0.0.0.0:%d", requestedPort))
@@ -96,9 +91,7 @@ func (m *Manager) CreateAllocation(fiveTuple *FiveTuple, turnSocket net.PacketCo
 	a.RelayAddr = conn.LocalAddr()
 
 	a.lifetimeTimer = time.AfterFunc(lifetime, func() {
-		if err := conn.Close(); err != nil {
-			a.log.Errorf("Failed to close listener for %v", a.fiveTuple)
-		}
+		m.DeleteAllocation(a.fiveTuple)
 	})
 
 	m.lock.Lock()
diff --git a/internal/allocation/channel_bind.go b/internal/allocation/channel_bind.go
index 26fc815..9c3b70d 100644
--- a/internal/allocation/channel_bind.go
+++ b/internal/allocation/channel_bind.go
@@ -11,8 +11,9 @@ import (
 // ChannelBind represents a TURN Channel
 // https://tools.ietf.org/html/rfc5766#section-2.5
 type ChannelBind struct {
-	Peer          net.Addr
-	ID            turn.ChannelNumber
+	Peer net.Addr
+	ID   turn.ChannelNumber
+
 	allocation    *Allocation
 	lifetimeTimer *time.Timer
 	log           logging.LeveledLogger
diff --git a/internal/allocation/permission.go b/internal/allocation/permission.go
index 2f7eaf4..dad8313 100644
--- a/internal/allocation/permission.go
+++ b/internal/allocation/permission.go
@@ -27,16 +27,14 @@ func NewPermission(addr net.Addr, log logging.LeveledLogger) *Permission {
 	}
 }
 
-func (p *Permission) start() {
-	p.lifetimeTimer = time.AfterFunc(permissionTimeout, func() {
-		if !p.allocation.RemovePermission(p.Addr) {
-			p.log.Errorf("Failed to remove permission for %v %v", p.Addr, p.allocation.fiveTuple)
-		}
+func (p *Permission) start(lifetime time.Duration) {
+	p.lifetimeTimer = time.AfterFunc(lifetime, func() {
+		p.allocation.RemovePermission(p.Addr.String())
 	})
 }
 
-func (p *Permission) refresh() {
-	if !p.lifetimeTimer.Reset(permissionTimeout) {
+func (p *Permission) refresh(lifetime time.Duration) {
+	if !p.lifetimeTimer.Reset(lifetime) {
 		p.log.Errorf("Failed to reset permission timer for %v %v", p.Addr, p.allocation.fiveTuple)
 	}
 }
diff --git a/server.go b/server.go
index 8862887..1e7c1e4 100644
--- a/server.go
+++ b/server.go
@@ -28,12 +28,18 @@ type AuthHandler func(username string, srcAddr net.Addr) (password string, ok bo
 
 // ServerConfig is a bag of config parameters for Server.
 type ServerConfig struct {
-	Realm              string
-	AuthHandler        AuthHandler
+	// Realm sets the realm for this server
+	Realm string
+	// AuthHandler is the handler called on each incoming auth requests.
+	AuthHandler AuthHandler
+	// ChannelBindTimeout sets the lifetime of channel binding. Defaults to 10 minutes.
 	ChannelBindTimeout time.Duration
-	ListeningPort      int
-	LoggerFactory      logging.LoggerFactory
-	Net                *vnet.Net
+	// ListeningPort sets the listening port number. Defaults to 3478.
+	ListeningPort int
+	// LoggerFactory must be set for logging from this server.
+	LoggerFactory logging.LoggerFactory
+	// Net is used by pion developers. Do not use in your application.
+	Net *vnet.Net
 }
 
 type listener struct {
@@ -76,13 +82,18 @@ func NewServer(config *ServerConfig) *Server {
 		listenPort = 3478
 	}
 
+	channelBindTimeout := config.ChannelBindTimeout
+	if channelBindTimeout == 0 {
+		channelBindTimeout = turn.DefaultLifetime
+	}
+
 	return &Server{
 		listenPort:         listenPort,
 		realm:              config.Realm,
 		authHandler:        config.AuthHandler,
 		manager:            manager,
 		reservationManager: &allocation.ReservationManager{},
-		channelBindTimeout: config.ChannelBindTimeout,
+		channelBindTimeout: channelBindTimeout,
 		log:                log,
 		net:                config.Net,
 	}
diff --git a/turn.go b/turn.go
index 48593d6..7694040 100644
--- a/turn.go
+++ b/turn.go
@@ -369,7 +369,7 @@ func (s *Server) handleSendIndication(conn net.PacketConn, srcAddr net.Addr, m *
 	}
 
 	msgDst := &net.UDPAddr{IP: peerAddress.IP, Port: peerAddress.Port}
-	if perm := a.GetPermission(msgDst); perm == nil {
+	if perm := a.GetPermission(msgDst.String()); perm == nil {
 		return errors.Errorf("Unable to handle send-indication, no permission added: %v", msgDst)
 	}
 


Test patch:
diff --git a/internal/allocation/allocation_manager_test.go b/internal/allocation/allocation_manager_test.go
index bc1fb26..c460110 100644
--- a/internal/allocation/allocation_manager_test.go
+++ b/internal/allocation/allocation_manager_test.go
@@ -1,16 +1,19 @@
 package allocation
 
 import (
+	"io"
 	"math/rand"
 	"net"
+	"strings"
 	"testing"
+	"time"
 
 	"github.com/gortc/turn"
 	"github.com/pion/logging"
 	"github.com/pion/turn/internal/ipnet"
 )
 
-func TestAllocation(t *testing.T) {
+func TestManager(t *testing.T) {
 	tt := []struct {
 		name string
 		f    func(*testing.T, ipnet.PacketConn)
@@ -18,6 +21,9 @@ func TestAllocation(t *testing.T) {
 		{"CreateInvalidAllocation", subTestCreateInvalidAllocation},
 		{"CreateAllocation", subTestCreateAllocation},
 		{"CreateAllocationDuplicateFiveTuple", subTestCreateAllocationDuplicateFiveTuple},
+		{"DeleteAllocation", subTestDeleteAllocation},
+		{"AllocationTimeout", subTestAllocationTimeout},
+		{"Close", subTestManagerClose},
 	}
 
 	network := "udp4"
@@ -41,9 +47,7 @@ func TestAllocation(t *testing.T) {
 
 // test invalid Allocation creations
 func subTestCreateInvalidAllocation(t *testing.T, turnSocket ipnet.PacketConn) {
-	loggerFactory := logging.NewDefaultLoggerFactory()
-	config := &ManagerConfig{LeveledLogger: loggerFactory.NewLogger("test")}
-	m := NewManager(config)
+	m := newTestManager()
 	if a, err := m.CreateAllocation(nil, turnSocket, 0, turn.DefaultLifetime); a != nil || err == nil {
 		t.Errorf("Illegally created allocation with nil FiveTuple")
 	}
@@ -57,9 +61,7 @@ func subTestCreateInvalidAllocation(t *testing.T, turnSocket ipnet.PacketConn) {
 
 // test valid Allocation creations
 func subTestCreateAllocation(t *testing.T, turnSocket ipnet.PacketConn) {
-	loggerFactory := logging.NewDefaultLoggerFactory()
-	config := &ManagerConfig{LeveledLogger: loggerFactory.NewLogger("test")}
-	m := NewManager(config)
+	m := newTestManager()
 	fiveTuple := randomFiveTuple()
 	if a, err := m.CreateAllocation(fiveTuple, turnSocket, 0, turn.DefaultLifetime); a == nil || err != nil {
 		t.Errorf("Failed to create allocation %v %v", a, err)
@@ -72,9 +74,7 @@ func subTestCreateAllocation(t *testing.T, turnSocket ipnet.PacketConn) {
 
 // test that two allocations can't be created with the same FiveTuple
 func subTestCreateAllocationDuplicateFiveTuple(t *testing.T, turnSocket ipnet.PacketConn) {
-	loggerFactory := logging.NewDefaultLoggerFactory()
-	config := &ManagerConfig{LeveledLogger: loggerFactory.NewLogger("test")}
-	m := NewManager(config)
+	m := newTestManager()
 	fiveTuple := randomFiveTuple()
 	if a, err := m.CreateAllocation(fiveTuple, turnSocket, 0, turn.DefaultLifetime); a == nil || err != nil {
 		t.Errorf("Failed to create allocation %v %v", a, err)
@@ -85,6 +85,73 @@ func subTestCreateAllocationDuplicateFiveTuple(t *testing.T, turnSocket ipnet.Pa
 	}
 }
 
+func subTestDeleteAllocation(t *testing.T, turnSocket ipnet.PacketConn) {
+	m := newTestManager()
+	fiveTuple := randomFiveTuple()
+	if a, err := m.CreateAllocation(fiveTuple, turnSocket, 0, turn.DefaultLifetime); a == nil || err != nil {
+		t.Errorf("Failed to create allocation %v %v", a, err)
+	}
+
+	if a := m.GetAllocation(fiveTuple); a == nil {
+		t.Errorf("Failed to get allocation right after creation")
+	}
+
+	m.DeleteAllocation(fiveTuple)
+	if a := m.GetAllocation(fiveTuple); a != nil {
+		t.Errorf("Get allocation with %v should be nil after delete", fiveTuple)
+	}
+}
+
+// test that allocation should be closed if timeout
+func subTestAllocationTimeout(t *testing.T, turnSocket ipnet.PacketConn) {
+	m := newTestManager()
+	allocations := make([]*Allocation, 5)
+	lifetime := time.Second
+
+	for index := range allocations {
+		fiveTuple := randomFiveTuple()
+
+		a, err := m.CreateAllocation(fiveTuple, turnSocket, 0, lifetime)
+		if err != nil {
+			t.Errorf("Failed to create allocation with %v", fiveTuple)
+		}
+
+		allocations[index] = a
+	}
+
+	// make sure all allocations timeout
+	time.Sleep(lifetime + time.Second)
+	for _, alloc := range allocations {
+		if !isClose(alloc.RelaySocket) {
+			t.Error("Allocation relay socket should be closed if lifetime timeout")
+		}
+	}
+}
+
+// test for manager close
+func subTestManagerClose(t *testing.T, turnSocket ipnet.PacketConn) {
+	m := newTestManager()
+	allocations := make([]*Allocation, 2)
+
+	a1, _ := m.CreateAllocation(randomFiveTuple(), turnSocket, 0, time.Second)
+	allocations[0] = a1
+	a2, _ := m.CreateAllocation(randomFiveTuple(), turnSocket, 0, time.Minute)
+	allocations[1] = a2
+
+	// make a1 timeout
+	time.Sleep(2 * time.Second)
+
+	if err := m.Close(); err != nil {
+		t.Errorf("Manager close with error: %v", err)
+	}
+
+	for _, alloc := range allocations {
+		if !isClose(alloc.RelaySocket) {
+			t.Error("Manager's allocations should be closed")
+		}
+	}
+}
+
 func randomFiveTuple() *FiveTuple {
 	/* #nosec */
 	return &FiveTuple{
@@ -92,3 +159,14 @@ func randomFiveTuple() *FiveTuple {
 		DstAddr: &net.UDPAddr{IP: nil, Port: rand.Int()},
 	}
 }
+
+func newTestManager() *Manager {
+	loggerFactory := logging.NewDefaultLoggerFactory()
+	config := &ManagerConfig{LeveledLogger: loggerFactory.NewLogger("test")}
+	return NewManager(config)
+}
+
+func isClose(conn io.Closer) bool {
+	closeErr := conn.Close()
+	return closeErr != nil && strings.Contains(closeErr.Error(), "use of closed network connection")
+}
diff --git a/internal/allocation/allocation_test.go b/internal/allocation/allocation_test.go
new file mode 100644
index 0000000..bd86d3b
--- /dev/null
+++ b/internal/allocation/allocation_test.go
@@ -0,0 +1,99 @@
+package allocation
+
+import (
+	"net"
+	"testing"
+)
+
+func TestAllocation(t *testing.T) {
+	tt := []struct {
+		name string
+		f    func(*testing.T)
+	}{
+		{"GetPermission", subTestGetPermission},
+		{"AddPermission", subTestAddPermission},
+		{"RemovePermission", subTestRemovePermission},
+	}
+
+	for _, tc := range tt {
+		f := tc.f
+		t.Run(tc.name, func(t *testing.T) {
+			f(t)
+		})
+	}
+}
+
+func subTestGetPermission(t *testing.T) {
+	a := NewAllocation(nil, nil, nil)
+
+	addr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:3478")
+	addr2, _ := net.ResolveUDPAddr("udp", "127.0.0.1:3479")
+	addr3, _ := net.ResolveUDPAddr("udp", "127.0.0.1:3480")
+
+	p := &Permission{
+		Addr: addr,
+	}
+	p2 := &Permission{
+		Addr: addr2,
+	}
+
+	a.AddPermission(p)
+	a.AddPermission(p2)
+
+	foundP1 := a.GetPermission(addr.String())
+	if foundP1 != p {
+		t.Error("Got permission is not same as the the added.")
+	}
+
+	foundP2 := a.GetPermission(addr2.String())
+	if foundP2 != p2 {
+		t.Error("Got permission is not same as the the added.")
+	}
+
+	foundP3 := a.GetPermission(addr3.String())
+	if foundP3 != nil {
+		t.Error("Got permission should be nil if not added.")
+	}
+}
+
+func subTestAddPermission(t *testing.T) {
+	a := NewAllocation(nil, nil, nil)
+
+	addr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:3478")
+	p := &Permission{
+		Addr: addr,
+	}
+
+	a.AddPermission(p)
+	if p.allocation != a {
+		t.Error("Permission's allocation should be the adder.")
+	}
+
+	foundPermission := a.GetPermission(p.Addr.String())
+	if foundPermission != p {
+		t.Error("Got permission is not same as the the added.")
+	}
+}
+
+func subTestRemovePermission(t *testing.T) {
+	a := NewAllocation(nil, nil, nil)
+
+	addr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:3478")
+	p := &Permission{
+		Addr: addr,
+	}
+
+	a.AddPermission(p)
+
+	foundPermission := a.GetPermission(p.Addr.String())
+	if foundPermission != p {
+		t.Error("Got permission is not same as the the added.")
+	}
+
+	a.RemovePermission(p.Addr.String())
+
+	foundPermission = a.GetPermission(p.Addr.String())
+	if foundPermission != nil {
+		t.Error("Got permission should be nil after removed.")
+	}
+}
diff --git a/internal/allocation/channel_bind_test.go b/internal/allocation/channel_bind_test.go
index 27beafc..4c586e7 100644
--- a/internal/allocation/channel_bind_test.go
+++ b/internal/allocation/channel_bind_test.go
@@ -10,6 +10,7 @@ import (
 
 func TestChannelBind(t *testing.T) {
 	c := newChannelBind(2 * time.Second)
+
 	if c.allocation.GetChannelByID(c.ID) != c {
 		t.Errorf("GetChannelByID(%d) shouldn't be nil after added to allocation", c.ID)
 	}
@@ -17,7 +18,9 @@ func TestChannelBind(t *testing.T) {
 
 func TestChannelBindStart(t *testing.T) {
 	c := newChannelBind(2 * time.Second)
+
 	time.Sleep(3 * time.Second)
+
 	if c.allocation.GetChannelByID(c.ID) != nil {
 		t.Errorf("GetChannelByID(%d) should be nil if timeout", c.ID)
 	}
@@ -25,16 +28,18 @@ func TestChannelBindStart(t *testing.T) {
 
 func TestChannelBindReset(t *testing.T) {
 	c := newChannelBind(3 * time.Second)
+
 	time.Sleep(2 * time.Second)
 	c.refresh(3 * time.Second)
 	time.Sleep(2 * time.Second)
+
 	if c.allocation.GetChannelByID(c.ID) == nil {
 		t.Errorf("GetChannelByID(%d) shouldn't be nil after refresh", c.ID)
 	}
 }
 
 func newChannelBind(lifetime time.Duration) *ChannelBind {
-	allocation := &Allocation{}
+	a := NewAllocation(nil, nil, nil)
 
 	addr, _ := net.ResolveUDPAddr("udp", "0.0.0.0:0")
 	c := &ChannelBind{
@@ -42,7 +47,7 @@ func newChannelBind(lifetime time.Duration) *ChannelBind {
 		Peer: addr,
 	}
 
-	_ = allocation.AddChannelBind(c, lifetime)
+	_ = a.AddChannelBind(c, lifetime)
 
 	return c
 }
diff --git a/server_test.go b/server_test.go
index 471ee02..2366008 100644
--- a/server_test.go
+++ b/server_test.go
@@ -5,6 +5,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/gortc/turn"
 	"github.com/pion/logging"
 	"github.com/stretchr/testify/assert"
 )
@@ -28,6 +29,8 @@ func TestServer(t *testing.T) {
 			LoggerFactory: loggerFactory,
 		})
 
+		assert.Equal(t, turn.DefaultLifetime, server.channelBindTimeout, "should match")
+
 		err := server.AddListeningIPAddr("127.0.0.1")
 		assert.NoError(t, err, "should succeed")