github.com/shaardie/u-root@v4.0.1-0.20190127173353-f24a1c26aa2e+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/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/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 } { 149 t.Run(fmt.Sprintf("%q", tc.in), func(t *testing.T) { 150 out, err := ResolvePackagePaths(l, tc.env, tc.in) 151 if (err != nil) != tc.wantErr { 152 t.Fatalf("ResolvePackagePaths(%#v, %v) err != nil is %v, want %v\nerr is %v", 153 tc.env, tc.in, err != nil, tc.wantErr, err) 154 } 155 if !reflect.DeepEqual(out, tc.expected) { 156 t.Errorf("ResolvePackagePaths(%#v, %v) = %v; want %v", 157 tc.env, tc.in, out, tc.expected) 158 } 159 }) 160 } 161 } 162 163 func TestCreateInitramfs(t *testing.T) { 164 dir, err := ioutil.TempDir("", "foo") 165 if err != nil { 166 t.Error(err) 167 } 168 defer os.RemoveAll(dir) 169 syscall.Umask(0) 170 171 tmp777 := filepath.Join(dir, "tmp777") 172 if err := os.MkdirAll(tmp777, 0777); err != nil { 173 t.Error(err) 174 } 175 176 // Why doesn't the log package export this as a default? 177 l := log.New(os.Stdout, "", log.LstdFlags) 178 179 for i, tt := range []struct { 180 name string 181 opts Opts 182 want error 183 validators []itest.ArchiveValidator 184 }{ 185 { 186 name: "BB archive with ls and init", 187 opts: Opts{ 188 Env: golang.Default(), 189 TempDir: dir, 190 ExtraFiles: nil, 191 UseExistingInit: false, 192 InitCmd: "init", 193 DefaultShell: "ls", 194 Commands: []Commands{ 195 { 196 Builder: builder.BusyBox, 197 Packages: []string{ 198 "github.com/u-root/u-root/cmds/init", 199 "github.com/u-root/u-root/cmds/ls", 200 }, 201 }, 202 }, 203 }, 204 want: nil, 205 validators: []itest.ArchiveValidator{ 206 itest.HasFile{"bbin/bb"}, 207 itest.HasRecord{cpio.Symlink("bbin/init", "bb")}, 208 itest.HasRecord{cpio.Symlink("bbin/ls", "bb")}, 209 itest.HasRecord{cpio.Symlink("bin/defaultsh", "../bbin/ls")}, 210 itest.HasRecord{cpio.Symlink("bin/sh", "../bbin/ls")}, 211 }, 212 }, 213 { 214 name: "no temp dir", 215 opts: Opts{ 216 Env: golang.Default(), 217 InitCmd: "init", 218 DefaultShell: "", 219 }, 220 // TODO: Ew. Our error types suck. 221 want: fmt.Errorf("temp dir \"\" must exist: stat : no such file or directory"), 222 validators: []itest.ArchiveValidator{ 223 itest.IsEmpty{}, 224 }, 225 }, 226 { 227 name: "no commands", 228 opts: Opts{ 229 Env: golang.Default(), 230 TempDir: dir, 231 }, 232 want: nil, 233 validators: []itest.ArchiveValidator{ 234 itest.MissingFile{"bbin/bb"}, 235 }, 236 }, 237 { 238 name: "init specified, but not in commands", 239 opts: Opts{ 240 Commands: []Commands{ 241 { 242 Builder: builder.Binary, 243 Packages: []string{ 244 "github.com/u-root/u-root/cmds/ls", 245 }, 246 }, 247 }, 248 Env: golang.Default(), 249 TempDir: dir, 250 DefaultShell: "zoocar", 251 InitCmd: "foobar", 252 }, 253 want: fmt.Errorf("could not find init: command or path \"foobar\" not included in u-root build"), 254 validators: []itest.ArchiveValidator{ 255 itest.IsEmpty{}, 256 }, 257 }, 258 { 259 name: "init symlinked to absolute path", 260 opts: Opts{ 261 Env: golang.Default(), 262 TempDir: dir, 263 InitCmd: "/bin/systemd", 264 }, 265 want: nil, 266 validators: []itest.ArchiveValidator{ 267 itest.HasRecord{cpio.Symlink("init", "bin/systemd")}, 268 }, 269 }, 270 { 271 name: "multi-mode archive", 272 opts: Opts{ 273 Env: golang.Default(), 274 TempDir: dir, 275 ExtraFiles: nil, 276 UseExistingInit: false, 277 InitCmd: "init", 278 DefaultShell: "ls", 279 Commands: []Commands{ 280 { 281 Builder: builder.BusyBox, 282 Packages: []string{ 283 "github.com/u-root/u-root/cmds/init", 284 "github.com/u-root/u-root/cmds/ls", 285 }, 286 }, 287 { 288 Builder: builder.Binary, 289 Packages: []string{ 290 "github.com/u-root/u-root/cmds/cp", 291 "github.com/u-root/u-root/cmds/dd", 292 }, 293 }, 294 { 295 Builder: builder.Source, 296 Packages: []string{ 297 "github.com/u-root/u-root/cmds/cat", 298 "github.com/u-root/u-root/cmds/chroot", 299 "github.com/u-root/u-root/cmds/installcommand", 300 }, 301 }, 302 }, 303 }, 304 want: nil, 305 validators: []itest.ArchiveValidator{ 306 itest.HasRecord{cpio.Symlink("init", "bbin/init")}, 307 308 // bb mode. 309 itest.HasFile{"bbin/bb"}, 310 itest.HasRecord{cpio.Symlink("bbin/init", "bb")}, 311 itest.HasRecord{cpio.Symlink("bbin/ls", "bb")}, 312 itest.HasRecord{cpio.Symlink("bin/defaultsh", "../bbin/ls")}, 313 itest.HasRecord{cpio.Symlink("bin/sh", "../bbin/ls")}, 314 315 // binary mode. 316 itest.HasFile{"bin/cp"}, 317 itest.HasFile{"bin/dd"}, 318 319 // source mode. 320 itest.HasRecord{cpio.Symlink("buildbin/cat", "installcommand")}, 321 itest.HasRecord{cpio.Symlink("buildbin/chroot", "installcommand")}, 322 itest.HasFile{"buildbin/installcommand"}, 323 itest.HasFile{"src/github.com/u-root/u-root/cmds/cat/cat.go"}, 324 itest.HasFile{"src/github.com/u-root/u-root/cmds/chroot/chroot.go"}, 325 itest.HasFile{"src/github.com/u-root/u-root/cmds/installcommand/installcommand.go"}, 326 }, 327 }, 328 } { 329 t.Run(fmt.Sprintf("Test %d [%s]", i, tt.name), func(t *testing.T) { 330 archive := inMemArchive{cpio.InMemArchive()} 331 tt.opts.OutputFile = archive 332 // Compare error type or error string. 333 if err := CreateInitramfs(l, tt.opts); err != tt.want && (tt.want == nil || err.Error() != tt.want.Error()) { 334 t.Errorf("CreateInitramfs(%v) = %v, want %v", tt.opts, err, tt.want) 335 } 336 337 for _, v := range tt.validators { 338 if err := v.Validate(archive.Archive); err != nil { 339 t.Errorf("validator failed: %v / archive:\n%s", err, archive) 340 } 341 } 342 }) 343 } 344 }