From 1e6834bc66e3898bb03de534d9b1875ef5134ef0 Mon Sep 17 00:00:00 2001
From: Oliver Herms <oliver.herms@exaring.de>
Date: Sun, 4 Nov 2018 13:31:00 +0100
Subject: [PATCH] Add integration test for gRPC interface

---
 apps/bmp-streamer/pkg/apiserver/server.go     |  23 +--
 .../bmp-streamer/pkg/apiserver/server_test.go | 142 +++++++++++++++++-
 protocols/bgp/server/bmp_server.go            |   2 +-
 3 files changed, 153 insertions(+), 14 deletions(-)

diff --git a/apps/bmp-streamer/pkg/apiserver/server.go b/apps/bmp-streamer/pkg/apiserver/server.go
index 0fe16ff0..5b886609 100644
--- a/apps/bmp-streamer/pkg/apiserver/server.go
+++ b/apps/bmp-streamer/pkg/apiserver/server.go
@@ -2,23 +2,28 @@ package apiserver
 
 import (
 	"fmt"
+	"net"
 
 	pb "github.com/bio-routing/bio-rd/apps/bmp-streamer/pkg/bmpstreamer"
-	net "github.com/bio-routing/bio-rd/net"
+	bionet "github.com/bio-routing/bio-rd/net"
 	netapi "github.com/bio-routing/bio-rd/net/api"
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
-	"github.com/bio-routing/bio-rd/protocols/bgp/server"
 	"github.com/bio-routing/bio-rd/route"
 	"github.com/bio-routing/bio-rd/routingtable"
 )
 
+type bmpServer interface {
+	SubscribeRIBs(client routingtable.RouteTableClient, rtr net.IP, afi uint8)
+	UnsubscribeRIBs(client routingtable.RouteTableClient, rtr net.IP, afi uint8)
+}
+
 // APIServer implements the BMP server API
 type APIServer struct {
-	bmpServer *server.BMPServer
+	bmpServer bmpServer
 }
 
 // New creates an new API server
-func New(bmpServer *server.BMPServer) *APIServer {
+func New(bmpServer bmpServer) *APIServer {
 	return &APIServer{
 		bmpServer: bmpServer,
 	}
@@ -39,11 +44,11 @@ func (a *APIServer) AdjRIBInStream(req *pb.AdjRIBInStreamRequest, stream pb.RIBS
 	r4 := newRIBClient()
 	r6 := newRIBClient()
 
-	addr := net.IP{}
+	addr := bionet.IP{}
 	if req.Router.Version == netapi.IP_IPv4 {
-		addr = net.IPv4(uint32(req.Router.Lower))
+		addr = bionet.IPv4(uint32(req.Router.Lower))
 	} else if req.Router.Version == netapi.IP_IPv6 {
-		addr = net.IPv6(req.Router.Higher, req.Router.Lower)
+		addr = bionet.IPv6(req.Router.Higher, req.Router.Lower)
 	} else {
 		return fmt.Errorf("Unknown protocol")
 	}
@@ -97,7 +102,7 @@ func newRIBClient() *ribClient {
 	}
 }
 
-func (r *ribClient) AddPath(pfx net.Prefix, path *route.Path) error {
+func (r *ribClient) AddPath(pfx bionet.Prefix, path *route.Path) error {
 	r.ch <- update{
 		advertisement: true,
 		route:         route.NewRoute(pfx, path),
@@ -106,7 +111,7 @@ func (r *ribClient) AddPath(pfx net.Prefix, path *route.Path) error {
 	return nil
 }
 
-func (r *ribClient) RemovePath(pfx net.Prefix, path *route.Path) bool {
+func (r *ribClient) RemovePath(pfx bionet.Prefix, path *route.Path) bool {
 	r.ch <- update{
 		advertisement: false,
 		route:         route.NewRoute(pfx, path),
diff --git a/apps/bmp-streamer/pkg/apiserver/server_test.go b/apps/bmp-streamer/pkg/apiserver/server_test.go
index 45f5a132..f14d877f 100644
--- a/apps/bmp-streamer/pkg/apiserver/server_test.go
+++ b/apps/bmp-streamer/pkg/apiserver/server_test.go
@@ -1,17 +1,39 @@
 package apiserver
 
 import (
+	"context"
+	"fmt"
+	"log"
+	"net"
+	"sync"
 	"testing"
+	"time"
 
 	pb "github.com/bio-routing/bio-rd/apps/bmp-streamer/pkg/bmpstreamer"
-	"github.com/bio-routing/bio-rd/net"
+	bionet "github.com/bio-routing/bio-rd/net"
 	apinet "github.com/bio-routing/bio-rd/net/api"
+	"github.com/bio-routing/bio-rd/protocols/bgp/server"
 	"github.com/bio-routing/bio-rd/protocols/bgp/types"
 	"github.com/bio-routing/bio-rd/route"
 	apiroute "github.com/bio-routing/bio-rd/route/api"
+	"github.com/bio-routing/bio-rd/routingtable"
+	"github.com/bio-routing/bio-rd/routingtable/locRIB"
 	"github.com/stretchr/testify/assert"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/test/bufconn"
 )
 
+func TestNew(t *testing.T) {
+	b := &server.BMPServer{}
+	s := New(b)
+
+	expected := &APIServer{
+		bmpServer: b,
+	}
+
+	assert.Equal(t, expected, s)
+}
+
 func TestUpdateToRIBUpdate(t *testing.T) {
 	tests := []struct {
 		name     string
@@ -22,11 +44,11 @@ func TestUpdateToRIBUpdate(t *testing.T) {
 			name: "Basics advert.",
 			u: update{
 				advertisement: true,
-				route: route.NewRoute(net.NewPfx(net.IPv4(200), 8), &route.Path{
+				route: route.NewRoute(bionet.NewPfx(bionet.IPv4(200), 8), &route.Path{
 					Type: route.BGPPathType,
 					BGPPath: &route.BGPPath{
 						PathIdentifier: 10,
-						NextHop:        net.IPv4(210),
+						NextHop:        bionet.IPv4(210),
 						LocalPref:      20,
 						ASPath: types.ASPath{
 							{
@@ -38,7 +60,7 @@ func TestUpdateToRIBUpdate(t *testing.T) {
 						MED:           1000,
 						EBGP:          true,
 						BGPIdentifier: 1337,
-						Source:        net.IPv4(220),
+						Source:        bionet.IPv4(220),
 						Communities:   []uint32{10000, 20000},
 						LargeCommunities: []types.LargeCommunity{
 							{
@@ -130,3 +152,115 @@ func TestUpdateToRIBUpdate(t *testing.T) {
 		assert.Equal(t, test.expected, res, test.name)
 	}
 }
+
+type mockBMPServer struct {
+	RIB *locRIB.LocRIB
+}
+
+func newmockBMPServer() *mockBMPServer {
+	return &mockBMPServer{
+		RIB: locRIB.New(),
+	}
+}
+
+func (m *mockBMPServer) SubscribeRIBs(client routingtable.RouteTableClient, rtr net.IP, afi uint8) {
+	m.RIB.Register(client)
+}
+
+func (m *mockBMPServer) UnsubscribeRIBs(client routingtable.RouteTableClient, rtr net.IP, afi uint8) {
+	m.RIB.Unregister(client)
+}
+
+func TestIntegration(t *testing.T) {
+	bmpSrv := newmockBMPServer()
+	apiSrv := New(bmpSrv)
+
+	bufSize := 1024 * 1024
+	lis := bufconn.Listen(bufSize)
+	s := grpc.NewServer()
+	pb.RegisterRIBServiceServer(s, apiSrv)
+	go func() {
+		if err := s.Serve(lis); err != nil {
+			log.Fatalf("Server exited with error: %v", err)
+		}
+	}()
+
+	ctx := context.Background()
+
+	conn, err := grpc.DialContext(ctx, "bufnet", grpc.WithDialer(func(string, time.Duration) (net.Conn, error) {
+		return lis.Dial()
+	}), grpc.WithInsecure())
+	if err != nil {
+		t.Fatalf("Failed to dial bufnet: %v", err)
+	}
+	defer conn.Close()
+
+	var wg sync.WaitGroup
+	wg.Add(1)
+	go func() {
+		bmpSrv.RIB.AddPath(bionet.NewPfx(bionet.IPv4FromOctets(169, 254, 0, 0), 24), &route.Path{
+			Type: route.BGPPathType,
+			BGPPath: &route.BGPPath{
+				LocalPref: 1337,
+				NextHop:   bionet.IPv4FromOctets(10, 0, 0, 1),
+				Source:    bionet.IPv4FromOctets(10, 0, 0, 2),
+			},
+		})
+		wg.Done()
+	}()
+
+	client := pb.NewRIBServiceClient(conn)
+	streamClient, err := client.AdjRIBInStream(ctx, &pb.AdjRIBInStreamRequest{
+		Router: bionet.IPv4FromOctets(10, 0, 0, 1).ToProto(),
+	})
+	if err != nil {
+		t.Fatalf("AdjRIBInStream client call failed: %v", err)
+	}
+
+	wg.Add(1)
+	go func() {
+		fmt.Printf("Waiting for stream receive to return\n")
+		update, err := streamClient.Recv()
+		if err != nil {
+			t.Fatalf("Recv failed: %v", err)
+		}
+
+		expected := &pb.RIBUpdate{
+			Advertisement: true,
+			Peer: &apinet.IP{
+				Lower:   167772162,
+				Version: apinet.IP_IPv4,
+			},
+			Route: &apiroute.Route{
+				Pfx: &apinet.Prefix{
+					Address: &apinet.IP{
+						Lower:   2851995648,
+						Version: apinet.IP_IPv4,
+					},
+					Pfxlen: 24,
+				},
+				Paths: []*apiroute.Path{
+					{
+						Type: apiroute.Path_BGP,
+						BGPPath: &apiroute.BGPPath{
+							LocalPref: 1337,
+							NextHop: &apinet.IP{
+								Version: apinet.IP_IPv4,
+								Lower:   167772161,
+							},
+							Source: &apinet.IP{
+								Version: apinet.IP_IPv4,
+								Lower:   167772162,
+							},
+						},
+					},
+				},
+			},
+		}
+
+		assert.Equal(t, expected, update)
+		wg.Done()
+	}()
+
+	wg.Wait()
+}
diff --git a/protocols/bgp/server/bmp_server.go b/protocols/bgp/server/bmp_server.go
index d49355ee..1fe83080 100644
--- a/protocols/bgp/server/bmp_server.go
+++ b/protocols/bgp/server/bmp_server.go
@@ -93,7 +93,7 @@ func (b *BMPServer) AddRouter(addr net.IP, port uint16, rib4 *locRIB.LocRIB, rib
 	defer b.gloablMu.Unlock()
 
 	r := newRouter(addr, port, rib4, rib6)
-	b.routers[fmt.Sprintf("%s", r.address.String())] = r
+	b.routers[r.address.String()] = r
 
 	go func(r *router) {
 		for {
-- 
GitLab