99 "bytes"
1010 "fmt"
1111 "io"
12+ "os"
1213 "path"
14+ "path/filepath"
1315 "testing"
1416 "time"
1517
@@ -24,9 +26,10 @@ import (
2426 "github.com/envoyproxy/gateway/internal/infrastructure/common"
2527 "github.com/envoyproxy/gateway/internal/ir"
2628 "github.com/envoyproxy/gateway/internal/logging"
29+ "github.com/envoyproxy/gateway/internal/utils"
2730 "github.com/envoyproxy/gateway/internal/utils/file"
2831 "github.com/envoyproxy/gateway/internal/xds/bootstrap"
29- "github.com/envoyproxy/gateway/test/utils"
32+ testutils "github.com/envoyproxy/gateway/test/utils"
3033)
3134
3235func newMockInfra (t * testing.T , cfg * config.Server ) * Infra {
@@ -65,31 +68,188 @@ func TestInfraCreateProxy(t *testing.T) {
6568
6669 // TODO: add more tests once it supports configurable homeDir and runDir.
6770 testCases := []struct {
68- name string
69- expect bool
70- infra * ir. Infra
71+ name string
72+ infra * ir. Infra
73+ expectedError string
7174 }{
7275 {
73- name : "nil cfg" ,
74- expect : false ,
75- infra : nil ,
76+ name : "nil cfg" ,
77+ infra : nil ,
78+ expectedError : "infra ir is nil" ,
7679 },
7780 {
78- name : "nil proxy" ,
79- expect : false ,
81+ name : "nil proxy" ,
8082 infra : & ir.Infra {
8183 Proxy : nil ,
8284 },
85+ expectedError : "infra proxy ir is nil" ,
8386 },
8487 }
8588
8689 for _ , tc := range testCases {
8790 t .Run (tc .name , func (t * testing.T ) {
88- err = infra .CreateOrUpdateProxyInfra (t .Context (), tc .infra )
89- if tc .expect {
90- require .NoError (t , err )
91+ actual := infra .CreateOrUpdateProxyInfra (t .Context (), tc .infra )
92+ require .EqualError (t , actual , tc .expectedError )
93+ })
94+ }
95+ }
96+
97+ func TestInfra_CreateOrUpdateProxyInfra_Success (t * testing.T ) {
98+ tmpdir := t .TempDir ()
99+ // Ensures that all the required binaries are available.
100+ err := func_e .Run (t .Context (), []string {"--version" }, api .HomeDir (tmpdir ))
101+ require .NoError (t , err )
102+
103+ cfg , err := config .New (io .Discard , io .Discard )
104+ require .NoError (t , err )
105+ infra := newMockInfra (t , cfg )
106+
107+ testCases := []struct {
108+ name string
109+ proxyName string
110+ expectProxyLoaded bool
111+ }{
112+ {
113+ name : "create new proxy" ,
114+ proxyName : "test-proxy" ,
115+ expectProxyLoaded : true ,
116+ },
117+ {
118+ name : "idempotent - proxy already exists" ,
119+ proxyName : "test-proxy-idempotent" ,
120+ expectProxyLoaded : true ,
121+ },
122+ }
123+
124+ for _ , tc := range testCases {
125+ t .Run (tc .name , func (t * testing.T ) {
126+ infraIR := & ir.Infra {
127+ Proxy : & ir.ProxyInfra {
128+ Name : tc .proxyName ,
129+ Namespace : "default" ,
130+ Config : & egv1a1.EnvoyProxy {
131+ Spec : egv1a1.EnvoyProxySpec {
132+ Logging : egv1a1.ProxyLogging {
133+ Level : map [egv1a1.ProxyLogComponent ]egv1a1.LogLevel {
134+ egv1a1 .LogComponentDefault : egv1a1 .LogLevelInfo ,
135+ },
136+ },
137+ },
138+ },
139+ },
140+ }
141+
142+ hashedName := utils .GetHashedName (tc .proxyName , 64 )
143+ t .Cleanup (func () { infra .stopEnvoy (hashedName ) })
144+
145+ // First call should create the proxy
146+ actual := infra .CreateOrUpdateProxyInfra (t .Context (), infraIR )
147+ require .NoError (t , actual )
148+
149+ // Verify proxy context was stored
150+ _ , loaded := infra .proxyContextMap .Load (hashedName )
151+ require .Equal (t , tc .expectProxyLoaded , loaded )
152+
153+ // Second call should be idempotent (early return)
154+ actual = infra .CreateOrUpdateProxyInfra (t .Context (), infraIR )
155+ require .NoError (t , actual )
156+
157+ // Verify proxy is still loaded
158+ _ , loaded = infra .proxyContextMap .Load (hashedName )
159+ require .Equal (t , tc .expectProxyLoaded , loaded )
160+ })
161+ }
162+ }
163+
164+ func TestInfra_DeleteProxyInfra (t * testing.T ) {
165+ tmpdir := t .TempDir ()
166+ // Ensures that all the required binaries are available.
167+ err := func_e .Run (t .Context (), []string {"--version" }, api .HomeDir (tmpdir ))
168+ require .NoError (t , err )
169+
170+ cfg , err := config .New (io .Discard , io .Discard )
171+ require .NoError (t , err )
172+ infra := newMockInfra (t , cfg )
173+
174+ testCases := []struct {
175+ name string
176+ setupProxy bool
177+ proxyName string
178+ infraIR * ir.Infra
179+ expectedError string
180+ expectRemoved bool
181+ }{
182+ {
183+ name : "delete existing proxy" ,
184+ setupProxy : true ,
185+ proxyName : "test-proxy-delete" ,
186+ infraIR : & ir.Infra {
187+ Proxy : & ir.ProxyInfra {
188+ Name : "test-proxy-delete" ,
189+ Namespace : "default" ,
190+ Config : & egv1a1.EnvoyProxy {
191+ Spec : egv1a1.EnvoyProxySpec {
192+ Logging : egv1a1.ProxyLogging {
193+ Level : map [egv1a1.ProxyLogComponent ]egv1a1.LogLevel {
194+ egv1a1 .LogComponentDefault : egv1a1 .LogLevelInfo ,
195+ },
196+ },
197+ },
198+ },
199+ },
200+ },
201+ expectedError : "" ,
202+ expectRemoved : true ,
203+ },
204+ {
205+ name : "delete non-existent proxy" ,
206+ setupProxy : false ,
207+ proxyName : "non-existent-proxy" ,
208+ infraIR : & ir.Infra {
209+ Proxy : & ir.ProxyInfra {
210+ Name : "non-existent-proxy" ,
211+ Namespace : "default" ,
212+ Config : & egv1a1.EnvoyProxy {},
213+ },
214+ },
215+ expectedError : "" ,
216+ expectRemoved : false ,
217+ },
218+ {
219+ name : "nil infra" ,
220+ setupProxy : false ,
221+ infraIR : nil ,
222+ expectedError : "infra ir is nil" ,
223+ },
224+ }
225+
226+ for _ , tc := range testCases {
227+ t .Run (tc .name , func (t * testing.T ) {
228+ var hashedName string
229+ if tc .setupProxy {
230+ // Create a proxy first
231+ actual := infra .CreateOrUpdateProxyInfra (t .Context (), tc .infraIR )
232+ require .NoError (t , actual )
233+
234+ hashedName = utils .GetHashedName (tc .proxyName , 64 )
235+ t .Cleanup (func () { infra .stopEnvoy (hashedName ) })
236+
237+ _ , loaded := infra .proxyContextMap .Load (hashedName )
238+ require .True (t , loaded , "proxy should be loaded before deletion" )
239+ }
240+
241+ // Delete the proxy
242+ actual := infra .DeleteProxyInfra (t .Context (), tc .infraIR )
243+ if tc .expectedError != "" {
244+ require .EqualError (t , actual , tc .expectedError )
91245 } else {
92- require .Error (t , err )
246+ require .NoError (t , actual )
247+ }
248+
249+ // Verify deletion
250+ if tc .expectRemoved {
251+ _ , loaded := infra .proxyContextMap .Load (hashedName )
252+ require .False (t , loaded , "proxy should be removed after deletion" )
93253 }
94254 })
95255 }
@@ -206,7 +366,7 @@ func TestInfra_runEnvoy_OutputRedirection(t *testing.T) {
206366 require .NoError (t , err )
207367
208368 // Create separate buffers for stdout and stderr
209- buffers := utils .DumpLogsOnFail (t , "stdout" , "stderr" )
369+ buffers := testutils .DumpLogsOnFail (t , "stdout" , "stderr" )
210370 stdout := buffers [0 ]
211371 stderr := buffers [1 ]
212372
@@ -323,6 +483,48 @@ func TestGetEnvoyVersion(t *testing.T) {
323483// TestTopologyInjectorDisabledInHostMode verifies we don't cause a 15+ second
324484// startup delay in standalone mode as Envoy waits for endpoint discovery.
325485// See: https://github.com/envoyproxy/gateway/issues/7080
486+ func TestNewInfra (t * testing.T ) {
487+ // This test verifies successful creation of Infra using defaults.
488+ // NewInfra uses hardcoded paths like defaultHomeDir and defaultLocalCertPathDir,
489+ // so we can only test the success case where those directories exist.
490+ cfg , err := config .New (io .Discard , io .Discard )
491+ require .NoError (t , err )
492+
493+ actual , err := NewInfra (t .Context (), cfg , logging .DefaultLogger (io .Discard , egv1a1 .LogLevelInfo ))
494+ require .NoError (t , err )
495+ require .NotNil (t , actual )
496+ require .Equal (t , defaultHomeDir , actual .HomeDir )
497+ require .Equal (t , defaultLocalCertPathDir , actual .sdsConfigPath )
498+ require .NotNil (t , actual .Logger )
499+ require .NotNil (t , actual .EnvoyGateway )
500+ require .Equal (t , egv1a1 .DefaultEnvoyProxyImage , actual .defaultEnvoyImage )
501+ require .NotNil (t , actual .Stdout )
502+ require .NotNil (t , actual .Stderr )
503+ }
504+
505+ func TestCreateSdsConfig (t * testing.T ) {
506+ dir := t .TempDir ()
507+ // Create required cert files
508+ require .NoError (t , file .WriteDir ([]byte ("test ca" ), dir , XdsTLSCaFilename ))
509+ require .NoError (t , file .WriteDir ([]byte ("test cert" ), dir , XdsTLSCertFilename ))
510+ require .NoError (t , file .WriteDir ([]byte ("test key" ), dir , XdsTLSKeyFilename ))
511+
512+ actual := createSdsConfig (dir )
513+ require .NoError (t , actual )
514+
515+ // Verify CA config was created
516+ caConfigPath := filepath .Join (dir , common .SdsCAFilename )
517+ actualCAConfig , err := os .ReadFile (caConfigPath )
518+ require .NoError (t , err )
519+ require .NotEmpty (t , actualCAConfig )
520+
521+ // Verify cert config was created
522+ certConfigPath := filepath .Join (dir , common .SdsCertFilename )
523+ actualCertConfig , err := os .ReadFile (certConfigPath )
524+ require .NoError (t , err )
525+ require .NotEmpty (t , actualCertConfig )
526+ }
527+
326528func TestTopologyInjectorDisabledInHostMode (t * testing.T ) {
327529 testCases := []struct {
328530 name string
0 commit comments