11package exporter
22
33import (
4+ "context"
5+ "fmt"
46 "net"
57 "testing"
68 "time"
79
10+ "github.com/netobserv/netobserv-ebpf-agent/pkg/config"
11+ grpcflow "github.com/netobserv/netobserv-ebpf-agent/pkg/grpc/flow"
812 "github.com/netobserv/netobserv-ebpf-agent/pkg/metrics"
913 "github.com/netobserv/netobserv-ebpf-agent/pkg/model"
1014 "github.com/netobserv/netobserv-ebpf-agent/pkg/pbflow"
1115 test2 "github.com/netobserv/netobserv-ebpf-agent/pkg/test"
1216
1317 "github.com/mariomac/guara/pkg/test"
1418 "github.com/netobserv/netobserv-ebpf-agent/pkg/ebpf"
15- grpc "github.com/netobserv/netobserv-ebpf-agent/pkg/grpc/flow"
1619 "github.com/stretchr/testify/assert"
1720 "github.com/stretchr/testify/require"
21+ "google.golang.org/grpc/peer"
1822)
1923
2024const timeout = 2 * time .Second
@@ -24,12 +28,17 @@ func TestIPv4GRPCProto_ExportFlows_AgentIP(t *testing.T) {
2428 port , err := test .FreeTCPPort ()
2529 require .NoError (t , err )
2630 serverOut := make (chan * pbflow.Records )
27- coll , err := grpc .StartCollector (port , serverOut )
31+ coll , err := grpcflow .StartCollector (port , serverOut )
2832 require .NoError (t , err )
2933 defer coll .Close ()
3034
3135 // Start GRPCProto exporter stage
32- exporter , err := StartGRPCProto ("127.0.0.1" , port , "" , "" , "" , 1000 , metrics .NoOp ())
36+ cfg := config.Agent {
37+ TargetHost : "127.0.0.1" ,
38+ TargetPort : port ,
39+ GRPCMessageMaxFlows : 1000 ,
40+ }
41+ exporter , err := StartGRPCProto (& cfg , metrics .NoOp ())
3342 require .NoError (t , err )
3443
3544 // Send some flows to the input of the exporter stage
@@ -66,12 +75,17 @@ func TestIPv6GRPCProto_ExportFlows_AgentIP(t *testing.T) {
6675 port , err := test .FreeTCPPort ()
6776 require .NoError (t , err )
6877 serverOut := make (chan * pbflow.Records )
69- coll , err := grpc .StartCollector (port , serverOut )
78+ coll , err := grpcflow .StartCollector (port , serverOut )
7079 require .NoError (t , err )
7180 defer coll .Close ()
7281
7382 // Start GRPCProto exporter stage
74- exporter , err := StartGRPCProto ("::1" , port , "" , "" , "" , 1000 , metrics .NoOp ())
83+ cfg := config.Agent {
84+ TargetHost : "::1" ,
85+ TargetPort : port ,
86+ GRPCMessageMaxFlows : 1000 ,
87+ }
88+ exporter , err := StartGRPCProto (& cfg , metrics .NoOp ())
7589 require .NoError (t , err )
7690
7791 // Send some flows to the input of the exporter stage
@@ -108,13 +122,17 @@ func TestGRPCProto_SplitLargeMessages(t *testing.T) {
108122 port , err := test .FreeTCPPort ()
109123 require .NoError (t , err )
110124 serverOut := make (chan * pbflow.Records )
111- coll , err := grpc .StartCollector (port , serverOut )
125+ coll , err := grpcflow .StartCollector (port , serverOut )
112126 require .NoError (t , err )
113127 defer coll .Close ()
114128
115- const msgMaxLen = 10000
116129 // Start GRPCProto exporter stage
117- exporter , err := StartGRPCProto ("127.0.0.1" , port , "" , "" , "" , msgMaxLen , metrics .NoOp ())
130+ cfg := config.Agent {
131+ TargetHost : "127.0.0.1" ,
132+ TargetPort : port ,
133+ GRPCMessageMaxFlows : 10_000 ,
134+ }
135+ exporter , err := StartGRPCProto (& cfg , metrics .NoOp ())
118136 require .NoError (t , err )
119137
120138 // Send a message much longer than the limit length
@@ -130,9 +148,9 @@ func TestGRPCProto_SplitLargeMessages(t *testing.T) {
130148
131149 // expect that the submitted message is split in chunks no longer than msgMaxLen
132150 rs := test2 .ReceiveTimeout (t , serverOut , timeout )
133- assert .Len (t , rs .Entries , msgMaxLen )
151+ assert .Len (t , rs .Entries , cfg . GRPCMessageMaxFlows )
134152 rs = test2 .ReceiveTimeout (t , serverOut , timeout )
135- assert .Len (t , rs .Entries , msgMaxLen )
153+ assert .Len (t , rs .Entries , cfg . GRPCMessageMaxFlows )
136154 rs = test2 .ReceiveTimeout (t , serverOut , timeout )
137155 assert .Len (t , rs .Entries , 5000 )
138156
@@ -144,3 +162,91 @@ func TestGRPCProto_SplitLargeMessages(t *testing.T) {
144162 // ok!
145163 }
146164}
165+
166+ type collectorAPI struct {
167+ pbflow.UnimplementedCollectorServer
168+ recordForwarder chan <- * pbflow.Records
169+ lastClient string
170+ clientOccurrences []int
171+ }
172+
173+ func (c * collectorAPI ) Send (ctx context.Context , records * pbflow.Records ) (* pbflow.CollectorReply , error ) {
174+ if p , ok := peer .FromContext (ctx ); ok {
175+ addr := p .Addr .String ()
176+ if len (c .clientOccurrences ) == 0 || addr != c .lastClient {
177+ c .clientOccurrences = append (c .clientOccurrences , 1 )
178+ c .lastClient = addr
179+ } else {
180+ c .clientOccurrences [len (c .clientOccurrences )- 1 ]++
181+ }
182+ }
183+ c .recordForwarder <- records
184+ return & pbflow.CollectorReply {}, nil
185+ }
186+
187+ func TestConnectionReset (t * testing.T ) {
188+ // start remote ingestor
189+ port , err := test .FreeTCPPort ()
190+ require .NoError (t , err )
191+ serverOut := make (chan * pbflow.Records )
192+
193+ api := collectorAPI {
194+ recordForwarder : serverOut ,
195+ clientOccurrences : []int {},
196+ }
197+ coll , err := grpcflow .StartCollectorWithAPI (port , & api )
198+ require .NoError (t , err )
199+ defer coll .Close ()
200+
201+ // Start GRPCProto exporter stage
202+ cfg := config.Agent {
203+ TargetHost : "127.0.0.1" ,
204+ TargetPort : port ,
205+ GRPCMessageMaxFlows : 1000 ,
206+ GRPCReconnectTimer : 500 * time .Millisecond ,
207+ }
208+ exporter , err := StartGRPCProto (& cfg , metrics .NoOp ())
209+ require .NoError (t , err )
210+
211+ // Send some flows to the input of the exporter stage
212+ nFlows := 5
213+ flows := make (chan []* model.Record , nFlows + 1 )
214+ go exporter .ExportFlows (flows )
215+ go func () {
216+ for i := range nFlows {
217+ flows <- []* model.Record {
218+ {AgentIP : net .ParseIP (fmt .Sprintf ("10.9.8.%d" , i )), Metrics : model.BpfFlowContent {BpfFlowMetrics : & ebpf.BpfFlowMetrics {}}},
219+ }
220+ time .Sleep (300 * time .Millisecond )
221+ }
222+ }()
223+
224+ for i := 0 ; i < nFlows ; i ++ {
225+ rs := test2 .ReceiveTimeout (t , serverOut , timeout )
226+ assert .Len (t , rs .Entries , 1 )
227+ r := rs .Entries [0 ]
228+ assert .EqualValues (t , 0x0a090800 + i , r .GetAgentIp ().GetIpv4 ())
229+ }
230+
231+ // Expect flows sent at +0ms, +300ms | +600ms, +900ms | +1200ms ("|" means reconnect event / new client detected)
232+ // If it ends up too flaky, we can increase the durations, e.g. over 5s, or relax the assertion
233+ assert .Equal (t , []int {2 , 2 , 1 }, api .clientOccurrences )
234+
235+ select {
236+ case rs := <- serverOut :
237+ assert .Failf (t , "shouldn't have received any flow" , "Got: %#v" , rs )
238+ default :
239+ // ok!
240+ }
241+ }
242+
243+ func TestRandomizeMaxMessages (t * testing.T ) {
244+ for i := 0 ; i < 1000 ; i ++ {
245+ v := randomizeTimer (& config.Agent {
246+ GRPCReconnectTimer : 5 * time .Minute ,
247+ GRPCReconnectTimerRandomization : 30 * time .Second ,
248+ })
249+ assert .GreaterOrEqual (t , v , 270 * time .Second /*4m30s*/ )
250+ assert .LessOrEqual (t , v , 330 * time .Second /*5m30s*/ )
251+ }
252+ }
0 commit comments