github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/pkg/boot/netboot/ipxe/ipxe_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 package ipxe 6 7 import ( 8 "fmt" 9 "io" 10 "net/url" 11 "reflect" 12 "strings" 13 "testing" 14 15 "github.com/u-root/u-root/pkg/boot" 16 "github.com/u-root/u-root/pkg/curl" 17 "github.com/u-root/u-root/pkg/uio" 18 ) 19 20 func mustReadAll(r io.ReaderAt) string { 21 if r == nil { 22 return "" 23 } 24 b, err := uio.ReadAll(r) 25 if err != nil { 26 return fmt.Sprintf("read error: %s", err) 27 } 28 return string(b) 29 } 30 31 type errorReader struct { 32 err error 33 } 34 35 func (e errorReader) ReadAt(p []byte, n int64) (int, error) { 36 return 0, e.err 37 } 38 39 func TestIpxeConfig(t *testing.T) { 40 content1 := "1111" 41 content2 := "2222" 42 43 for i, tt := range []struct { 44 desc string 45 schemeFunc func() curl.Schemes 46 curl *url.URL 47 want *boot.LinuxImage 48 err error 49 }{ 50 { 51 desc: "all files exist, simple config with no cmdline", 52 schemeFunc: func() curl.Schemes { 53 s := make(curl.Schemes) 54 fs := curl.NewMockScheme("http") 55 conf := `#!ipxe 56 kernel http://someplace.com/foobar/pxefiles/kernel 57 initrd http://someplace.com/foobar/pxefiles/initrd 58 boot` 59 fs.Add("someplace.com", "/foobar/pxefiles/ipxeconfig", conf) 60 fs.Add("someplace.com", "/foobar/pxefiles/kernel", content1) 61 fs.Add("someplace.com", "/foobar/pxefiles/initrd", content2) 62 s.Register(fs.Scheme, fs) 63 return s 64 }, 65 curl: &url.URL{ 66 Scheme: "http", 67 Host: "someplace.com", 68 Path: "/foobar/pxefiles/ipxeconfig", 69 }, 70 want: &boot.LinuxImage{ 71 Kernel: strings.NewReader(content1), 72 Initrd: strings.NewReader(content2), 73 }, 74 }, 75 { 76 desc: "all files exist, simple config, no initrd", 77 schemeFunc: func() curl.Schemes { 78 s := make(curl.Schemes) 79 fs := curl.NewMockScheme("http") 80 conf := `#!ipxe 81 kernel http://someplace.com/foobar/pxefiles/kernel 82 boot` 83 fs.Add("someplace.com", "/foobar/pxefiles/ipxeconfig", conf) 84 fs.Add("someplace.com", "/foobar/pxefiles/kernel", content1) 85 s.Register(fs.Scheme, fs) 86 return s 87 }, 88 curl: &url.URL{ 89 Scheme: "http", 90 Host: "someplace.com", 91 Path: "/foobar/pxefiles/ipxeconfig", 92 }, 93 want: &boot.LinuxImage{ 94 Kernel: strings.NewReader(content1), 95 }, 96 }, 97 { 98 desc: "comments and blank lines", 99 schemeFunc: func() curl.Schemes { 100 s := make(curl.Schemes) 101 fs := curl.NewMockScheme("http") 102 conf := `#!ipxe 103 # the next line is blank 104 105 kernel http://someplace.com/foobar/pxefiles/kernel 106 boot` 107 fs.Add("someplace.com", "/foobar/pxefiles/ipxeconfig", conf) 108 fs.Add("someplace.com", "/foobar/pxefiles/kernel", content1) 109 s.Register(fs.Scheme, fs) 110 return s 111 }, 112 curl: &url.URL{ 113 Scheme: "http", 114 Host: "someplace.com", 115 Path: "/foobar/pxefiles/ipxeconfig", 116 }, 117 want: &boot.LinuxImage{ 118 Kernel: strings.NewReader(content1), 119 }, 120 }, 121 { 122 desc: "kernel does not exist, simple config", 123 schemeFunc: func() curl.Schemes { 124 s := make(curl.Schemes) 125 fs := curl.NewMockScheme("http") 126 conf := `#!ipxe 127 kernel http://someplace.com/foobar/pxefiles/kernel 128 boot` 129 fs.Add("someplace.com", "/foobar/pxefiles/ipxeconfig", conf) 130 s.Register(fs.Scheme, fs) 131 return s 132 }, 133 curl: &url.URL{ 134 Scheme: "http", 135 Host: "someplace.com", 136 Path: "/foobar/pxefiles/ipxeconfig", 137 }, 138 want: &boot.LinuxImage{ 139 Kernel: errorReader{&curl.URLError{ 140 URL: &url.URL{ 141 Scheme: "http", 142 Host: "someplace.com", 143 Path: "/foobar/pxefiles/kernel", 144 }, 145 Err: curl.ErrNoSuchFile, 146 }}, 147 Initrd: nil, 148 Cmdline: "", 149 }, 150 }, 151 { 152 desc: "config file does not exist", 153 schemeFunc: func() curl.Schemes { 154 s := make(curl.Schemes) 155 fs := curl.NewMockScheme("http") 156 s.Register(fs.Scheme, fs) 157 return s 158 }, 159 curl: &url.URL{ 160 Scheme: "http", 161 Host: "someplace.com", 162 Path: "/foobar/pxefiles/ipxeconfig", 163 }, 164 err: &curl.URLError{ 165 URL: &url.URL{ 166 Scheme: "http", 167 Host: "someplace.com", 168 Path: "/foobar/pxefiles/ipxeconfig", 169 }, 170 Err: curl.ErrNoSuchHost, 171 }, 172 }, 173 { 174 desc: "invalid config", 175 schemeFunc: func() curl.Schemes { 176 s := make(curl.Schemes) 177 fs := curl.NewMockScheme("http") 178 fs.Add("someplace.com", "/foobar/pxefiles/ipxeconfig", "") 179 s.Register(fs.Scheme, fs) 180 return s 181 }, 182 curl: &url.URL{ 183 Scheme: "http", 184 Host: "someplace.com", 185 Path: "/foobar/pxefiles/ipxeconfig", 186 }, 187 err: ErrNotIpxeScript, 188 }, 189 { 190 desc: "empty config", 191 schemeFunc: func() curl.Schemes { 192 s := make(curl.Schemes) 193 fs := curl.NewMockScheme("http") 194 conf := `#!ipxe` 195 fs.Add("someplace.com", "/foobar/pxefiles/ipxeconfig", conf) 196 s.Register(fs.Scheme, fs) 197 return s 198 }, 199 curl: &url.URL{ 200 Scheme: "http", 201 Host: "someplace.com", 202 Path: "/foobar/pxefiles/ipxeconfig", 203 }, 204 want: &boot.LinuxImage{}, 205 }, 206 { 207 desc: "valid config with kernel cmdline args", 208 schemeFunc: func() curl.Schemes { 209 s := make(curl.Schemes) 210 fs := curl.NewMockScheme("http") 211 conf := `#!ipxe 212 kernel http://someplace.com/foobar/pxefiles/kernel earlyprintk=ttyS0 printk=ttyS0 213 boot` 214 fs.Add("someplace.com", "/foobar/pxefiles/ipxeconfig", conf) 215 fs.Add("someplace.com", "/foobar/pxefiles/kernel", content1) 216 s.Register(fs.Scheme, fs) 217 return s 218 }, 219 curl: &url.URL{ 220 Scheme: "http", 221 Host: "someplace.com", 222 Path: "/foobar/pxefiles/ipxeconfig", 223 }, 224 want: &boot.LinuxImage{ 225 Kernel: strings.NewReader(content1), 226 Cmdline: "earlyprintk=ttyS0 printk=ttyS0", 227 }, 228 }, 229 { 230 desc: "multi-scheme valid config", 231 schemeFunc: func() curl.Schemes { 232 conf := `#!ipxe 233 kernel tftp://1.2.3.4/foobar/pxefiles/kernel 234 initrd http://someplace.com/someinitrd.gz 235 boot` 236 237 tftp := curl.NewMockScheme("tftp") 238 tftp.Add("1.2.3.4", "/foobar/pxefiles/kernel", content1) 239 240 http := curl.NewMockScheme("http") 241 http.Add("someplace.com", "/foobar/pxefiles/ipxeconfig", conf) 242 http.Add("someplace.com", "/someinitrd.gz", content2) 243 244 s := make(curl.Schemes) 245 s.Register(tftp.Scheme, tftp) 246 s.Register(http.Scheme, http) 247 return s 248 }, 249 curl: &url.URL{ 250 Scheme: "http", 251 Host: "someplace.com", 252 Path: "/foobar/pxefiles/ipxeconfig", 253 }, 254 want: &boot.LinuxImage{ 255 Kernel: strings.NewReader(content1), 256 Initrd: strings.NewReader(content2), 257 }, 258 }, 259 { 260 desc: "valid config with unsupported cmds", 261 schemeFunc: func() curl.Schemes { 262 s := make(curl.Schemes) 263 fs := curl.NewMockScheme("http") 264 conf := `#!ipxe 265 kernel http://someplace.com/foobar/pxefiles/kernel 266 initrd http://someplace.com/someinitrd.gz 267 set ip 0.0.0.0 268 boot` 269 fs.Add("someplace.com", "/foobar/pxefiles/ipxeconfig", conf) 270 fs.Add("someplace.com", "/foobar/pxefiles/kernel", content1) 271 fs.Add("someplace.com", "/someinitrd.gz", content2) 272 s.Register(fs.Scheme, fs) 273 return s 274 }, 275 curl: &url.URL{ 276 Scheme: "http", 277 Host: "someplace.com", 278 Path: "/foobar/pxefiles/ipxeconfig", 279 }, 280 want: &boot.LinuxImage{ 281 Kernel: strings.NewReader(content1), 282 Initrd: strings.NewReader(content2), 283 }, 284 }, 285 } { 286 t.Run(fmt.Sprintf("Test [%02d] %s", i, tt.desc), func(t *testing.T) { 287 got, err := ParseConfigWithSchemes(tt.curl, tt.schemeFunc()) 288 if !reflect.DeepEqual(err, tt.err) { 289 t.Errorf("NewConfigWithSchemes() got %v, want %v", err, tt.err) 290 return 291 } else if err != nil { 292 return 293 } 294 want := tt.want 295 296 // Same kernel? 297 if !uio.ReaderAtEqual(got.Kernel, want.Kernel) { 298 t.Errorf("got kernel %s, want %s", mustReadAll(got.Kernel), mustReadAll(want.Kernel)) 299 } 300 // Same initrd? 301 if !uio.ReaderAtEqual(got.Initrd, want.Initrd) { 302 t.Errorf("got initrd %s, want %s", mustReadAll(got.Initrd), mustReadAll(want.Initrd)) 303 } 304 // Same cmdline? 305 if got.Cmdline != want.Cmdline { 306 t.Errorf("got cmdline %s, want %s", got.Cmdline, want.Cmdline) 307 } 308 }) 309 } 310 }