k8s.io/test-infra@v0.0.0-20240520184403-27c6b4c223d8/kubetest/extract_test.go (about) 1 /* 2 Copyright 2017 The Kubernetes 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 main 18 19 import ( 20 "fmt" 21 "os" 22 "path" 23 "reflect" 24 "strings" 25 "testing" 26 "time" 27 ) 28 29 func TestParseGciExtractOption(t *testing.T) { 30 cases := []struct { 31 option string 32 expectFamily string 33 expectParamsMap map[string]string 34 }{ 35 { 36 option: "gci-canary", 37 expectFamily: "gci-canary", 38 expectParamsMap: map[string]string{ 39 "project": "container-vm-image-staging", 40 "k8s-map-bucket": "container-vm-image-staging", 41 }, 42 }, 43 { 44 option: "gci-canary?project=test-project", 45 expectFamily: "gci-canary", 46 expectParamsMap: map[string]string{ 47 "project": "test-project", 48 "k8s-map-bucket": "container-vm-image-staging", 49 }, 50 }, 51 { 52 option: "gci-canary?k8s-map-bucket=test-bucket", 53 expectFamily: "gci-canary", 54 expectParamsMap: map[string]string{ 55 "project": "container-vm-image-staging", 56 "k8s-map-bucket": "test-bucket", 57 }, 58 }, 59 { 60 option: "gci-canary?project=test-project:k8s-map-bucket=test-bucket", 61 expectFamily: "gci-canary", 62 expectParamsMap: map[string]string{ 63 "project": "test-project", 64 "k8s-map-bucket": "test-bucket", 65 }, 66 }, 67 } 68 69 var gotFamily string 70 var gotParamsMap map[string]string 71 72 for _, tc := range cases { 73 gotFamily, gotParamsMap = parseGciExtractOption(tc.option) 74 if gotFamily != tc.expectFamily || !reflect.DeepEqual(gotParamsMap, tc.expectParamsMap) { 75 t.Errorf("got parseGciExtractOption(%q) = %q, %q; want %q, %q", tc.option, gotFamily, gotParamsMap, tc.expectFamily, tc.expectParamsMap) 76 } 77 } 78 } 79 80 func TestGetKube(t *testing.T) { 81 cases := []struct { 82 name string 83 script string 84 success bool 85 }{ 86 { 87 name: "can succeed", 88 script: "true", 89 success: true, 90 }, 91 { 92 name: "can fail", 93 script: "exit 1", 94 success: false, 95 }, 96 { 97 name: "can successfully retry", 98 script: "([[ -e ran ]] && true) || (touch ran && exit 1)", 99 success: true, 100 }, 101 } 102 103 if !terminate.Stop() { 104 <-terminate.C 105 } 106 if !interrupt.Stop() { 107 <-interrupt.C 108 } 109 110 oldSleep := sleep 111 defer func() { sleep = oldSleep }() 112 sleep = func(d time.Duration) {} 113 114 if o, err := os.Getwd(); err != nil { 115 t.Fatal(err) 116 } else { 117 defer os.Chdir(o) 118 } 119 120 d := t.TempDir() 121 if err := os.Chdir(d); err != nil { 122 t.Fatal(err) 123 } 124 125 for _, tc := range cases { 126 bytes := []byte(fmt.Sprintf("#!/bin/bash\necho hello\n%s\nmkdir -p ./kubernetes/cluster && touch ./kubernetes/cluster/get-kube-binaries.sh", tc.script)) 127 if err := os.WriteFile("./get-kube.sh", bytes, 0700); err != nil { 128 t.Fatal(err) 129 } 130 err := getKube("url", "version", false) 131 if tc.success && err != nil { 132 t.Errorf("%s did not succeed: %s", tc.name, err) 133 } 134 if !tc.success && err == nil { 135 t.Errorf("%s unexpectedly succeeded", tc.name) 136 } 137 } 138 } 139 140 func TestExtractStrategies(t *testing.T) { 141 cases := []struct { 142 option string 143 expectURL string 144 expectVersion string 145 }{ 146 { 147 "bazel/v1.8.0-alpha.2.899+2c624e590f5670", 148 "", 149 "bazel/v1.8.0-alpha.2.899+2c624e590f5670", 150 }, 151 { 152 "bazel/49747/master:b341939d6d3666b119028400a4311cc66da9a542,49747:c4656c3d029e47d03b3d7d9915d79cab72a80852", 153 "", 154 "bazel/49747/master:b341939d6d3666b119028400a4311cc66da9a542,49747:c4656c3d029e47d03b3d7d9915d79cab72a80852", 155 }, 156 { 157 "gs://k8s-release-dev/bazel/v1.8.0-alpha.3.389+eab2f8f6c19fcb", 158 "https://storage.googleapis.com/k8s-release-dev/bazel", 159 "v1.8.0-alpha.3.389+eab2f8f6c19fcb", 160 }, 161 { 162 "v1.8.0-alpha.1", 163 "https://storage.googleapis.com/k8s-release/release", 164 "v1.8.0-alpha.1", 165 }, 166 { 167 "v1.8.0-alpha.2.899+2c624e590f5670", 168 "https://storage.googleapis.com/k8s-release-dev/ci", 169 "v1.8.0-alpha.2.899+2c624e590f5670", 170 }, 171 { 172 "v1.8.0-gke.0", 173 "https://storage.googleapis.com/gke-release-staging/kubernetes/release", 174 "v1.8.0-gke.0", 175 }, 176 { 177 "ci/latest", 178 "https://storage.googleapis.com/k8s-release-dev/ci", 179 "v1.2.3+abcde", 180 }, 181 { 182 "ci/latest-fast", 183 "https://storage.googleapis.com/k8s-release-dev/ci/fast", 184 "v1.2.3+abcde", 185 }, 186 { 187 "ci/gke-staging-latest", 188 "https://storage.googleapis.com/gke-release-staging/kubernetes/release", 189 "v1.2.3+abcde", 190 }, 191 { 192 "ci/gke-latest-1.13", 193 "https://storage.googleapis.com/gke-release-staging/kubernetes/release", 194 "v1.2.3+abcde", 195 }, 196 { 197 "ci/gke-latest-1.13.0", 198 "https://storage.googleapis.com/gke-release-staging/kubernetes/release", 199 "v1.2.3+abcde", 200 }, 201 { 202 "ci/gke-latest-1.13.0-gke", 203 "https://storage.googleapis.com/gke-release-staging/kubernetes/release", 204 "v1.2.3+abcde", 205 }, 206 { 207 "ci/gke-latest-1.13.10-gke", 208 "https://storage.googleapis.com/gke-release-staging/kubernetes/release", 209 "v1.2.3+abcde", 210 }, 211 { 212 "ci/gke-channel-rapid", 213 "https://storage.googleapis.com/gke-release-staging/kubernetes/release", 214 "v1.2.3+abcde", 215 }, 216 { 217 "gs://whatever-bucket/ci/latest.txt", 218 "https://storage.googleapis.com/whatever-bucket/ci", 219 "v1.2.3+abcde", 220 }, 221 } 222 223 var gotURL string 224 var gotVersion string 225 226 // getKube is tested independently, so mock it out here so we can test 227 // that different extraction strategies call getKube with the correct 228 // arguments. 229 oldGetKube := getKube 230 defer func() { getKube = oldGetKube }() 231 getKube = func(url, version string, _ bool) error { 232 gotURL = url 233 gotVersion = version 234 // This is needed or else Extract() will think that getKube failed. 235 os.Mkdir("kubernetes", 0775) 236 return nil 237 } 238 239 oldCat := gsutilCat 240 defer func() { gsutilCat = oldCat }() 241 gsutilCat = func(url string) ([]byte, error) { 242 if path.Ext(url) != ".txt" { 243 return []byte{}, fmt.Errorf("url %s must end with .txt", url) 244 } 245 if !strings.HasPrefix(path.Dir(url), "gs:/") { 246 return []byte{}, fmt.Errorf("url %s must starts with gs:/", path.Dir(url)) 247 } 248 249 return []byte("v1.2.3+abcde"), nil 250 } 251 252 oldHTTPCat := httpCat 253 defer func() { httpCat = oldHTTPCat }() 254 httpCat = func(url string) ([]byte, error) { 255 if path.Ext(url) != ".txt" { 256 return []byte{}, fmt.Errorf("url %s must end with .txt", url) 257 } 258 if !strings.HasPrefix(url, "https://") { 259 return []byte{}, fmt.Errorf("url %s must starts with https://", url) 260 } 261 262 return []byte("v1.2.3+abcde"), nil 263 } 264 265 ciBucket := "k8s-release-dev" 266 releaseBucket := "k8s-release" 267 268 for _, tc := range cases { 269 d := t.TempDir() 270 if err := os.Chdir(d); err != nil { 271 t.Fatal(err) 272 } 273 274 var es extractStrategies 275 if err := es.Set(tc.option); err != nil { 276 t.Errorf("extractStrategy.Set(%q) returned err: %q", tc.option, err) 277 } 278 if err := es.Extract("", "", "", ciBucket, releaseBucket, false); err != nil { 279 t.Errorf("extractStrategy(%q).Extract() returned err: %q", tc.option, err) 280 } 281 282 if gotURL != tc.expectURL || gotVersion != tc.expectVersion { 283 t.Errorf("extractStrategy(%q).Extract() wanted getKube(%q, %q), got getKube(%q, %q)", tc.option, tc.expectURL, tc.expectVersion, gotURL, gotVersion) 284 } 285 } 286 } 287 288 func TestGciExtractStrategy(t *testing.T) { 289 cases := []struct { 290 option string 291 expectURL string 292 expectVersion string 293 expectFamily string 294 expectProject string 295 expectVersionMapBucket string 296 }{ 297 { 298 "gci/gci-canary", 299 "https://storage.googleapis.com/k8s-release/release", 300 "v1.2.3+abcde", 301 "gci-canary", 302 "container-vm-image-staging", 303 "gs://container-vm-image-staging/k8s-version-map/test-image", 304 }, 305 { 306 "gci/gci-canary?project=test-project:k8s-map-bucket=test-bucket", 307 "https://storage.googleapis.com/k8s-release/release", 308 "v1.2.3+abcde", 309 "gci-canary", 310 "test-project", 311 "gs://test-bucket/k8s-version-map/test-image", 312 }, 313 { 314 "gci/gci-canary?project=test-project/latest", 315 "https://storage.googleapis.com/k8s-release-dev/ci", 316 "1.2.3+abcde", 317 "gci-canary", 318 "test-project", 319 "gs://k8s-release-dev/ci/latest.txt", 320 }, 321 } 322 323 var gotURL string 324 var gotVersion string 325 var gotFamily string 326 var gotProject string 327 var gotVersionMapBucket string 328 329 // getKube is tested independently, so mock it out here so we can test 330 // that different extraction strategies call getKube with the correct 331 // arguments. 332 oldGetKube := getKube 333 defer func() { getKube = oldGetKube }() 334 getKube = func(url, version string, _ bool) error { 335 gotURL = url 336 gotVersion = version 337 // This is needed or else Extract() will think that getKube failed. 338 os.Mkdir("kubernetes", 0775) 339 return nil 340 } 341 342 oldCat := gsutilCat 343 defer func() { gsutilCat = oldCat }() 344 gsutilCat = func(url string) ([]byte, error) { 345 if !strings.HasPrefix(path.Dir(url), "gs:/") { 346 return []byte{}, fmt.Errorf("url %s must start with gs:/", path.Dir(url)) 347 } 348 gotVersionMapBucket = url 349 return []byte("1.2.3+abcde"), nil 350 } 351 352 oldGcloudGetImageName := gcloudGetImageName 353 defer func() { gcloudGetImageName = oldGcloudGetImageName }() 354 gcloudGetImageName = func(family string, project string) ([]byte, error) { 355 gotFamily = family 356 gotProject = project 357 return []byte("test-image"), nil 358 } 359 360 ciBucket := "k8s-release-dev" 361 releaseBucket := "k8s-release" 362 363 for _, tc := range cases { 364 d := t.TempDir() 365 if err := os.Chdir(d); err != nil { 366 t.Fatal(err) 367 } 368 369 var es extractStrategies 370 if err := es.Set(tc.option); err != nil { 371 t.Errorf("extractStrategy.Set(%q) returned err: %q", tc.option, err) 372 } 373 if err := es.Extract("", "", "", ciBucket, releaseBucket, false); err != nil { 374 t.Errorf("extractStrategy(%q).Extract() returned err: %q", tc.option, err) 375 } 376 377 if gotFamily != tc.expectFamily || gotProject != tc.expectProject { 378 t.Errorf("extractStrategies(%q).Extract() wanted setupGciVars(%q, %q), got setupGciVars(%q, %q)", tc.option, tc.expectFamily, tc.expectProject, gotFamily, gotProject) 379 } 380 if gotVersionMapBucket != tc.expectVersionMapBucket { 381 t.Errorf("extractStrategies(%q).Extract() wanted gsutilCat(%q), got gsutilCat(%q)", tc.option, tc.expectVersionMapBucket, gotVersionMapBucket) 382 } 383 if gotURL != tc.expectURL || gotVersion != tc.expectVersion { 384 t.Errorf("extractStrategy(%q).Extract() wanted getKube(%q, %q), got getKube(%q, %q)", tc.option, tc.expectURL, tc.expectVersion, gotURL, gotVersion) 385 } 386 } 387 }