summaryrefslogtreecommitdiffhomepage
path: root/server/fsm_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'server/fsm_test.go')
-rw-r--r--server/fsm_test.go212
1 files changed, 212 insertions, 0 deletions
diff --git a/server/fsm_test.go b/server/fsm_test.go
new file mode 100644
index 00000000..76b2a095
--- /dev/null
+++ b/server/fsm_test.go
@@ -0,0 +1,212 @@
+// Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+// implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package server
+
+import (
+ "fmt"
+ "github.com/osrg/gobgp/config"
+ "github.com/osrg/gobgp/packet"
+ "github.com/stretchr/testify/assert"
+ "net"
+ "strconv"
+ "testing"
+ "time"
+)
+
+type MockConnection struct {
+ net.Conn
+ recvCh chan []byte
+ sendBuf [][]byte
+ readBytes int
+}
+
+func NewMockConnection() *MockConnection {
+ m := &MockConnection{
+ recvCh: make(chan []byte, 128),
+ sendBuf: make([][]byte, 129),
+ }
+ return m
+}
+
+func (m *MockConnection) Read(buf []byte) (int, error) {
+
+ data := <-m.recvCh
+
+ for _, val := range data {
+ buf[m.readBytes] = val
+ m.readBytes += 1
+ }
+
+ length := 0
+ if m.readBytes == len(buf) {
+ m.readBytes = 0
+ length = len(buf)
+ } else {
+ length = m.readBytes
+ }
+
+ fmt.Printf("%d bytes read from peer\n", length)
+ return length, nil
+}
+
+func (m *MockConnection) Write(buf []byte) (int, error) {
+ m.sendBuf = append(m.sendBuf, buf)
+ msg, _ := bgp.ParseBGPMessage(buf)
+ fmt.Printf("%d bytes written by gobgp message type : %s\n", len(buf), showMessageType(msg.Header.Type))
+ return len(buf), nil
+}
+
+func showMessageType(t uint8) string {
+ switch t {
+ case bgp.BGP_MSG_KEEPALIVE:
+ return "BGP_MSG_KEEPALIVE"
+ case bgp.BGP_MSG_NOTIFICATION:
+ return "BGP_MSG_NOTIFICATION"
+ case bgp.BGP_MSG_OPEN:
+ return "BGP_MSG_OPEN"
+ case bgp.BGP_MSG_UPDATE:
+ return "BGP_MSG_UPDATE"
+ case bgp.BGP_MSG_ROUTE_REFRESH:
+ return "BGP_MSG_ROUTE_REFRESH"
+ }
+ return strconv.Itoa(int(t))
+}
+
+func (m *MockConnection) Close() error {
+ fmt.Printf("close called")
+ return nil
+}
+
+func TestReadAll(t *testing.T) {
+ assert := assert.New(t)
+ m := NewMockConnection()
+ msg := open()
+ expected1, _ := msg.Header.Serialize()
+ expected2, _ := msg.Body.Serialize()
+
+ pushBytes := func() {
+ fmt.Println("push 5 bytes")
+ m.recvCh <- expected1[0:5]
+ fmt.Println("wait 5 seconds...")
+ time.Sleep(time.Second * 5)
+ fmt.Println("push rest")
+ m.recvCh <- expected1[5:]
+ fmt.Println("push bytes at once")
+ m.recvCh <- expected2
+ }
+
+ go pushBytes()
+
+ var actual1 []byte
+ actual1, _ = readAll(m, bgp.BGP_HEADER_LENGTH)
+ fmt.Println(actual1)
+ assert.Equal(expected1, actual1)
+
+ var actual2 []byte
+ actual2, _ = readAll(m, len(expected2))
+ fmt.Println(actual2)
+ assert.Equal(expected2, actual2)
+}
+
+func TestFSMHandlerEstablish_HoldTimerExpired(t *testing.T) {
+ assert := assert.New(t)
+ m := NewMockConnection()
+
+ p, h := makePeerAndHandler()
+
+ // push mock connection
+ p.fsm.passiveConn = m
+
+ // set up keepalive ticker
+ sec := time.Second * 2
+ p.fsm.keepaliveTicker = time.NewTicker(sec)
+
+ msg := keepalive()
+ header, _ := msg.Header.Serialize()
+ body, _ := msg.Body.Serialize()
+
+ pushPackets := func() {
+ // first keepalive from peer
+ m.recvCh <- header
+ m.recvCh <- body
+ time.Sleep(time.Second * 4)
+ // second keepalive from peer
+ m.recvCh <- header
+ m.recvCh <- body
+ }
+
+ // set holdtime
+ p.fsm.peerConfig.Timers.HoldTime = 10
+ p.fsm.negotiatedHoldTime = 10
+
+ go pushPackets()
+ state := h.established()
+ time.Sleep(time.Second * 4)
+ assert.Equal(bgp.BGP_FSM_IDLE, state)
+ lastMsg := m.sendBuf[len(m.sendBuf)-1]
+ sent, _ := bgp.ParseBGPMessage(lastMsg)
+ assert.Equal(bgp.BGP_MSG_NOTIFICATION, sent.Header.Type)
+ assert.Equal(bgp.BGP_ERROR_HOLD_TIMER_EXPIRED, sent.Body.(*bgp.BGPNotification).ErrorCode)
+}
+
+func makePeerAndHandler() (*Peer, *FSMHandler) {
+ globalConfig := config.GlobalType{}
+ neighborConfig := config.NeighborType{}
+
+ p := &Peer{
+ globalConfig: globalConfig,
+ peerConfig: neighborConfig,
+ acceptedConnCh: make(chan net.Conn),
+ serverMsgCh: make(chan *serverMsg),
+ peerMsgCh: make(chan *peerMsg),
+ capMap: make(map[bgp.BGPCapabilityCode]bgp.ParameterCapabilityInterface),
+ }
+
+ p.siblings = make(map[string]*serverMsgDataPeer)
+ p.fsm = NewFSM(&globalConfig, &neighborConfig, p.acceptedConnCh)
+
+ incoming := make(chan *fsmMsg, FSM_CHANNEL_LENGTH)
+ p.outgoing = make(chan *bgp.BGPMessage, FSM_CHANNEL_LENGTH)
+
+ h := &FSMHandler{
+ fsm: p.fsm,
+ errorCh: make(chan bool, 2),
+ incoming: incoming,
+ outgoing: p.outgoing,
+ }
+
+ return p, h
+
+}
+
+func open() *bgp.BGPMessage {
+ p1 := bgp.NewOptionParameterCapability(
+ []bgp.ParameterCapabilityInterface{bgp.NewCapRouteRefresh()})
+ p2 := bgp.NewOptionParameterCapability(
+ []bgp.ParameterCapabilityInterface{bgp.NewCapMultiProtocol(3, 4)})
+ g := bgp.CapGracefulRestartTuples{4, 2, 3}
+ p3 := bgp.NewOptionParameterCapability(
+ []bgp.ParameterCapabilityInterface{bgp.NewCapGracefulRestart(2, 100,
+ []bgp.CapGracefulRestartTuples{g})})
+ p4 := bgp.NewOptionParameterCapability(
+ []bgp.ParameterCapabilityInterface{bgp.NewCapFourOctetASNumber(100000)})
+ return bgp.NewBGPOpenMessage(11033, 303, "100.4.10.3",
+ []bgp.OptionParameterInterface{p1, p2, p3, p4})
+}
+
+func keepalive() *bgp.BGPMessage {
+ return bgp.NewBGPKeepAliveMessage()
+}