github.com/lalkh/containerd@v1.4.3/platforms/platforms_test.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package platforms 18 19 import ( 20 "reflect" 21 "runtime" 22 "testing" 23 24 specs "github.com/opencontainers/image-spec/specs-go/v1" 25 ) 26 27 func TestParseSelector(t *testing.T) { 28 var ( 29 defaultOS = runtime.GOOS 30 defaultArch = runtime.GOARCH 31 defaultVariant = "" 32 ) 33 34 if defaultArch == "arm" && cpuVariant != "v7" { 35 defaultVariant = cpuVariant 36 } 37 38 for _, testcase := range []struct { 39 skip bool 40 input string 41 expected specs.Platform 42 matches []specs.Platform 43 formatted string 44 }{ 45 // While wildcards are a valid use case for platform selection, 46 // addressing these cases is outside the initial scope for this 47 // package. When we do add platform wildcards, we should add in these 48 // testcases to ensure that they are correctly represented. 49 { 50 skip: true, 51 input: "*", 52 expected: specs.Platform{ 53 OS: "*", 54 Architecture: "*", 55 }, 56 formatted: "*/*", 57 }, 58 { 59 skip: true, 60 input: "linux/*", 61 expected: specs.Platform{ 62 OS: "linux", 63 Architecture: "*", 64 }, 65 formatted: "linux/*", 66 }, 67 { 68 skip: true, 69 input: "*/arm64", 70 expected: specs.Platform{ 71 OS: "*", 72 Architecture: "arm64", 73 }, 74 matches: []specs.Platform{ 75 { 76 OS: "*", 77 Architecture: "aarch64", 78 }, 79 { 80 OS: "*", 81 Architecture: "aarch64", 82 Variant: "v8", 83 }, 84 { 85 OS: "*", 86 Architecture: "arm64", 87 Variant: "v8", 88 }, 89 }, 90 formatted: "*/arm64", 91 }, 92 { 93 input: "linux/arm64", 94 expected: specs.Platform{ 95 OS: "linux", 96 Architecture: "arm64", 97 }, 98 matches: []specs.Platform{ 99 { 100 OS: "linux", 101 Architecture: "aarch64", 102 }, 103 { 104 OS: "linux", 105 Architecture: "aarch64", 106 Variant: "v8", 107 }, 108 { 109 OS: "linux", 110 Architecture: "arm64", 111 Variant: "v8", 112 }, 113 }, 114 formatted: "linux/arm64", 115 }, 116 { 117 input: "linux/arm64/v8", 118 expected: specs.Platform{ 119 OS: "linux", 120 Architecture: "arm64", 121 Variant: "v8", 122 }, 123 matches: []specs.Platform{ 124 { 125 OS: "linux", 126 Architecture: "aarch64", 127 }, 128 { 129 OS: "linux", 130 Architecture: "aarch64", 131 Variant: "v8", 132 }, 133 { 134 OS: "linux", 135 Architecture: "arm64", 136 }, 137 }, 138 formatted: "linux/arm64/v8", 139 }, 140 { 141 // NOTE(stevvooe): In this case, the consumer can assume this is v7 142 // but we leave the variant blank. This will represent the vast 143 // majority of arm images. 144 input: "linux/arm", 145 expected: specs.Platform{ 146 OS: "linux", 147 Architecture: "arm", 148 }, 149 matches: []specs.Platform{ 150 { 151 OS: "linux", 152 Architecture: "arm", 153 Variant: "v7", 154 }, 155 { 156 OS: "linux", 157 Architecture: "armhf", 158 }, 159 { 160 OS: "linux", 161 Architecture: "arm", 162 Variant: "7", 163 }, 164 }, 165 formatted: "linux/arm", 166 }, 167 { 168 input: "linux/arm/v6", 169 expected: specs.Platform{ 170 OS: "linux", 171 Architecture: "arm", 172 Variant: "v6", 173 }, 174 matches: []specs.Platform{ 175 { 176 OS: "linux", 177 Architecture: "armel", 178 }, 179 }, 180 formatted: "linux/arm/v6", 181 }, 182 { 183 input: "linux/arm/v7", 184 expected: specs.Platform{ 185 OS: "linux", 186 Architecture: "arm", 187 Variant: "v7", 188 }, 189 matches: []specs.Platform{ 190 { 191 OS: "linux", 192 Architecture: "arm", 193 }, 194 { 195 OS: "linux", 196 Architecture: "armhf", 197 }, 198 }, 199 formatted: "linux/arm/v7", 200 }, 201 { 202 input: "arm", 203 expected: specs.Platform{ 204 OS: defaultOS, 205 Architecture: "arm", 206 }, 207 formatted: joinNotEmpty(defaultOS, "arm"), 208 }, 209 { 210 input: "armel", 211 expected: specs.Platform{ 212 OS: defaultOS, 213 Architecture: "arm", 214 Variant: "v6", 215 }, 216 formatted: joinNotEmpty(defaultOS, "arm/v6"), 217 }, 218 { 219 input: "armhf", 220 expected: specs.Platform{ 221 OS: defaultOS, 222 Architecture: "arm", 223 }, 224 formatted: joinNotEmpty(defaultOS, "arm"), 225 }, 226 { 227 input: "Aarch64", 228 expected: specs.Platform{ 229 OS: defaultOS, 230 Architecture: "arm64", 231 }, 232 formatted: joinNotEmpty(defaultOS, "arm64"), 233 }, 234 { 235 input: "x86_64", 236 expected: specs.Platform{ 237 OS: defaultOS, 238 Architecture: "amd64", 239 }, 240 formatted: joinNotEmpty(defaultOS, "amd64"), 241 }, 242 { 243 input: "Linux/x86_64", 244 expected: specs.Platform{ 245 OS: "linux", 246 Architecture: "amd64", 247 }, 248 formatted: "linux/amd64", 249 }, 250 { 251 input: "i386", 252 expected: specs.Platform{ 253 OS: defaultOS, 254 Architecture: "386", 255 }, 256 formatted: joinNotEmpty(defaultOS, "386"), 257 }, 258 { 259 input: "linux", 260 expected: specs.Platform{ 261 OS: "linux", 262 Architecture: defaultArch, 263 Variant: defaultVariant, 264 }, 265 formatted: joinNotEmpty("linux", defaultArch, defaultVariant), 266 }, 267 { 268 input: "s390x", 269 expected: specs.Platform{ 270 OS: defaultOS, 271 Architecture: "s390x", 272 }, 273 formatted: joinNotEmpty(defaultOS, "s390x"), 274 }, 275 { 276 input: "linux/s390x", 277 expected: specs.Platform{ 278 OS: "linux", 279 Architecture: "s390x", 280 }, 281 formatted: "linux/s390x", 282 }, 283 { 284 input: "macOS", 285 expected: specs.Platform{ 286 OS: "darwin", 287 Architecture: defaultArch, 288 Variant: defaultVariant, 289 }, 290 formatted: joinNotEmpty("darwin", defaultArch, defaultVariant), 291 }, 292 } { 293 t.Run(testcase.input, func(t *testing.T) { 294 if testcase.skip { 295 t.Skip("this case is not yet supported") 296 } 297 p, err := Parse(testcase.input) 298 if err != nil { 299 t.Fatal(err) 300 } 301 302 if !reflect.DeepEqual(p, testcase.expected) { 303 t.Fatalf("platform did not match expected: %#v != %#v", p, testcase.expected) 304 } 305 306 m := NewMatcher(p) 307 308 // ensure that match works on the input to the output. 309 if ok := m.Match(testcase.expected); !ok { 310 t.Fatalf("expected specifier %q matches %#v", testcase.input, testcase.expected) 311 } 312 for _, mc := range testcase.matches { 313 if ok := m.Match(mc); !ok { 314 t.Fatalf("expected specifier %q matches %#v", testcase.input, mc) 315 } 316 } 317 318 formatted := Format(p) 319 if formatted != testcase.formatted { 320 t.Fatalf("unexpected format: %q != %q", formatted, testcase.formatted) 321 } 322 323 // re-parse the formatted output and ensure we are stable 324 reparsed, err := Parse(formatted) 325 if err != nil { 326 t.Fatalf("error parsing formatted output: %v", err) 327 } 328 329 if Format(reparsed) != formatted { 330 t.Fatalf("normalized output did not survive the round trip: %v != %v", Format(reparsed), formatted) 331 } 332 }) 333 } 334 } 335 336 func TestParseSelectorInvalid(t *testing.T) { 337 for _, testcase := range []struct { 338 input string 339 }{ 340 { 341 input: "", // empty 342 }, 343 { 344 input: "/linux/arm", // leading slash 345 }, 346 { 347 input: "linux/arm/", // trailing slash 348 }, 349 { 350 input: "linux /arm", // spaces 351 }, 352 { 353 input: "linux/&arm", // invalid character 354 }, 355 { 356 input: "linux/arm/foo/bar", // too many components 357 }, 358 } { 359 t.Run(testcase.input, func(t *testing.T) { 360 if _, err := Parse(testcase.input); err == nil { 361 t.Fatalf("should have received an error") 362 } 363 }) 364 } 365 }