Skip to content

Commit fb46b78

Browse files
committed
test(internal/procfs/sysfs): add unit test for net_class
1 parent 6c530f2 commit fb46b78

1 file changed

Lines changed: 228 additions & 0 deletions

File tree

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
// Copyright 2026 The HuaTuo Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package sysfs
16+
17+
import (
18+
"os"
19+
"path/filepath"
20+
"strings"
21+
"testing"
22+
23+
"huatuo-bamai/internal/procfs"
24+
25+
"github.com/stretchr/testify/assert"
26+
"github.com/stretchr/testify/require"
27+
)
28+
29+
func TestDefaultNetClassDevices_Filesystem(t *testing.T) {
30+
tests := []struct {
31+
name string
32+
setup func(t *testing.T) string
33+
want []string
34+
wantErr bool
35+
errContains string
36+
}{
37+
{
38+
name: "multiple devices",
39+
setup: func(t *testing.T) string {
40+
tmpDir := t.TempDir()
41+
netPath := filepath.Join(tmpDir, "sys", "class", "net")
42+
require.NoError(t, os.MkdirAll(netPath, 0o755))
43+
44+
for _, dev := range []string{"eth0", "eth1", "lo"} {
45+
require.NoError(t, os.Mkdir(filepath.Join(netPath, dev), 0o755))
46+
}
47+
return tmpDir
48+
},
49+
want: []string{"eth0", "eth1", "lo"},
50+
wantErr: false,
51+
},
52+
{
53+
name: "no devices",
54+
setup: func(t *testing.T) string {
55+
tmpDir := t.TempDir()
56+
netPath := filepath.Join(tmpDir, "sys", "class", "net")
57+
require.NoError(t, os.MkdirAll(netPath, 0o755))
58+
return tmpDir
59+
},
60+
want: []string{},
61+
wantErr: false,
62+
},
63+
{
64+
name: "ignores regular files",
65+
setup: func(t *testing.T) string {
66+
tmpDir := t.TempDir()
67+
netPath := filepath.Join(tmpDir, "sys", "class", "net")
68+
require.NoError(t, os.MkdirAll(netPath, 0o755))
69+
require.NoError(t, os.Mkdir(filepath.Join(netPath, "eth0"), 0o755))
70+
require.NoError(t, os.WriteFile(filepath.Join(netPath, "file.txt"), []byte("test"), 0o600))
71+
return tmpDir
72+
},
73+
want: []string{"eth0"},
74+
wantErr: false,
75+
},
76+
{
77+
name: "device names with special characters",
78+
setup: func(t *testing.T) string {
79+
tmpDir := t.TempDir()
80+
netPath := filepath.Join(tmpDir, "sys", "class", "net")
81+
require.NoError(t, os.MkdirAll(netPath, 0o755))
82+
83+
specialDevs := []string{"eth0.1", "vlan@100", "br-123456"}
84+
for _, dev := range specialDevs {
85+
require.NoError(t, os.Mkdir(filepath.Join(netPath, dev), 0o755))
86+
}
87+
return tmpDir
88+
},
89+
want: []string{"eth0.1", "vlan@100", "br-123456"},
90+
wantErr: false,
91+
},
92+
}
93+
94+
originalPrefix := strings.TrimSuffix(DefaultPath(), "sys")
95+
defer func() { procfs.RootPrefix(originalPrefix) }()
96+
97+
for _, tt := range tests {
98+
t.Run(tt.name, func(t *testing.T) {
99+
procfs.RootPrefix(tt.setup(t))
100+
101+
devices, err := DefaultNetClassDevices()
102+
103+
if tt.wantErr {
104+
assert.Error(t, err)
105+
} else {
106+
assert.NoError(t, err)
107+
assert.ElementsMatch(t, tt.want, devices)
108+
}
109+
})
110+
}
111+
}
112+
113+
func TestDefaultNetClass_Filesystem(t *testing.T) {
114+
tests := []struct {
115+
name string
116+
setup func(t *testing.T) string
117+
wantErr bool
118+
validate func(*testing.T, NetClass)
119+
}{
120+
{
121+
name: "valid net class with devices",
122+
setup: func(t *testing.T) string {
123+
tmpDir := t.TempDir()
124+
sysPath := filepath.Join(tmpDir, "sys")
125+
126+
// Create eth0 device with attributes
127+
eth0Path := filepath.Join(sysPath, "class", "net", "eth0")
128+
require.NoError(t, os.MkdirAll(eth0Path, 0o755))
129+
require.NoError(t, os.WriteFile(filepath.Join(eth0Path, "address"), []byte("00:11:22:33:44:55"), 0o600))
130+
require.NoError(t, os.WriteFile(filepath.Join(eth0Path, "mtu"), []byte("1500"), 0o600))
131+
require.NoError(t, os.WriteFile(filepath.Join(eth0Path, "operstate"), []byte("up"), 0o600))
132+
133+
// Create lo device with attributes
134+
loPath := filepath.Join(sysPath, "class", "net", "lo")
135+
require.NoError(t, os.MkdirAll(loPath, 0o755))
136+
require.NoError(t, os.WriteFile(filepath.Join(loPath, "address"), []byte("00:00:00:00:00:00"), 0o600))
137+
require.NoError(t, os.WriteFile(filepath.Join(loPath, "mtu"), []byte("65536"), 0o600))
138+
require.NoError(t, os.WriteFile(filepath.Join(loPath, "operstate"), []byte("unknown"), 0o600))
139+
140+
return tmpDir
141+
},
142+
validate: func(t *testing.T, nc NetClass) {
143+
assert.NotNil(t, nc)
144+
145+
// Verify eth0 exists
146+
eth0, ok := nc["eth0"]
147+
assert.True(t, ok, "eth0 should exist in NetClass")
148+
assert.Equal(t, "eth0", eth0.Name)
149+
assert.Equal(t, "00:11:22:33:44:55", eth0.Address)
150+
assert.NotNil(t, eth0.MTU)
151+
assert.Equal(t, int64(1500), *eth0.MTU)
152+
assert.Equal(t, "up", eth0.OperState)
153+
154+
// Verify eth0.Speed is not exist
155+
assert.Nil(t, eth0.Speed)
156+
157+
// Verify lo exists
158+
lo, ok := nc["lo"]
159+
assert.True(t, ok, "lo should exist in NetClass")
160+
assert.Equal(t, "lo", lo.Name)
161+
assert.Equal(t, "00:00:00:00:00:00", lo.Address)
162+
assert.NotNil(t, lo.MTU)
163+
assert.Equal(t, int64(65536), *lo.MTU)
164+
assert.Equal(t, "unknown", lo.OperState)
165+
166+
// Verify we have 2 devices
167+
assert.Len(t, nc, 2)
168+
},
169+
},
170+
{
171+
name: "empty net class",
172+
setup: func(t *testing.T) string {
173+
tmpDir := t.TempDir()
174+
sysPath := filepath.Join(tmpDir, "sys")
175+
netPath := filepath.Join(sysPath, "class", "net")
176+
require.NoError(t, os.MkdirAll(netPath, 0o755))
177+
return tmpDir
178+
},
179+
validate: func(t *testing.T, nc NetClass) {
180+
assert.NotNil(t, nc)
181+
assert.Empty(t, nc, "NetClass should be empty when no devices exist")
182+
},
183+
},
184+
}
185+
186+
originalPrefix := strings.TrimSuffix(DefaultPath(), "sys")
187+
defer func() { procfs.RootPrefix(originalPrefix) }()
188+
189+
for _, tt := range tests {
190+
t.Run(tt.name, func(t *testing.T) {
191+
procfs.RootPrefix(tt.setup(t))
192+
193+
netClass, err := DefaultNetClass()
194+
assert.NoError(t, err)
195+
tt.validate(t, netClass)
196+
})
197+
}
198+
}
199+
200+
// Integration Tests (Real Environment)
201+
// TEST_INTEGRATION=true go test -v ./internal/procfs/sysfs/...
202+
func TestDefaultNetClassDevices_Integration(t *testing.T) {
203+
if os.Getenv("TEST_INTEGRATION") == "" {
204+
t.Skip("Set TEST_INTEGRATION=true to run integration tests")
205+
}
206+
207+
devices, err := DefaultNetClassDevices()
208+
if err != nil {
209+
t.Skipf("/sys/class/net not available: %v", err)
210+
}
211+
212+
assert.NotEmpty(t, devices, "should have at least one network device")
213+
t.Logf("Found %d devices: %v", len(devices), devices)
214+
}
215+
216+
func TestDefaultNetClass_Integration(t *testing.T) {
217+
if os.Getenv("TEST_INTEGRATION") == "" {
218+
t.Skip("Set TEST_INTEGRATION=true to run integration tests")
219+
}
220+
221+
netClass, err := DefaultNetClass()
222+
if err != nil {
223+
t.Skipf("/sys/class/net not available: %v", err)
224+
}
225+
226+
assert.NotNil(t, netClass, "should have a valid NetClass object")
227+
t.Logf("Got NetClass: %+v", netClass)
228+
}

0 commit comments

Comments
 (0)