Skip to content

Commit 2db4d0a

Browse files
Replace parseOSRelease env var hack with mockable function variable
Signed-off-by: Karthik Vetrivel <[email protected]>
1 parent c5d513d commit 2db4d0a

File tree

2 files changed

+81
-10
lines changed

2 files changed

+81
-10
lines changed

controllers/object_controls.go

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -966,19 +966,22 @@ func TransformGPUDiscoveryPlugin(obj *appsv1.DaemonSet, config *gpuv1.ClusterPol
966966
return nil
967967
}
968968

969-
// Read and parse os-release file
970-
func parseOSRelease() (map[string]string, error) {
971-
release := map[string]string{}
969+
// parseOSRelease can be overridden in tests for mocking filesystem access.
970+
// In production, it reads and parses /host-etc/os-release.
971+
var parseOSRelease = parseOSReleaseFromFile
972972

973-
// TODO: mock this call instead
974-
if os.Getenv("UNIT_TEST") == "true" {
975-
return release, nil
976-
}
973+
// osReleaseFilePath is the path to the os-release file, configurable for testing.
974+
var osReleaseFilePath = "/host-etc/os-release"
975+
976+
// parseOSReleaseFromFile reads and parses the os-release file from the host filesystem.
977+
func parseOSReleaseFromFile() (map[string]string, error) {
978+
release := map[string]string{}
977979

978-
f, err := os.Open("/host-etc/os-release")
980+
f, err := os.Open(osReleaseFilePath)
979981
if err != nil {
980982
return nil, err
981983
}
984+
defer f.Close()
982985

983986
re := regexp.MustCompile(`^(?P<key>\w+)=(?P<value>.+)`)
984987

controllers/object_controls_test.go

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,18 @@ func getModuleRoot(dir string) (string, error) {
146146
return dir, nil
147147
}
148148

149+
// mockOSRelease returns a mock parseOSRelease function for testing.
150+
// It allows tests to simulate different operating systems without filesystem access.
151+
func mockOSRelease(osID, version string) func() (map[string]string, error) {
152+
return func() (map[string]string, error) {
153+
return map[string]string{
154+
"ID": osID,
155+
"VERSION_ID": version,
156+
"NAME": osID,
157+
}, nil
158+
}
159+
}
160+
149161
// setup creates a mock kubernetes cluster and client. Nodes are labeled with the minimum
150162
// required NFD labels to be detected as GPU nodes by the GPU Operator. A sample
151163
// ClusterPolicy resource is applied to the cluster. The ClusterPolicyController
@@ -158,8 +170,8 @@ func setup() error {
158170
boolTrue = new(bool)
159171
*boolTrue = true
160172

161-
// add env for calls that we cannot mock
162-
os.Setenv("UNIT_TEST", "true")
173+
// Mock parseOSRelease to avoid filesystem dependency in tests
174+
parseOSRelease = mockOSRelease("ubuntu", "20.04")
163175

164176
s := scheme.Scheme
165177
if err := gpuv1.AddToScheme(s); err != nil {
@@ -1393,3 +1405,59 @@ func TestService(t *testing.T) {
13931405
})
13941406
}
13951407
}
1408+
1409+
func TestParseOSReleaseFromFile(t *testing.T) {
1410+
tests := []struct {
1411+
description string
1412+
content string
1413+
expected map[string]string
1414+
}{
1415+
{
1416+
description: "quoted values",
1417+
content: `NAME="Ubuntu"` + "\n" + `VERSION_ID="20.04"`,
1418+
expected: map[string]string{"NAME": "Ubuntu", "VERSION_ID": "20.04"},
1419+
},
1420+
{
1421+
description: "unquoted values",
1422+
content: `NAME=Ubuntu` + "\n" + `ID=ubuntu`,
1423+
expected: map[string]string{"NAME": "Ubuntu", "ID": "ubuntu"},
1424+
},
1425+
{
1426+
description: "mixed quoted and unquoted",
1427+
content: `ID="rhel"` + "\n" + `VERSION_ID=8.5`,
1428+
expected: map[string]string{"ID": "rhel", "VERSION_ID": "8.5"},
1429+
},
1430+
{
1431+
description: "empty lines and comments",
1432+
content: `NAME="Ubuntu"` + "\n\n# comment\n" + `ID=ubuntu`,
1433+
expected: map[string]string{"NAME": "Ubuntu", "ID": "ubuntu"},
1434+
},
1435+
}
1436+
1437+
tempDir := t.TempDir()
1438+
1439+
// Save original value and restore after tests for future subsequent tests (if needed)
1440+
originalPath := osReleaseFilePath
1441+
defer func() { osReleaseFilePath = originalPath }()
1442+
1443+
for i, test := range tests {
1444+
t.Run(test.description, func(t *testing.T) {
1445+
testFile := filepath.Join(tempDir, fmt.Sprintf("os-release-%d", i))
1446+
err := os.WriteFile(testFile, []byte(test.content), 0600)
1447+
require.NoError(t, err)
1448+
1449+
// Override the path for this test
1450+
osReleaseFilePath = testFile
1451+
result, err := parseOSReleaseFromFile()
1452+
require.NoError(t, err)
1453+
require.Equal(t, test.expected, result)
1454+
})
1455+
}
1456+
1457+
t.Run("file not found", func(t *testing.T) {
1458+
osReleaseFilePath = "/nonexistent/path"
1459+
_, err := parseOSReleaseFromFile()
1460+
require.Error(t, err)
1461+
require.True(t, os.IsNotExist(err))
1462+
})
1463+
}

0 commit comments

Comments
 (0)