github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/uroot/uroot_test.go (about) 1 // Copyright 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 package uroot 6 7 import ( 8 "fmt" 9 "io/ioutil" 10 "log" 11 "os" 12 "path/filepath" 13 "reflect" 14 "syscall" 15 "testing" 16 17 "github.com/u-root/u-root/pkg/cpio" 18 "github.com/u-root/u-root/pkg/golang" 19 "github.com/u-root/u-root/pkg/uroot/builder" 20 itest "github.com/u-root/u-root/pkg/uroot/initramfs/test" 21 ) 22 23 type inMemArchive struct { 24 *cpio.Archive 25 } 26 27 // Finish implements initramfs.Writer.Finish. 28 func (inMemArchive) Finish() error { return nil } 29 30 func TestResolvePackagePaths(t *testing.T) { 31 defaultEnv := golang.Default() 32 gopath1, err := filepath.Abs("test/gopath1") 33 if err != nil { 34 t.Fatalf("failure to set up test: %v", err) 35 } 36 gopath2, err := filepath.Abs("test/gopath2") 37 if err != nil { 38 t.Fatalf("failure to set up test: %v", err) 39 } 40 gopath1Env := defaultEnv 41 gopath1Env.GOPATH = gopath1 42 gopath2Env := defaultEnv 43 gopath2Env.GOPATH = gopath2 44 everythingEnv := defaultEnv 45 everythingEnv.GOPATH = gopath1 + ":" + gopath2 46 foopath, err := filepath.Abs("test/gopath1/src/foo") 47 if err != nil { 48 t.Fatalf("failure to set up test: %v", err) 49 } 50 51 // Why doesn't the log package export this as a default? 52 l := log.New(os.Stdout, "", log.LstdFlags) 53 54 for _, tc := range []struct { 55 env golang.Environ 56 in []string 57 expected []string 58 wantErr bool 59 }{ 60 // Nonexistent Package 61 { 62 env: defaultEnv, 63 in: []string{"fakepackagename"}, 64 expected: nil, 65 wantErr: true, 66 }, 67 // Single go package import 68 { 69 env: defaultEnv, 70 in: []string{"github.com/u-root/u-root/cmds/core/ls"}, 71 // We expect the full URL format because that's the path in our default GOPATH 72 expected: []string{"github.com/u-root/u-root/cmds/core/ls"}, 73 wantErr: false, 74 }, 75 // Single package directory relative to working dir 76 { 77 env: defaultEnv, 78 in: []string{"test/gopath1/src/foo"}, 79 expected: []string{"github.com/u-root/u-root/pkg/uroot/test/gopath1/src/foo"}, 80 wantErr: false, 81 }, 82 // Single package directory with absolute path 83 { 84 env: defaultEnv, 85 in: []string{foopath}, 86 expected: []string{"github.com/u-root/u-root/pkg/uroot/test/gopath1/src/foo"}, 87 wantErr: false, 88 }, 89 // Single package directory relative to GOPATH 90 { 91 env: gopath1Env, 92 in: []string{"foo"}, 93 expected: []string{ 94 "foo", 95 }, 96 wantErr: false, 97 }, 98 // Package directory glob 99 { 100 env: defaultEnv, 101 in: []string{"test/gopath2/src/mypkg*"}, 102 expected: []string{ 103 "github.com/u-root/u-root/pkg/uroot/test/gopath2/src/mypkga", 104 "github.com/u-root/u-root/pkg/uroot/test/gopath2/src/mypkgb", 105 }, 106 wantErr: false, 107 }, 108 // GOPATH glob 109 { 110 env: gopath2Env, 111 in: []string{"mypkg*"}, 112 expected: []string{ 113 "mypkga", 114 "mypkgb", 115 }, 116 wantErr: false, 117 }, 118 // Single ambiguous package - exists in both GOROOT and GOPATH 119 { 120 env: gopath1Env, 121 in: []string{"os"}, 122 expected: []string{ 123 "os", 124 }, 125 wantErr: false, 126 }, 127 // Packages from different gopaths 128 { 129 env: everythingEnv, 130 in: []string{"foo", "mypkga"}, 131 expected: []string{ 132 "foo", 133 "mypkga", 134 }, 135 wantErr: false, 136 }, 137 // Same package specified twice 138 { 139 env: defaultEnv, 140 in: []string{"test/gopath2/src/mypkga", "test/gopath2/src/mypkga"}, 141 // TODO: This returns the package twice. Is this preferred? 142 expected: []string{ 143 "github.com/u-root/u-root/pkg/uroot/test/gopath2/src/mypkga", 144 "github.com/u-root/u-root/pkg/uroot/test/gopath2/src/mypkga", 145 }, 146 wantErr: false, 147 }, 148 // Excludes 149 { 150 env: defaultEnv, 151 in: []string{"test/gopath2/src/*", "-test/gopath2/src/mypkga"}, 152 expected: []string{ 153 "github.com/u-root/u-root/pkg/uroot/test/gopath2/src/mypkgb", 154 }, 155 wantErr: false, 156 }, 157 } { 158 t.Run(fmt.Sprintf("%q", tc.in), func(t *testing.T) { 159 out, err := ResolvePackagePaths(l, tc.env, tc.in) 160 if (err != nil) != tc.wantErr { 161 t.Fatalf("ResolvePackagePaths(%#v, %v) err != nil is %v, want %v\nerr is %v", 162 tc.env, tc.in, err != nil, tc.wantErr, err) 163 } 164 if !reflect.DeepEqual(out, tc.expected) { 165 t.Errorf("ResolvePackagePaths(%#v, %v) = %v; want %v", 166 tc.env, tc.in, out, tc.expected) 167 } 168 }) 169 } 170 } 171 172 func TestCreateInitramfs(t *testing.T) { 173 dir, err := ioutil.TempDir("", "foo") 174 if err != nil { 175 t.Error(err) 176 } 177 defer os.RemoveAll(dir) 178 syscall.Umask(0) 179 180 tmp777 := filepath.Join(dir, "tmp777") 181 if err := os.MkdirAll(tmp777, 0777); err != nil { 182 t.Error(err) 183 } 184 185 // Why doesn't the log package export this as a default? 186 l := log.New(os.Stdout, "", log.LstdFlags) 187 188 for i, tt := range []struct { 189 name string 190 opts Opts 191 want string 192 validators []itest.ArchiveValidator 193 }{ 194 { 195 name: "BB archive with ls and init", 196 opts: Opts{ 197 Env: golang.Default(), 198 TempDir: dir, 199 ExtraFiles: nil, 200 UseExistingInit: false, 201 InitCmd: "init", 202 DefaultShell: "ls", 203 Commands: []Commands{ 204 { 205 Builder: builder.BusyBox, 206 Packages: []string{ 207 "github.com/u-root/u-root/cmds/core/init", 208 "github.com/u-root/u-root/cmds/core/ls", 209 }, 210 }, 211 }, 212 }, 213 want: "", 214 validators: []itest.ArchiveValidator{ 215 itest.HasFile{"bbin/bb"}, 216 itest.HasRecord{cpio.Symlink("bbin/init", "bb")}, 217 itest.HasRecord{cpio.Symlink("bbin/ls", "bb")}, 218 itest.HasRecord{cpio.Symlink("bin/defaultsh", "../bbin/ls")}, 219 itest.HasRecord{cpio.Symlink("bin/sh", "../bbin/ls")}, 220 }, 221 }, 222 { 223 name: "no temp dir", 224 opts: Opts{ 225 Env: golang.Default(), 226 InitCmd: "init", 227 DefaultShell: "", 228 }, 229 want: "temp dir \"\" must exist: stat : no such file or directory", 230 validators: []itest.ArchiveValidator{ 231 itest.IsEmpty{}, 232 }, 233 }, 234 { 235 name: "no commands", 236 opts: Opts{ 237 Env: golang.Default(), 238 TempDir: dir, 239 }, 240 want: "", 241 validators: []itest.ArchiveValidator{ 242 itest.MissingFile{"bbin/bb"}, 243 }, 244 }, 245 { 246 name: "init specified, but not in commands", 247 opts: Opts{ 248 Commands: []Commands{ 249 { 250 Builder: builder.Binary, 251 Packages: []string{ 252 "github.com/u-root/u-root/cmds/core/ls", 253 }, 254 }, 255 }, 256 Env: golang.Default(), 257 TempDir: dir, 258 DefaultShell: "zoocar", 259 InitCmd: "foobar", 260 }, 261 want: "could not create symlink from \"init\" to \"foobar\": command or path \"foobar\" not included in u-root build: specify -initcmd=\"\" to ignore this error and build without an init", 262 validators: []itest.ArchiveValidator{ 263 itest.IsEmpty{}, 264 }, 265 }, 266 { 267 name: "init symlinked to absolute path", 268 opts: Opts{ 269 Env: golang.Default(), 270 TempDir: dir, 271 InitCmd: "/bin/systemd", 272 }, 273 want: "", 274 validators: []itest.ArchiveValidator{ 275 itest.HasRecord{cpio.Symlink("init", "bin/systemd")}, 276 }, 277 }, 278 { 279 name: "multi-mode archive", 280 opts: Opts{ 281 Env: golang.Default(), 282 TempDir: dir, 283 ExtraFiles: nil, 284 UseExistingInit: false, 285 InitCmd: "init", 286 DefaultShell: "ls", 287 Commands: []Commands{ 288 { 289 Builder: builder.BusyBox, 290 Packages: []string{ 291 "github.com/u-root/u-root/cmds/core/init", 292 "github.com/u-root/u-root/cmds/core/ls", 293 }, 294 }, 295 { 296 Builder: builder.Binary, 297 Packages: []string{ 298 "github.com/u-root/u-root/cmds/core/cp", 299 "github.com/u-root/u-root/cmds/core/dd", 300 }, 301 }, 302 { 303 Builder: builder.Source, 304 Packages: []string{ 305 "github.com/u-root/u-root/cmds/core/cat", 306 "github.com/u-root/u-root/cmds/core/chroot", 307 "github.com/u-root/u-root/cmds/core/installcommand", 308 }, 309 }, 310 }, 311 }, 312 want: "", 313 validators: []itest.ArchiveValidator{ 314 itest.HasRecord{cpio.Symlink("init", "bbin/init")}, 315 316 // bb mode. 317 itest.HasFile{"bbin/bb"}, 318 itest.HasRecord{cpio.Symlink("bbin/init", "bb")}, 319 itest.HasRecord{cpio.Symlink("bbin/ls", "bb")}, 320 itest.HasRecord{cpio.Symlink("bin/defaultsh", "../bbin/ls")}, 321 itest.HasRecord{cpio.Symlink("bin/sh", "../bbin/ls")}, 322 323 // binary mode. 324 itest.HasFile{"bin/cp"}, 325 itest.HasFile{"bin/dd"}, 326 327 // source mode. 328 itest.HasRecord{cpio.Symlink("buildbin/cat", "installcommand")}, 329 itest.HasRecord{cpio.Symlink("buildbin/chroot", "installcommand")}, 330 itest.HasFile{"buildbin/installcommand"}, 331 itest.HasFile{"src/github.com/u-root/u-root/cmds/core/cat/cat.go"}, 332 itest.HasFile{"src/github.com/u-root/u-root/cmds/core/chroot/chroot.go"}, 333 itest.HasFile{"src/github.com/u-root/u-root/cmds/core/installcommand/installcommand.go"}, 334 }, 335 }, 336 } { 337 t.Run(fmt.Sprintf("Test %d [%s]", i, tt.name), func(t *testing.T) { 338 archive := inMemArchive{cpio.InMemArchive()} 339 tt.opts.OutputFile = archive 340 // Compare error type or error string. 341 if err := CreateInitramfs(l, tt.opts); (err != nil && err.Error() != tt.want) || (len(tt.want) > 0 && err == nil) { 342 t.Errorf("CreateInitramfs(%v) = %v, want %v", tt.opts, err, tt.want) 343 } 344 345 for _, v := range tt.validators { 346 if err := v.Validate(archive.Archive); err != nil { 347 t.Errorf("validator failed: %v / archive:\n%s", err, archive) 348 } 349 } 350 }) 351 } 352 }