1// Copyright 2019 The Prometheus Authors 2// Licensed under the Apache License, Version 2.0 (the "License"); 3// you may not use this file except in compliance with the License. 4// You may obtain a copy of the License at 5// 6// http://www.apache.org/licenses/LICENSE-2.0 7// 8// Unless required by applicable law or agreed to in writing, software 9// distributed under the License is distributed on an "AS IS" BASIS, 10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11// See the License for the specific language governing permissions and 12// limitations under the License. 13package procfs 14 15import ( 16 "reflect" 17 "testing" 18) 19 20func TestMountInfo(t *testing.T) { 21 tests := []struct { 22 name string 23 s string 24 mount *MountInfo 25 invalid bool 26 }{ 27 { 28 name: "Regular sysfs mounted at /sys", 29 s: "16 21 0:16 / /sys rw,nosuid,nodev,noexec,relatime shared:7 - sysfs sysfs rw", 30 invalid: false, 31 mount: &MountInfo{ 32 MountID: 16, 33 ParentID: 21, 34 MajorMinorVer: "0:16", 35 Root: "/", 36 MountPoint: "/sys", 37 Options: map[string]string{"rw": "", "nosuid": "", "nodev": "", "noexec": "", "relatime": ""}, 38 OptionalFields: map[string]string{"shared": "7"}, 39 FSType: "sysfs", 40 Source: "sysfs", 41 SuperOptions: map[string]string{"rw": ""}, 42 }, 43 }, 44 { 45 name: "Not enough information", 46 s: "hello", 47 invalid: true, 48 }, 49 { 50 name: "Tmpfs mounted at /run", 51 s: "225 20 0:39 / /run/user/112 rw,nosuid,nodev,relatime shared:177 - tmpfs tmpfs rw,size=405096k,mode=700,uid=112,gid=116", 52 mount: &MountInfo{ 53 MountID: 225, 54 ParentID: 20, 55 MajorMinorVer: "0:39", 56 Root: "/", 57 MountPoint: "/run/user/112", 58 Options: map[string]string{"rw": "", "nosuid": "", "nodev": "", "relatime": ""}, 59 OptionalFields: map[string]string{"shared": "177"}, 60 FSType: "tmpfs", 61 Source: "tmpfs", 62 SuperOptions: map[string]string{"rw": "", "size": "405096k", "mode": "700", "uid": "112", "gid": "116"}, 63 }, 64 invalid: false, 65 }, 66 { 67 name: "Tmpfs mounted at /run, but no optional values", 68 s: "225 20 0:39 / /run/user/112 rw,nosuid,nodev,relatime - tmpfs tmpfs rw,size=405096k,mode=700,uid=112,gid=116", 69 mount: &MountInfo{ 70 MountID: 225, 71 ParentID: 20, 72 MajorMinorVer: "0:39", 73 Root: "/", 74 MountPoint: "/run/user/112", 75 Options: map[string]string{"rw": "", "nosuid": "", "nodev": "", "relatime": ""}, 76 OptionalFields: nil, 77 FSType: "tmpfs", 78 Source: "tmpfs", 79 SuperOptions: map[string]string{"rw": "", "size": "405096k", "mode": "700", "uid": "112", "gid": "116"}, 80 }, 81 invalid: false, 82 }, 83 { 84 name: "Tmpfs mounted at /run, with multiple optional values", 85 s: "225 20 0:39 / /run/user/112 rw,nosuid,nodev,relatime shared:177 master:8 - tmpfs tmpfs rw,size=405096k,mode=700,uid=112,gid=116", 86 mount: &MountInfo{ 87 MountID: 225, 88 ParentID: 20, 89 MajorMinorVer: "0:39", 90 Root: "/", 91 MountPoint: "/run/user/112", 92 Options: map[string]string{"rw": "", "nosuid": "", "nodev": "", "relatime": ""}, 93 OptionalFields: map[string]string{"shared": "177", "master": "8"}, 94 FSType: "tmpfs", 95 Source: "tmpfs", 96 SuperOptions: map[string]string{"rw": "", "size": "405096k", "mode": "700", "uid": "112", "gid": "116"}, 97 }, 98 invalid: false, 99 }, 100 { 101 name: "Tmpfs mounted at /run, with a mixture of valid and invalid optional values", 102 s: "225 20 0:39 / /run/user/112 rw,nosuid,nodev,relatime shared:177 master:8 foo:bar - tmpfs tmpfs rw,size=405096k,mode=700,uid=112,gid=116", 103 mount: &MountInfo{ 104 MountID: 225, 105 ParentID: 20, 106 MajorMinorVer: "0:39", 107 Root: "/", 108 MountPoint: "/run/user/112", 109 Options: map[string]string{"rw": "", "nosuid": "", "nodev": "", "relatime": ""}, 110 OptionalFields: map[string]string{"shared": "177", "master": "8"}, 111 FSType: "tmpfs", 112 Source: "tmpfs", 113 SuperOptions: map[string]string{"rw": "", "size": "405096k", "mode": "700", "uid": "112", "gid": "116"}, 114 }, 115 invalid: false, 116 }, 117 { 118 name: "CIFS mounted at /with/a-hyphen", 119 s: "454 29 0:87 / /with/a-hyphen rw,relatime shared:255 - cifs //remote-storage/Path rw,vers=3.1.1,cache=strict,username=user,uid=1000,forceuid,gid=0,noforcegid,addr=127.0.0.1,file_mode=0755,dir_mode=0755,soft,nounix,serverino,mapposix,echo_interval=60,actimeo=1", 120 mount: &MountInfo{ 121 MountID: 454, 122 ParentID: 29, 123 MajorMinorVer: "0:87", 124 Root: "/", 125 MountPoint: "/with/a-hyphen", 126 Options: map[string]string{"rw": "", "relatime": ""}, 127 OptionalFields: map[string]string{"shared": "255"}, 128 FSType: "cifs", 129 Source: "//remote-storage/Path", 130 SuperOptions: map[string]string{"rw": "", "vers": "3.1.1", "cache": "strict", "username": "user", "uid": "1000", "forceuid": "", "gid": "0", "noforcegid": "", "addr": "127.0.0.1", "file_mode": "0755", "dir_mode": "0755", "soft": "", "nounix": "", "serverino": "", "mapposix": "", "echo_interval": "60", "actimeo": "1"}, 131 }, 132 invalid: false, 133 }, 134 { 135 name: "Docker overlay with 10 fields (no optional fields)", 136 s: "137 45 253:2 /lib/docker/overlay2 /var/lib/docker/overlay2 rw,relatime - ext4 /dev/mapper/vg0-lv_var rw,data=ordered", 137 mount: &MountInfo{ 138 MountID: 137, 139 ParentID: 45, 140 MajorMinorVer: "253:2", 141 Root: "/lib/docker/overlay2", 142 MountPoint: "/var/lib/docker/overlay2", 143 Options: map[string]string{"rw": "", "relatime": ""}, 144 OptionalFields: map[string]string{}, 145 FSType: "ext4", 146 Source: "/dev/mapper/vg0-lv_var", 147 SuperOptions: map[string]string{"rw": "", "data": "ordered"}, 148 }, 149 }, 150 { 151 name: "bind chroot bind mount with 10 fields (no optional fields)", 152 s: "157 47 253:2 /etc/named /var/named/chroot/etc/named rw,relatime - ext4 /dev/mapper/vg0-lv_root rw,data=ordered", 153 mount: &MountInfo{ 154 MountID: 157, 155 ParentID: 47, 156 MajorMinorVer: "253:2", 157 Root: "/etc/named", 158 MountPoint: "/var/named/chroot/etc/named", 159 Options: map[string]string{"rw": "", "relatime": ""}, 160 OptionalFields: map[string]string{}, 161 FSType: "ext4", 162 Source: "/dev/mapper/vg0-lv_root", 163 SuperOptions: map[string]string{"rw": "", "data": "ordered"}, 164 }, 165 }, 166 } 167 168 for i, test := range tests { 169 t.Logf("[%02d] test %q", i, test.name) 170 171 mount, err := parseMountInfoString(test.s) 172 173 if test.invalid && err == nil { 174 t.Error("expected an error, but none occurred") 175 } 176 if !test.invalid && err != nil { 177 t.Errorf("unexpected error: %v", err) 178 } 179 180 if want, have := test.mount, mount; !reflect.DeepEqual(want, have) { 181 t.Errorf("mounts:\nwant:\n%+v\nhave:\n%+v", want, have) 182 } 183 } 184} 185