Skip to content

Commit ec94952

Browse files
Copilotbehzad-mir
andcommitted
Add unit tests for createHostNCApipaNetwork and apply changes from PR #3693
Co-authored-by: behzad-mir <[email protected]>
1 parent ee87e99 commit ec94952

File tree

2 files changed

+103
-1
lines changed

2 files changed

+103
-1
lines changed

cns/hnsclient/hnsclient_windows.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//go:build windows
2+
// +build windows
3+
14
package hnsclient
25

36
import (
@@ -53,6 +56,9 @@ const (
5356
// Name of the loopback adapter needed to create Host NC apipa network
5457
hostNCLoopbackAdapterName = "LoopbackAdapterHostNCConnectivity"
5558

59+
// Name of the loopback adapter created by HNS for Host NC apipa network
60+
vEthernethostNCLoopbackAdapterName = "vEthernet (" + hostNCLoopbackAdapterName + ")"
61+
5662
// HNS rehydration issue requires this GW to be different than the loopback adapter ip, so we set it to .2
5763
defaultHnsGwIPAddress = "169.254.128.2"
5864
hnsLoopbackAdapterIPAddress = "169.254.128.1"
@@ -301,7 +307,12 @@ func createHostNCApipaNetwork(
301307
}
302308

303309
// Create loopback adapter needed for this HNS network
304-
if interfaceExists, _ := networkcontainers.InterfaceExists(hostNCLoopbackAdapterName); !interfaceExists {
310+
// We need to first check the existence of either "LoopbackAdapterHostNCConnectivity" or the vEthernet(LoopbackAdapterHostNCConnectivity) interfaces
311+
// If neither exists, we create the loopback adapter with the specified IP configuration.
312+
shouldCreate, logMessage := shouldCreateLoopbackAdapter(networkcontainers.InterfaceExists)
313+
logger.Printf(logMessage)
314+
315+
if shouldCreate {
305316
ipconfig := cns.IPConfiguration{
306317
IPSubnet: cns.IPSubnet{
307318
IPAddress: hnsLoopbackAdapterIPAddress,
@@ -339,6 +350,24 @@ func createHostNCApipaNetwork(
339350
return network, err
340351
}
341352

353+
// shouldCreateLoopbackAdapter determines whether a loopback adapter should be created
354+
// based on the existence of either the hostNCLoopbackAdapterName or vEthernethostNCLoopbackAdapterName interfaces
355+
func shouldCreateLoopbackAdapter(
356+
interfaceExistsFunc func(string) (bool, error)) (bool, string) {
357+
loopbackInterfaceExists, _ := interfaceExistsFunc(hostNCLoopbackAdapterName)
358+
vethernetLoopbackInterfaceExists, _ := interfaceExistsFunc(vEthernethostNCLoopbackAdapterName)
359+
360+
if loopbackInterfaceExists {
361+
return false, hostNCLoopbackAdapterName + " already created, skipping loopback interface creation"
362+
}
363+
if vethernetLoopbackInterfaceExists {
364+
return false, vEthernethostNCLoopbackAdapterName + " already created, skipping loopback interface creation"
365+
}
366+
367+
// Neither interface exists, so we should create the loopback adapter
368+
return true, "Creating loopback adapter"
369+
}
370+
342371
// LogNetworkInterfaces logs the host's network interfaces in the default namespace.
343372
func LogNetworkInterfaces() {
344373
interfaces, err := net.Interfaces()

cns/hnsclient/hnsclient_windows_test.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//go:build windows
2+
// +build windows
3+
14
package hnsclient
25

36
import (
@@ -33,3 +36,73 @@ func TestAdhocAdjustIPConfig(t *testing.T) {
3336
})
3437
}
3538
}
39+
40+
func TestShouldCreateLoopbackAdapter(t *testing.T) {
41+
tests := []struct {
42+
name string
43+
hostNCExists bool
44+
vEthernetHostNCExists bool
45+
expectedShouldCreate bool
46+
expectedLogMessagePrefix string
47+
}{
48+
{
49+
name: "should create when neither interface exists",
50+
hostNCExists: false,
51+
vEthernetHostNCExists: false,
52+
expectedShouldCreate: true,
53+
expectedLogMessagePrefix: "Creating loopback adapter",
54+
},
55+
{
56+
name: "should not create when hostNCLoopbackAdapterName exists",
57+
hostNCExists: true,
58+
vEthernetHostNCExists: false,
59+
expectedShouldCreate: false,
60+
expectedLogMessagePrefix: "LoopbackAdapterHostNCConnectivity already created",
61+
},
62+
{
63+
name: "should not create when vEthernethostNCLoopbackAdapterName exists",
64+
hostNCExists: false,
65+
vEthernetHostNCExists: true,
66+
expectedShouldCreate: false,
67+
expectedLogMessagePrefix: "vEthernet (LoopbackAdapterHostNCConnectivity) already created",
68+
},
69+
{
70+
name: "should not create when both interfaces exist - prioritizes hostNCLoopbackAdapterName",
71+
hostNCExists: true,
72+
vEthernetHostNCExists: true,
73+
expectedShouldCreate: false,
74+
expectedLogMessagePrefix: "LoopbackAdapterHostNCConnectivity already created",
75+
},
76+
}
77+
78+
for _, tt := range tests {
79+
tt := tt
80+
t.Run(tt.name, func(t *testing.T) {
81+
// Create mock interface exists function
82+
mockInterfaceExists := func(interfaceName string) (bool, error) {
83+
switch interfaceName {
84+
case hostNCLoopbackAdapterName:
85+
return tt.hostNCExists, nil
86+
case vEthernethostNCLoopbackAdapterName:
87+
return tt.vEthernetHostNCExists, nil
88+
default:
89+
return false, nil
90+
}
91+
}
92+
93+
shouldCreate, logMessage := shouldCreateLoopbackAdapter(mockInterfaceExists)
94+
95+
assert.Equal(t, tt.expectedShouldCreate, shouldCreate)
96+
assert.Contains(t, logMessage, tt.expectedLogMessagePrefix)
97+
})
98+
}
99+
}
100+
101+
func TestConstants(t *testing.T) {
102+
// Test that the vEthernet constant is constructed correctly
103+
expectedVEthernetName := "vEthernet (LoopbackAdapterHostNCConnectivity)"
104+
assert.Equal(t, expectedVEthernetName, vEthernethostNCLoopbackAdapterName)
105+
106+
// Test that the hostNCLoopbackAdapterName constant is as expected
107+
assert.Equal(t, "LoopbackAdapterHostNCConnectivity", hostNCLoopbackAdapterName)
108+
}

0 commit comments

Comments
 (0)