blob: e1bfae293a29997fa7029f5cac8dd050fbb59e88 [file] [log] [blame]
Matus Fabian8792e5c2024-08-14 12:38:20 +02001// Suite for Envoy proxy testing
2//
3// The topology consists of 4 containers: curl (client), VPP (session layer), Envoy (proxy), nginx (target HTTP server).
4// VPP has 2 tap interfaces configured, one for client network and second for server/target network.
5
6package hst
7
8import (
9 "fmt"
10 . "github.com/onsi/ginkgo/v2"
11 "reflect"
12 "runtime"
13 "strings"
14)
15
16const (
17 VppContainerName = "vpp"
18 EnvoyProxyContainerName = "envoy-vcl"
19)
20
21type EnvoyProxySuite struct {
22 HstSuite
23 nginxPort uint16
24 proxyPort uint16
25}
26
27var envoyProxyTests = map[string][]func(s *EnvoyProxySuite){}
28var envoyProxySoloTests = map[string][]func(s *EnvoyProxySuite){}
29
30func RegisterEnvoyProxyTests(tests ...func(s *EnvoyProxySuite)) {
31 envoyProxyTests[getTestFilename()] = tests
32}
33
34func RegisterEnvoyProxySoloTests(tests ...func(s *EnvoyProxySuite)) {
35 envoyProxySoloTests[getTestFilename()] = tests
36}
37
38func (s *EnvoyProxySuite) SetupSuite() {
39 s.HstSuite.SetupSuite()
40 s.LoadNetworkTopology("2taps")
41 s.LoadContainerTopology("envoyProxy")
42}
43
44func (s *EnvoyProxySuite) SetupTest() {
45 s.HstSuite.SetupTest()
46
47 // VPP
48 var sessionConfig Stanza
49 sessionConfig.
50 NewStanza("session").
51 Append("enable").
52 Append("use-app-socket-api").
53 Append("evt_qs_memfd_seg").
54 Append("event-queue-length 100000")
55
56 vppContainer := s.GetContainerByName(VppContainerName)
57 vpp, err := vppContainer.newVppInstance(vppContainer.AllocatedCpus, sessionConfig)
58 s.AssertNotNil(vpp, fmt.Sprint(err))
59 s.AssertNil(vpp.Start())
60 clientInterface := s.GetInterfaceByName(ClientTapInterfaceName)
61 s.AssertNil(vpp.createTap(clientInterface, 1))
62 serverInterface := s.GetInterfaceByName(ServerTapInterfaceName)
63 s.AssertNil(vpp.createTap(serverInterface, 2))
64 vppContainer.Exec("chmod 777 -R %s", vppContainer.GetContainerWorkDir())
65
66 // nginx HTTP server
67 nginxContainer := s.GetTransientContainerByName(NginxServerContainerName)
68 s.AssertNil(nginxContainer.Create())
69 s.nginxPort = 80
70 nginxSettings := struct {
71 LogPrefix string
72 Address string
73 Port uint16
74 }{
75 LogPrefix: nginxContainer.Name,
76 Address: serverInterface.Ip4AddressString(),
77 Port: s.nginxPort,
78 }
79 nginxContainer.CreateConfig(
80 "/nginx.conf",
81 "./resources/nginx/nginx_server.conf",
82 nginxSettings,
83 )
84 s.AssertNil(nginxContainer.Start())
85
86 // Envoy
87 envoyContainer := s.GetContainerByName(EnvoyProxyContainerName)
88 s.AssertNil(envoyContainer.Create())
89 s.proxyPort = 8080
90 envoySettings := struct {
91 LogPrefix string
92 ServerAddress string
93 ServerPort uint16
94 ProxyPort uint16
95 }{
96 LogPrefix: envoyContainer.Name,
97 ServerAddress: serverInterface.Ip4AddressString(),
98 ServerPort: s.nginxPort,
99 ProxyPort: s.proxyPort,
100 }
101 envoyContainer.CreateConfig(
102 "/etc/envoy/envoy.yaml",
103 "resources/envoy/proxy.yaml",
104 envoySettings,
105 )
106 s.AssertNil(envoyContainer.Start())
107
108 // Add Ipv4 ARP entry for nginx HTTP server, otherwise first request fail (HTTP error 503)
109 arp := fmt.Sprintf("set ip neighbor %s %s %s",
110 serverInterface.Peer.Name(),
111 serverInterface.Ip4AddressString(),
112 serverInterface.HwAddress)
113 vppContainer.VppInstance.Vppctl(arp)
114}
115
116func (s *EnvoyProxySuite) TearDownTest() {
117 if CurrentSpecReport().Failed() {
118 s.CollectNginxLogs(NginxServerContainerName)
119 s.CollectEnvoyLogs(EnvoyProxyContainerName)
120 }
121 s.HstSuite.TearDownTest()
122}
123
124func (s *EnvoyProxySuite) ProxyPort() uint16 {
125 return s.proxyPort
126}
127
128func (s *EnvoyProxySuite) ProxyAddr() string {
129 return s.GetInterfaceByName(ClientTapInterfaceName).Peer.Ip4AddressString()
130}
131
132func (s *EnvoyProxySuite) CurlDownloadResource(uri string) {
133 args := fmt.Sprintf("--insecure --noproxy '*' --remote-name --output-dir /tmp %s", uri)
134 _, log := s.RunCurlContainer(args)
135 s.AssertNotContains(log, "Recv failure")
136 s.AssertContains(log, "HTTP/1.1 200")
137}
138
139var _ = Describe("EnvoyProxySuite", Ordered, ContinueOnFailure, func() {
140 var s EnvoyProxySuite
141 BeforeAll(func() {
142 s.SetupSuite()
143 })
144 BeforeEach(func() {
145 s.SetupTest()
146 })
147 AfterAll(func() {
148 s.TearDownSuite()
149 })
150 AfterEach(func() {
151 s.TearDownTest()
152 })
153
154 for filename, tests := range envoyProxyTests {
155 for _, test := range tests {
156 test := test
157 pc := reflect.ValueOf(test).Pointer()
158 funcValue := runtime.FuncForPC(pc)
159 testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
160 It(testName, func(ctx SpecContext) {
161 s.Log(testName + ": BEGIN")
162 test(&s)
163 }, SpecTimeout(SuiteTimeout))
164 }
165 }
166})
167
168var _ = Describe("EnvoyProxySuiteSolo", Ordered, ContinueOnFailure, func() {
169 var s EnvoyProxySuite
170 BeforeAll(func() {
171 s.SetupSuite()
172 })
173 BeforeEach(func() {
174 s.SetupTest()
175 })
176 AfterAll(func() {
177 s.TearDownSuite()
178 })
179 AfterEach(func() {
180 s.TearDownTest()
181 })
182
183 for filename, tests := range envoyProxySoloTests {
184 for _, test := range tests {
185 test := test
186 pc := reflect.ValueOf(test).Pointer()
187 funcValue := runtime.FuncForPC(pc)
188 testName := filename + "/" + strings.Split(funcValue.Name(), ".")[2]
189 It(testName, Label("SOLO"), func(ctx SpecContext) {
190 s.Log(testName + ": BEGIN")
191 test(&s)
192 }, SpecTimeout(SuiteTimeout))
193 }
194 }
195})