@@ -15,12 +15,12 @@ public class ReverseProxyClientTests
1515 private readonly Mock < IDockerEngine > _dockerMock = new ( ) ;
1616 private readonly Mock < IConsole > _consoleMock = new ( ) ;
1717 private readonly Mock < IKindClient > _kindMock = new ( ) ;
18- private readonly Mock < IKubernetesClient > _k8sMock = new ( ) ;
18+ private readonly Mock < IKubernetesClient > _kubeClientMock = new ( ) ;
1919 private readonly Func < string , IKubernetesClient > _clientFunc ;
2020
2121 public ReverseProxyClientTests ( )
2222 {
23- _clientFunc = _ => _k8sMock . Object ;
23+ _clientFunc = _ => _kubeClientMock . Object ;
2424 }
2525
2626 [ Fact ]
@@ -66,5 +66,149 @@ public void InitConfFile_CreatesFileAndWritesConfig()
6666 File . ReadAllText ( tempFile ) . Should ( ) . Contain ( "server {" ) ;
6767 File . Delete ( tempFile ) ;
6868 }
69+
70+ [ Fact ]
71+ public void PatchCoreDns_ReturnsFalse_WhenIngressServiceNotFound ( )
72+ {
73+ // Arrange
74+ _kubeClientMock . SetupSequence ( x => x . Get < V1Service > ( "ingress-nginx-controller" , "ingress-nginx" ) )
75+ . Returns ( ( V1Service ? ) null ) ;
76+ var client = new ReverseProxyClient ( _dockerMock . Object , _clientFunc , _consoleMock . Object , _kindMock . Object ) ;
77+
78+ // Act
79+ var result = InvokePatchCoreDns ( client , "test-cluster" ) ;
80+
81+ // Assert
82+ Assert . False ( result ) ;
83+ _consoleMock . Verify ( x => x . WriteError ( It . Is < string > ( s => s . Contains ( "Ingress-nginx-controller service not found" ) ) ) , Times . Once ) ;
84+ }
85+
86+ [ Fact ]
87+ public void PatchCoreDns_ReturnsFalse_WhenCoreDnsConfigMapNotFound ( )
88+ {
89+ // Arrange
90+ _kubeClientMock . Setup ( x => x . Get < V1Service > ( "ingress-nginx-controller" , "ingress-nginx" ) )
91+ . Returns ( new V1Service { Metadata = new V1ObjectMeta { Name = "svc" , NamespaceProperty = "ns" } } ) ;
92+ _kubeClientMock . Setup ( x => x . Get < V1ConfigMap > ( "coredns" , "kube-system" ) )
93+ . Returns ( ( V1ConfigMap ? ) null ) ;
94+ var client = new ReverseProxyClient ( _dockerMock . Object , _clientFunc , _consoleMock . Object , _kindMock . Object ) ;
95+
96+ // Act
97+ var result = InvokePatchCoreDns ( client , "test-cluster" ) ;
98+
99+ // Assert
100+ Assert . False ( result ) ;
101+ _consoleMock . Verify ( x => x . WriteError ( It . Is < string > ( s => s . Contains ( "CoreDNS configmap not found" ) ) ) , Times . Once ) ;
102+ }
103+
104+ [ Fact ]
105+ public void PatchCoreDns_ReturnsFalse_WhenCorefileMissing ( )
106+ {
107+ // Arrange
108+ _kubeClientMock . Setup ( x => x . Get < V1Service > ( "ingress-nginx-controller" , "ingress-nginx" ) )
109+ . Returns ( new V1Service { Metadata = new V1ObjectMeta { Name = "svc" , NamespaceProperty = "ns" } } ) ;
110+ _kubeClientMock . Setup ( x => x . Get < V1ConfigMap > ( "coredns" , "kube-system" ) )
111+ . Returns ( new V1ConfigMap { Data = new Dictionary < string , string > ( ) } ) ;
112+ var client = new ReverseProxyClient ( _dockerMock . Object , _clientFunc , _consoleMock . Object , _kindMock . Object ) ;
113+
114+ // Act
115+ var result = InvokePatchCoreDns ( client , "test-cluster" ) ;
116+
117+ // Assert
118+ Assert . False ( result ) ;
119+ _consoleMock . Verify ( x => x . WriteError ( It . Is < string > ( s => s . Contains ( "CoreDNS Corefile not found" ) ) ) , Times . Once ) ;
120+ }
121+
122+ [ Fact ]
123+ public void PatchCoreDns_ReturnsTrue_WhenRewriteAlreadyExists ( )
124+ {
125+ // Arrange
126+ var clusterName = "test-cluster" ;
127+ var rewriteString = $ " rewrite name { clusterName } .dev-k8s.cloud svc.ns.svc.cluster.local";
128+ var corefile = $ "kubernetes cluster.local in-addr.arpa ip6.arpa {{\n }}\n { rewriteString } \n ";
129+ _kubeClientMock . Setup ( x => x . Get < V1Service > ( "ingress-nginx-controller" , "ingress-nginx" ) )
130+ . Returns ( new V1Service { Metadata = new V1ObjectMeta { Name = "svc" , NamespaceProperty = "ns" } } ) ;
131+ _kubeClientMock . Setup ( x => x . Get < V1ConfigMap > ( "coredns" , "kube-system" ) )
132+ . Returns ( new V1ConfigMap { Data = new Dictionary < string , string > { { "Corefile" , corefile } } } ) ;
133+ var client = new ReverseProxyClient ( _dockerMock . Object , _clientFunc , _consoleMock . Object , _kindMock . Object ) ;
134+
135+ // Act
136+ var result = InvokePatchCoreDns ( client , clusterName ) ;
137+
138+ // Assert
139+ Assert . True ( result ) ;
140+ _consoleMock . Verify ( x => x . WriteLine ( It . Is < string > ( s => s . Contains ( "already contains the rewrite entry" ) ) ) , Times . Once ) ;
141+ }
142+
143+ [ Fact ]
144+ public void PatchCoreDns_ReturnsFalse_WhenNoKubernetesBlock ( )
145+ {
146+ // Arrange
147+ var corefile = "some unrelated config" ;
148+ _kubeClientMock . Setup ( x => x . Get < V1Service > ( "ingress-nginx-controller" , "ingress-nginx" ) )
149+ . Returns ( new V1Service { Metadata = new V1ObjectMeta { Name = "svc" , NamespaceProperty = "ns" } } ) ;
150+ _kubeClientMock . Setup ( x => x . Get < V1ConfigMap > ( "coredns" , "kube-system" ) )
151+ . Returns ( new V1ConfigMap { Data = new Dictionary < string , string > { { "Corefile" , corefile } } } ) ;
152+ var client = new ReverseProxyClient ( _dockerMock . Object , _clientFunc , _consoleMock . Object , _kindMock . Object ) ;
153+
154+ // Act
155+ var result = InvokePatchCoreDns ( client , "test-cluster" ) ;
156+
157+ // Assert
158+ Assert . False ( result ) ;
159+ _consoleMock . Verify ( x => x . WriteError ( It . Is < string > ( s => s . Contains ( "does not contain a kubernetes block" ) ) ) , Times . Once ) ;
160+ }
161+
162+ [ Fact ]
163+ public void PatchCoreDns_ReturnsFalse_WhenNoClosingBrace ( )
164+ {
165+ // Arrange
166+ var corefile = "kubernetes cluster.local in-addr.arpa ip6.arpa {" ;
167+ _kubeClientMock . Setup ( x => x . Get < V1Service > ( "ingress-nginx-controller" , "ingress-nginx" ) )
168+ . Returns ( new V1Service { Metadata = new V1ObjectMeta { Name = "svc" , NamespaceProperty = "ns" } } ) ;
169+ _kubeClientMock . Setup ( x => x . Get < V1ConfigMap > ( "coredns" , "kube-system" ) )
170+ . Returns ( new V1ConfigMap { Data = new Dictionary < string , string > { { "Corefile" , corefile } } } ) ;
171+ var client = new ReverseProxyClient ( _dockerMock . Object , _clientFunc , _consoleMock . Object , _kindMock . Object ) ;
172+
173+ // Act
174+ var result = InvokePatchCoreDns ( client , "test-cluster" ) ;
175+
176+ // Assert
177+ Assert . False ( result ) ;
178+ _consoleMock . Verify ( x => x . WriteError ( It . Is < string > ( s => s . Contains ( "does not contain a closing brace" ) ) ) , Times . Once ) ;
179+ }
180+
181+ [ Fact ]
182+ public void PatchCoreDns_UpdatesConfigMapAndRestartsPods ( )
183+ {
184+ // Arrange
185+ var clusterName = "test-cluster" ;
186+ var corefile = $ "kubernetes cluster.local in-addr.arpa ip6.arpa {{{Environment.NewLine}}}{ Environment . NewLine } ";
187+ var configMap = new V1ConfigMap { Data = new Dictionary < string , string > { { "Corefile" , corefile } } } ;
188+ var pod = new V1Pod { Metadata = new V1ObjectMeta { Name = "coredns-1" } } ;
189+ _kubeClientMock . Setup ( x => x . Get < V1Service > ( "ingress-nginx-controller" , "ingress-nginx" ) )
190+ . Returns ( new V1Service { Metadata = new V1ObjectMeta { Name = "svc" , NamespaceProperty = "ns" } } ) ;
191+ _kubeClientMock . Setup ( x => x . Get < V1ConfigMap > ( "coredns" , "kube-system" ) )
192+ . Returns ( configMap ) ;
193+ _kubeClientMock . Setup ( x => x . List < V1Pod > ( "kube-system" , It . IsAny < string > ( ) ) )
194+ . Returns ( new List < V1Pod > { pod } ) ;
195+ var client = new ReverseProxyClient ( _dockerMock . Object , _clientFunc , _consoleMock . Object , _kindMock . Object ) ;
196+
197+ // Act
198+ var result = InvokePatchCoreDns ( client , clusterName ) ;
199+
200+ // Assert
201+ Assert . True ( result ) ;
202+ _kubeClientMock . Verify ( x => x . Update ( It . Is < V1ConfigMap > ( cm => cm . Data [ "Corefile" ] . Contains ( $ "rewrite name { clusterName } .dev-k8s.cloud svc.ns.svc.cluster.local") ) ) , Times . Once ) ;
203+ _kubeClientMock . Verify ( x => x . Delete ( pod ) , Times . Once ) ;
204+ _consoleMock . Verify ( x => x . WriteLine ( It . Is < string > ( s => s . Contains ( "CoreDNS configmap updated successfully." ) ) ) , Times . Once ) ;
205+ }
206+
207+ // Helper to invoke private PatchCoreDns via reflection
208+ private static bool InvokePatchCoreDns ( ReverseProxyClient client , string clusterName )
209+ {
210+ var method = typeof ( ReverseProxyClient ) . GetMethod ( "PatchCoreDns" , System . Reflection . BindingFlags . NonPublic | System . Reflection . BindingFlags . Instance ) ;
211+ return ( bool ) method . Invoke ( client , new object [ ] { clusterName } ) ;
212+ }
69213 }
70214}
0 commit comments