stats: golang vpp_if_stats_client
[vpp.git] / extras / vpp_if_stats / vpp_if_stats_test.go
1 package main
2
3 import (
4         "git.fd.io/govpp.git/adapter"
5         "git.fd.io/govpp.git/api"
6         "git.fd.io/govpp.git/examples/bin_api/interfaces"
7         "git.fd.io/govpp.git/examples/bin_api/vpe"
8         "github.com/golang/mock/gomock"
9         "github.com/stretchr/testify/assert"
10         "math/rand"
11         "testing"
12         "time"
13 )
14
15 var (
16         vppDetails = vpe.ShowVersionReply{
17                 Program: []byte("vpe"),
18                 Version: []byte("18.10"),
19         }
20
21         testSwIfIndex = uint32(0)
22         testInterface = func() *vppInterface {
23                 return &vppInterface{
24                         SwInterfaceDetails: interfaces.SwInterfaceDetails{SwIfIndex: testSwIfIndex}, // TODO
25                         Stats:              interfaceStats{},                                        // TODO
26                 }
27         }
28         testInterfaces = func() *map[uint32]*vppInterface {
29                 return &map[uint32]*vppInterface{
30                         testSwIfIndex: testInterface(),
31                 }
32         }
33
34         r                 = rand.New(rand.NewSource(time.Now().UnixNano()))
35         testCombinedStats = interfaceStats{
36                 TxBytes:   r.Uint64(),
37                 TxPackets: r.Uint64(),
38                 RxBytes:   r.Uint64(),
39                 RxPackets: r.Uint64(),
40         }
41         testCombinedStatsDump = []*adapter.StatEntry{
42                 {
43                         Name: "/if/tx",
44                         Type: adapter.CombinedCounterVector,
45                         Data: adapter.CombinedCounterStat{
46                                 []adapter.CombinedCounter{
47                                         {
48                                                 Bytes:   adapter.Counter(testCombinedStats.TxBytes),
49                                                 Packets: adapter.Counter(testCombinedStats.TxPackets),
50                                         },
51                                 },
52                         },
53                 },
54                 {
55                         Name: "/if/rx",
56                         Type: adapter.CombinedCounterVector,
57                         Data: adapter.CombinedCounterStat{
58                                 []adapter.CombinedCounter{
59                                         {
60                                                 Bytes:   adapter.Counter(testCombinedStats.RxBytes),
61                                                 Packets: adapter.Counter(testCombinedStats.RxPackets),
62                                         },
63                                 },
64                         },
65                 },
66         }
67
68         testSimpleStats = interfaceStats{
69                 TxErrors: r.Uint64(),
70                 RxErrors: r.Uint64(),
71                 Drops:    r.Uint64(),
72                 Punts:    r.Uint64(),
73         }
74         testSimpleStatsDump = []*adapter.StatEntry{
75                 {
76                         Name: "/if/tx-error",
77                         Type: adapter.SimpleCounterVector,
78                         Data: adapter.SimpleCounterStat{
79                                 []adapter.Counter{adapter.Counter(testSimpleStats.TxErrors)},
80                         },
81                 },
82                 {
83                         Name: "/if/rx-error",
84                         Type: adapter.SimpleCounterVector,
85                         Data: adapter.SimpleCounterStat{
86                                 []adapter.Counter{adapter.Counter(testSimpleStats.RxErrors)},
87                         },
88                 },
89                 {
90                         Name: "/if/drops",
91                         Type: adapter.SimpleCounterVector,
92                         Data: adapter.SimpleCounterStat{
93                                 []adapter.Counter{adapter.Counter(testSimpleStats.Drops)},
94                         },
95                 },
96                 {
97                         Name: "/if/punt",
98                         Type: adapter.SimpleCounterVector,
99                         Data: adapter.SimpleCounterStat{
100                                 []adapter.Counter{adapter.Counter(testSimpleStats.Punts)},
101                         },
102                 },
103         }
104 )
105
106 type showDetailsContext struct {
107         details vpe.ShowVersionReply
108 }
109
110 func (ctx *showDetailsContext) ReceiveReply(msg api.Message) (err error) {
111         *(msg.(*vpe.ShowVersionReply)) = vppDetails
112         return nil
113 }
114
115 type interfaceDumpContext struct {
116         interfaces   []interfaces.SwInterfaceDetails
117         currentIndex int
118 }
119
120 func (ctx *interfaceDumpContext) ReceiveReply(msg api.Message) (lastReplyReceived bool, err error) {
121         stop := ctx.currentIndex >= len(ctx.interfaces)
122         if !stop {
123                 *(msg.(*interfaces.SwInterfaceDetails)) = ctx.interfaces[ctx.currentIndex]
124                 ctx.currentIndex++
125         }
126         return stop, nil
127 }
128
129 func TestVppIfStats_GetVppVersion(t *testing.T) {
130         mockCtrl := gomock.NewController(t)
131         defer mockCtrl.Finish()
132
133         mockChannel := NewMockChannel(mockCtrl)
134         mockChannel.EXPECT().SendRequest(&vpe.ShowVersion{}).Return(&showDetailsContext{details: vppDetails})
135
136         v := vppConnector{api: mockChannel}
137         err := v.getVppVersion()
138         assert.NoError(t, err, "GetVppVersion should not return an error")
139         assert.Equal(t, vppDetails, v.VppDetails, "VPP details should be saved")
140 }
141
142 func TestVppIfStats_GetInterfaces(t *testing.T) {
143         mockCtrl := gomock.NewController(t)
144         defer mockCtrl.Finish()
145
146         testContext := interfaceDumpContext{interfaces: []interfaces.SwInterfaceDetails{testInterface().SwInterfaceDetails}}
147         mockChannel := NewMockChannel(mockCtrl)
148         mockChannel.EXPECT().SendMultiRequest(&interfaces.SwInterfaceDump{}).Return(&testContext)
149
150         v := vppConnector{api: mockChannel}
151         err := v.getInterfaces()
152         assert.NoError(t, err, "GetInterfaces should not return an error")
153         assert.Len(t, v.Interfaces, len(testContext.interfaces), "All dumped interfaces should be saved")
154         if len(testContext.interfaces) > 0 {
155                 assert.Equal(t, testContext.interfaces[0], v.Interfaces[testInterface().SwIfIndex].SwInterfaceDetails,
156                         "All dumped interface info should be saved")
157         }
158 }
159
160 func TestVppIfStats_GetStatsForAllInterfacesNoStats(t *testing.T) {
161         mockCtrl := gomock.NewController(t)
162         defer mockCtrl.Finish()
163
164         mockStatsAPI := NewMockStatsAPI(mockCtrl)
165         mockStatsAPI.EXPECT().DumpStats("/if").Return([]*adapter.StatEntry{}, nil)
166
167         v := vppConnector{stats: mockStatsAPI, Interfaces: *testInterfaces()}
168         err := v.getStatsForAllInterfaces()
169         assert.NoError(t, err, "GetStatsForAllInterfaces should not return an error")
170         assert.Equal(t, interfaceStats{}, v.Interfaces[testSwIfIndex].Stats, "Stats should be empty")
171 }
172
173 func testStats(t *testing.T, statsDump *[]*adapter.StatEntry, expectedStats *interfaceStats) {
174         mockCtrl := gomock.NewController(t)
175         defer mockCtrl.Finish()
176
177         mockStatsAPI := NewMockStatsAPI(mockCtrl)
178         mockStatsAPI.EXPECT().DumpStats("/if").Return(*statsDump, nil)
179
180         v := vppConnector{stats: mockStatsAPI, Interfaces: *testInterfaces()}
181         err := v.getStatsForAllInterfaces()
182         assert.NoError(t, err, "GetStatsForAllInterfaces should not return an error")
183         assert.Equal(t, *expectedStats, v.Interfaces[testSwIfIndex].Stats, "Collected and saved stats should match")
184 }
185
186 func TestVppIfStats_GetStatsForAllInterfacesCombinedStats(t *testing.T) {
187         testStats(t, &testCombinedStatsDump, &testCombinedStats)
188 }
189
190 func TestVppIfStats_GetStatsForAllInterfacesSimpleStats(t *testing.T) {
191         testStats(t, &testSimpleStatsDump, &testSimpleStats)
192 }