github.com/andrewsun2898/u-root@v6.0.1-0.20200616011413-4b2895c1b815+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 } { 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 string 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/core/init", 199 "github.com/u-root/u-root/cmds/core/ls", 200 }, 201 }, 202 }, 203 }, 204 want: "", 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 want: "temp dir \"\" must exist: stat : no such file or directory", 221 validators: []itest.ArchiveValidator{ 222 itest.IsEmpty{}, 223 }, 224 }, 225 { 226 name: "no commands", 227 opts: Opts{ 228 Env: golang.Default(), 229 TempDir: dir, 230 }, 231 want: "", 232 validators: []itest.ArchiveValidator{ 233 itest.MissingFile{"bbin/bb"}, 234 }, 235 }, 236 { 237 name: "init specified, but not in commands", 238 opts: Opts{ 239 Commands: []Commands{ 240 { 241 Builder: builder.Binary, 242 Packages: []string{ 243 "github.com/u-root/u-root/cmds/core/ls", 244 }, 245 }, 246 }, 247 Env: golang.Default(), 248 TempDir: dir, 249 DefaultShell: "zoocar", 250 InitCmd: "foobar", 251 }, 252 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", 253 validators: []itest.ArchiveValidator{ 254 itest.IsEmpty{}, 255 }, 256 }, 257 { 258 name: "init symlinked to absolute path", 259 opts: Opts{ 260 Env: golang.Default(), 261 TempDir: dir, 262 InitCmd: "/bin/systemd", 263 }, 264 want: "", 265 validators: []itest.ArchiveValidator{ 266 itest.HasRecord{cpio.Symlink("init", "bin/systemd")}, 267 }, 268 }, 269 { 270 name: "multi-mode archive", 271 opts: Opts{ 272 Env: golang.Default(), 273 TempDir: dir, 274 ExtraFiles: nil, 275 UseExistingInit: false, 276 InitCmd: "init", 277 DefaultShell: "ls", 278 Commands: []Commands{ 279 { 280 Builder: builder.BusyBox, 281 Packages: []string{ 282 "github.com/u-root/u-root/cmds/core/init", 283 "github.com/u-root/u-root/cmds/core/ls", 284 }, 285 }, 286 { 287 Builder: builder.Binary, 288 Packages: []string{ 289 "github.com/u-root/u-root/cmds/core/cp", 290 "github.com/u-root/u-root/cmds/core/dd", 291 }, 292 }, 293 { 294 Builder: builder.Source, 295 Packages: []string{ 296 "github.com/u-root/u-root/cmds/core/cat", 297 "github.com/u-root/u-root/cmds/core/chroot", 298 "github.com/u-root/u-root/cmds/core/installcommand", 299 }, 300 }, 301 }, 302 }, 303 want: "", 304 validators: []itest.ArchiveValidator{ 305 itest.HasRecord{cpio.Symlink("init", "bbin/init")}, 306 307 // bb mode. 308 itest.HasFile{"bbin/bb"}, 309 itest.HasRecord{cpio.Symlink("bbin/init", "bb")}, 310 itest.HasRecord{cpio.Symlink("bbin/ls", "bb")}, 311 itest.HasRecord{cpio.Symlink("bin/defaultsh", "../bbin/ls")}, 312 itest.HasRecord{cpio.Symlink("bin/sh", "../bbin/ls")}, 313 314 // binary mode. 315 itest.HasFile{"bin/cp"}, 316 itest.HasFile{"bin/dd"}, 317 318 // source mode. 319 itest.HasRecord{cpio.Symlink("buildbin/cat", "installcommand")}, 320 itest.HasRecord{cpio.Symlink("buildbin/chroot", "installcommand")}, 321 itest.HasFile{"buildbin/installcommand"}, 322 itest.HasFile{"src/github.com/u-root/u-root/cmds/core/cat/cat.go"}, 323 itest.HasFile{"src/github.com/u-root/u-root/cmds/core/chroot/chroot.go"}, 324 itest.HasFile{"src/github.com/u-root/u-root/cmds/core/installcommand/installcommand.go"}, 325 }, 326 }, 327 } { 328 t.Run(fmt.Sprintf("Test %d [%s]", i, tt.name), func(t *testing.T) { 329 archive := inMemArchive{cpio.InMemArchive()} 330 tt.opts.OutputFile = archive 331 // Compare error type or error string. 332 if err := CreateInitramfs(l, tt.opts); (err != nil && err.Error() != tt.want) || (len(tt.want) > 0 && err == nil) { 333 t.Errorf("CreateInitramfs(%v) = %v, want %v", tt.opts, err, tt.want) 334 } 335 336 for _, v := range tt.validators { 337 if err := v.Validate(archive.Archive); err != nil { 338 t.Errorf("validator failed: %v / archive:\n%s", err, archive) 339 } 340 } 341 }) 342 } 343 }