gitlab.com/apertussolutions/u-root@v7.0.0+incompatible/cmds/core/id/id_test.go (about) 1 // Copyright 2017-2018 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build !plan9 6 7 package main 8 9 import ( 10 "bytes" 11 "fmt" 12 "os/exec" 13 "sort" 14 "testing" 15 16 "github.com/u-root/u-root/pkg/testutil" 17 ) 18 19 var ( 20 logPrefixLength = len("2009/11/10 23:00:00 ") 21 ) 22 23 type test struct { 24 opt []string 25 out string 26 } 27 28 // Run the command, with the optional args, and return a string 29 // for stdout, stderr, and an error. 30 func run(c *exec.Cmd) (string, string, error) { 31 var o, e bytes.Buffer 32 c.Stdout, c.Stderr = &o, &e 33 err := c.Run() 34 return o.String(), e.String(), err 35 } 36 37 // Test incorrect invocation of id 38 func TestInvocation(t *testing.T) { 39 var tests = []test{ 40 {opt: []string{"-n"}, out: "id: cannot print only names in default format\n"}, 41 {opt: []string{"-G", "-g"}, out: "id: cannot print \"only\" of more than one choice\n"}, 42 {opt: []string{"-G", "-u"}, out: "id: cannot print \"only\" of more than one choice\n"}, 43 {opt: []string{"-g", "-u"}, out: "id: cannot print \"only\" of more than one choice\n"}, 44 {opt: []string{"-g", "-u", "-G"}, out: "id: cannot print \"only\" of more than one choice\n"}, 45 } 46 47 for _, test := range tests { 48 c := testutil.Command(t, test.opt...) 49 _, e, _ := run(c) 50 51 // Ignore the date and time because we're using Log.Fatalf 52 if e[logPrefixLength:] != test.out { 53 t.Errorf("id for '%v' failed: got '%s', want '%s'", test.opt, e, test.out) 54 } 55 } 56 } 57 58 type passwd struct { 59 name string 60 uid int 61 gid int 62 } 63 64 var passwdShould = []passwd{ 65 {"root", 0, 0}, 66 {"bin", 1, 1}, 67 {"daemon", 2, 2}, 68 {"lary", 1000, 1000}, 69 {"curly", 1001, 1001}, 70 {"moe", 1002, 2002}, 71 } 72 73 var passwdShouldnt = []passwd{ 74 {"adm", 3, 4}, 75 } 76 77 var passwdFiles = []string{ 78 "testdata/passwd-simple.txt", 79 "testdata/passwd-comments.txt", 80 } 81 82 type group struct { 83 name string 84 gid int 85 } 86 87 var groupShould = []group{ 88 {"printadmin", 997}, 89 {"ssh_keys", 996}, 90 {"rpcuser", 29}, 91 {"nfsnobody", 65534}, 92 {"sshd", 74}, 93 {"wheel", 10}, 94 } 95 96 var groupShouldnt = []group{ 97 {"bad", 314}, 98 {"wrong", 996}, 99 {"wheel", 11}, 100 } 101 102 var groupFiles = []string{ 103 "testdata/group-simple.txt", 104 "testdata/group-comments.txt", 105 } 106 107 var groupMembers = map[string][]int{ 108 "larry": {10, 74}, 109 "curly": {10, 29}, 110 "moe": {10}, 111 "joe": {}, 112 } 113 114 func passwdSame(u *Users, us passwd) error { 115 var s string 116 var d int 117 var err error 118 d, err = u.GetUID(us.name) 119 if err != nil { 120 return fmt.Errorf("failed to GetUID expected user %s: %v", us.name, err) 121 } 122 if d != us.uid { 123 return fmt.Errorf("wrong UID for %s: got %d, expected %d", us.name, d, us.uid) 124 } 125 126 d, err = u.GetGID(us.uid) 127 if err != nil { 128 return fmt.Errorf("failed to GetGID expected uid %d: %v", us.uid, err) 129 } 130 if d != us.gid { 131 return fmt.Errorf("wrong GID for uid %d: got %d, expected %d", us.uid, d, us.gid) 132 } 133 134 s, err = u.GetUser(us.uid) 135 if err != nil { 136 return fmt.Errorf("failed to GetUser expected user %s: %v", us.name, err) 137 } 138 if s != us.name { 139 return fmt.Errorf("wrong username for %d: got %s, expected %s", us.uid, s, us.name) 140 } 141 return nil 142 } 143 144 func TestUsers(t *testing.T) { 145 t.Run("non-existent passwd file", func(t *testing.T) { 146 f := "testdata/does-not-exist" 147 u, e := NewUsers(f) 148 if e == nil { 149 t.Errorf("NewUser on non-existant file should return an error") 150 } 151 if u == nil { 152 t.Errorf("NewUser should return a valid Users object, even on error") 153 } 154 }) 155 t.Run("empty passwd file", func(t *testing.T) { 156 f := "testdata/passwd-empty.txt" 157 u, e := NewUsers(f) 158 if e != nil { 159 t.Errorf("NewUser should not report error for empty passwd file") 160 } 161 if u == nil { 162 t.Errorf("NewUser should return a valid Users object even if passwd file is empty") 163 } 164 }) 165 t.Run("almost empty passwd file", func(t *testing.T) { 166 f := "testdata/passwd-newline.txt" 167 u, e := NewUsers(f) 168 if e != nil { 169 t.Errorf("NewUser should not report error for empty passwd file") 170 } 171 if u == nil { 172 t.Errorf("NewUser should return a valid Users object even if passwd file is empty") 173 } 174 }) 175 for _, f := range passwdFiles { 176 t.Run(f, func(t *testing.T) { 177 u, e := NewUsers(f) 178 if e != nil { 179 t.Errorf("NewUser should not return an error on valid file") 180 } 181 if u == nil { 182 t.Errorf("NewUser should return a valid Users object on valid file") 183 } 184 for _, us := range passwdShould { 185 if e := passwdSame(u, us); e != nil { 186 t.Errorf("%v", e) 187 } 188 } 189 for _, us := range passwdShouldnt { 190 if e := passwdSame(u, us); e == nil { 191 t.Errorf("user %s matched when it shouldn't", us.name) 192 } 193 } 194 }) 195 } 196 } 197 198 func groupSame(g *Groups, gs group) error { 199 var s string 200 var d int 201 var err error 202 203 d, err = g.GetGID(gs.name) 204 if err != nil { 205 return fmt.Errorf("failed to GetGID expected group %s: %v", gs.name, err) 206 } 207 if d != gs.gid { 208 return fmt.Errorf("wrong GID for %s: got %d, expected %d", gs.name, d, gs.gid) 209 } 210 211 s, err = g.GetGroup(gs.gid) 212 if err != nil { 213 return fmt.Errorf("failed to GetGroup expected group %s: %v", gs.name, err) 214 } 215 if s != gs.name { 216 return fmt.Errorf("wrong groupname for %d: got %s, expected %s", gs.gid, s, gs.name) 217 } 218 return nil 219 } 220 221 func TestGroups(t *testing.T) { 222 t.Run("non-existent group file", func(t *testing.T) { 223 f := "testdata/does-not-exist" 224 g, e := NewGroups(f) 225 if e == nil { 226 t.Errorf("NewGroups jnon-existant file should return an error") 227 } 228 if g == nil { 229 t.Errorf("NewGroups should return a valid Groups object, even on error") 230 } 231 }) 232 t.Run("empty group file", func(t *testing.T) { 233 f := "testdata/group-empty.txt" 234 g, e := NewGroups(f) 235 if e != nil { 236 t.Errorf("NewGroups should not report error for empty passwd file") 237 } 238 if g == nil { 239 t.Errorf("NewGroups should return a valid Users object even if passwd file is empty") 240 } 241 }) 242 t.Run("almost empty group file", func(t *testing.T) { 243 f := "testdata/group-newline.txt" 244 g, e := NewGroups(f) 245 if e != nil { 246 t.Errorf("NewGroups should not report error for empty passwd file") 247 } 248 if g == nil { 249 t.Errorf("NewGroups should return a valid Users object even if passwd file is empty") 250 } 251 }) 252 for _, f := range groupFiles { 253 t.Run(f, func(t *testing.T) { 254 g, e := NewGroups(f) 255 if e != nil { 256 t.Errorf("NewGroups should not return an error on valid file") 257 } 258 if g == nil { 259 t.Errorf("NewGroups should return a valid Users object on valid file") 260 } 261 for _, gs := range groupShould { 262 if e := groupSame(g, gs); e != nil { 263 t.Errorf("%v", e) 264 } 265 } 266 for _, gs := range groupShouldnt { 267 if e := groupSame(g, gs); e == nil { 268 t.Errorf("group %s matched when it shouldn't", gs.name) 269 } 270 } 271 for u, is := range groupMembers { 272 js := g.UserGetGIDs(u) 273 if len(js) != len(is) { 274 t.Errorf("unequal gid lists for %s: %v vs %v", u, is, js) 275 } else { 276 sort.Ints(is) 277 sort.Ints(js) 278 for i := range is { 279 if is[i] != js[i] { 280 t.Errorf("unequal gid lists for %s: %v vs %v", u, is, js) 281 } 282 } 283 } 284 } 285 }) 286 } 287 } 288 289 func TestMain(m *testing.M) { 290 testutil.Run(m, main) 291 }