diff options
author | Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp> | 2015-01-21 20:14:49 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-01-26 20:41:08 +0900 |
commit | dafa0a31d73f49b6cd68e658f000da904565f36c (patch) | |
tree | 75bb21a4920f78ec7f5a4fdc70a79d13ee30f1ad /server/fsm_test.go | |
parent | 3491d5214352586708444bcf41eca16f7ff1d3e6 (diff) |
fsm: check hold timer expiration and add test case for holdtimer expiration at Established state
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Diffstat (limited to 'server/fsm_test.go')
-rw-r--r-- | server/fsm_test.go | 212 |
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() +} |