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  }