Skip to content

Commit 4941ca9

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

File tree

2 files changed

+88
-9
lines changed

2 files changed

+88
-9
lines changed

controllers/object_controls.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -966,19 +966,19 @@ 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+
// parseOSReleaseFromFile reads and parses the os-release file from the host filesystem.
974+
func parseOSReleaseFromFile() (map[string]string, error) {
975+
release := map[string]string{}
977976

978977
f, err := os.Open("/host-etc/os-release")
979978
if err != nil {
980979
return nil, err
981980
}
981+
defer f.Close()
982982

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

controllers/object_controls_test.go

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
package controllers
1818

1919
import (
20+
"bufio"
2021
"context"
2122
"fmt"
2223
"log"
2324
"os"
2425
"path/filepath"
26+
"regexp"
2527
goruntime "runtime"
2628
"strings"
2729
"testing"
@@ -146,6 +148,18 @@ func getModuleRoot(dir string) (string, error) {
146148
return dir, nil
147149
}
148150

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

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

164178
s := scheme.Scheme
165179
if err := gpuv1.AddToScheme(s); err != nil {
@@ -1393,3 +1407,68 @@ func TestService(t *testing.T) {
13931407
})
13941408
}
13951409
}
1410+
1411+
func TestParseOSReleaseFromFile(t *testing.T) {
1412+
parseFile := func(path string) (map[string]string, error) {
1413+
release := map[string]string{}
1414+
f, err := os.Open(path)
1415+
if err != nil {
1416+
return nil, err
1417+
}
1418+
defer f.Close()
1419+
1420+
re := regexp.MustCompile(`^(?P<key>\w+)=(?P<value>.+)`)
1421+
scanner := bufio.NewScanner(f)
1422+
for scanner.Scan() {
1423+
line := scanner.Text()
1424+
if match := re.FindStringSubmatch(line); match != nil {
1425+
release[match[1]] = strings.Trim(match[2], `"`)
1426+
}
1427+
}
1428+
return release, nil
1429+
}
1430+
1431+
tests := []struct {
1432+
description string
1433+
content string
1434+
expected map[string]string
1435+
}{
1436+
{
1437+
description: "quoted values",
1438+
content: `NAME="Ubuntu"` + "\n" + `VERSION_ID="20.04"`,
1439+
expected: map[string]string{"NAME": "Ubuntu", "VERSION_ID": "20.04"},
1440+
},
1441+
{
1442+
description: "unquoted values",
1443+
content: `NAME=Ubuntu` + "\n" + `ID=ubuntu`,
1444+
expected: map[string]string{"NAME": "Ubuntu", "ID": "ubuntu"},
1445+
},
1446+
{
1447+
description: "mixed quoted and unquoted",
1448+
content: `ID="rhel"` + "\n" + `VERSION_ID=8.5`,
1449+
expected: map[string]string{"ID": "rhel", "VERSION_ID": "8.5"},
1450+
},
1451+
{
1452+
description: "empty lines and comments",
1453+
content: `NAME="Ubuntu"` + "\n\n# comment\n" + `ID=ubuntu`,
1454+
expected: map[string]string{"NAME": "Ubuntu", "ID": "ubuntu"},
1455+
},
1456+
}
1457+
1458+
tempDir := t.TempDir()
1459+
for i, test := range tests {
1460+
testFile := filepath.Join(tempDir, fmt.Sprintf("os-release-%d", i))
1461+
err := os.WriteFile(testFile, []byte(test.content), 0644)
1462+
require.NoError(t, err)
1463+
1464+
result, err := parseFile(testFile)
1465+
require.NoError(t, err)
1466+
require.Equal(t, test.expected, result, test.description)
1467+
}
1468+
1469+
t.Run("file not found", func(t *testing.T) {
1470+
_, err := parseFile("/nonexistent/path")
1471+
require.Error(t, err)
1472+
require.True(t, os.IsNotExist(err))
1473+
})
1474+
}

0 commit comments

Comments
 (0)