Skip to content

Commit 51cb4f9

Browse files
committed
test: Add findmnt package
When testing mounts we can use findmnt --json output to parse the output cleanly. The package provides only ParseOutput() now, but it can be extended later to run the findmnt command.
1 parent 358a142 commit 51cb4f9

File tree

4 files changed

+593
-0
lines changed

4 files changed

+593
-0
lines changed

test/integration/findmnt/findmnt.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//go:build integration
2+
3+
/*
4+
Copyright 2025 The Kubernetes Authors All rights reserved.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
19+
// package parse findmnt command results.
20+
package findmnt
21+
22+
import (
23+
"encoding/json"
24+
"slices"
25+
)
26+
27+
// Filesystem is a findmnt --json filesystem node. It may include children
28+
// filesystems.
29+
type Filesystem struct {
30+
Target string `json:"target"`
31+
Source string `json:"source"`
32+
FSType string `json:"fstype"`
33+
Options string `json:"options"`
34+
Children []Filesystem `json:"children,omitempty"`
35+
}
36+
37+
// Result if findmnt --json result.
38+
type Result struct {
39+
Filesystems []Filesystem `json:"filesystems"`
40+
}
41+
42+
// ParseOutput parse findmnt --json output.
43+
func ParseOutput(output []byte) (*Result, error) {
44+
r := &Result{}
45+
if err := json.Unmarshal(output, r); err != nil {
46+
return nil, err
47+
}
48+
return r, nil
49+
}
50+
51+
func (r *Result) Equal(other *Result) bool {
52+
if r == other {
53+
return true
54+
}
55+
if other == nil {
56+
return false
57+
}
58+
if !slices.EqualFunc(r.Filesystems, other.Filesystems, func(a, b Filesystem) bool {
59+
return a.Equal(&b)
60+
}) {
61+
return false
62+
}
63+
return true
64+
}
65+
66+
func (f *Filesystem) Equal(other *Filesystem) bool {
67+
if f == other {
68+
return true
69+
}
70+
if other == nil {
71+
return false
72+
}
73+
if f.Target != other.Target {
74+
return false
75+
}
76+
if f.Source != other.Source {
77+
return false
78+
}
79+
if f.FSType != other.FSType {
80+
return false
81+
}
82+
if !slices.EqualFunc(f.Children, other.Children, func(a, b Filesystem) bool {
83+
return a.Equal(&b)
84+
}) {
85+
return false
86+
}
87+
return true
88+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
//go:build integration
2+
3+
/*
4+
Copyright 2025 The Kubernetes Authors All rights reserved.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
19+
package findmnt_test
20+
21+
import (
22+
"os"
23+
"testing"
24+
25+
"k8s.io/minikube/test/integration/findmnt"
26+
)
27+
28+
func TestParseAllMounts(t *testing.T) {
29+
// Output from `findmnt --json` command.
30+
output, err := os.ReadFile("testdata/findmnt.json")
31+
if err != nil {
32+
t.Fatal(err)
33+
}
34+
result, err := findmnt.ParseOutput(output)
35+
if err != nil {
36+
t.Fatal(err)
37+
}
38+
39+
assert(t, len(result.Filesystems), 1)
40+
41+
root := result.Filesystems[0]
42+
assert(t, root.Target, "/")
43+
assert(t, root.Source, "tmpfs")
44+
assert(t, root.FSType, "tmpfs")
45+
assert(t, root.Options, "rw,relatime,size=5469192k")
46+
assert(t, len(root.Children), 20)
47+
48+
dev := root.Children[0]
49+
assert(t, dev.Target, "/dev")
50+
assert(t, dev.Source, "devtmpfs")
51+
assert(t, dev.FSType, "devtmpfs")
52+
assert(t, dev.Options, "rw,relatime,size=2838500k,nr_inodes=709625,mode=755")
53+
assert(t, len(dev.Children), 4)
54+
55+
devShm := dev.Children[0]
56+
assert(t, devShm.Target, "/dev/shm")
57+
assert(t, devShm.Source, "tmpfs")
58+
assert(t, devShm.FSType, "tmpfs")
59+
assert(t, devShm.Options, "rw,nosuid,nodev")
60+
}
61+
62+
func TestParseSingle(t *testing.T) {
63+
// Output from `findmnt --json /proc` command.
64+
output, err := os.ReadFile("testdata/findmnt-proc.json")
65+
if err != nil {
66+
t.Fatal(err)
67+
}
68+
result, err := findmnt.ParseOutput(output)
69+
if err != nil {
70+
t.Fatal(err)
71+
}
72+
expected := &findmnt.Result{
73+
Filesystems: []findmnt.Filesystem{
74+
{
75+
Target: "/proc",
76+
Source: "proc",
77+
FSType: "proc",
78+
Options: "rw,relatime",
79+
},
80+
},
81+
}
82+
if !result.Equal(expected) {
83+
t.Fatalf("expected %+v, got %+v", expected, result)
84+
}
85+
}
86+
87+
func assert[T comparable](t *testing.T, a, b T) {
88+
if a != b {
89+
t.Fatalf("expected \"%v\", got \"%v\"", b, a)
90+
}
91+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"filesystems": [
3+
{
4+
"target": "/proc",
5+
"source": "proc",
6+
"fstype": "proc",
7+
"options": "rw,relatime"
8+
}
9+
]
10+
}

0 commit comments

Comments
 (0)