github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/update_test.go (about)

     1  // Copyright (c) 2015-2021 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"encoding/hex"
    22  	"fmt"
    23  	"net/http"
    24  	"net/http/httptest"
    25  	"net/url"
    26  	"os"
    27  	"runtime"
    28  	"strings"
    29  	"testing"
    30  	"time"
    31  )
    32  
    33  func TestMinioVersionToReleaseTime(t *testing.T) {
    34  	testCases := []struct {
    35  		version    string
    36  		isOfficial bool
    37  	}{
    38  		{"2017-09-29T19:16:56Z", true},
    39  		{"RELEASE.2017-09-29T19-16-56Z", false},
    40  		{"DEVELOPMENT.GOGET", false},
    41  	}
    42  	for i, testCase := range testCases {
    43  		_, err := minioVersionToReleaseTime(testCase.version)
    44  		if (err == nil) != testCase.isOfficial {
    45  			t.Errorf("Test %d: Expected %v but got %v",
    46  				i+1, testCase.isOfficial, err == nil)
    47  		}
    48  	}
    49  }
    50  
    51  func TestReleaseTagToNFromTimeConversion(t *testing.T) {
    52  	utcLoc, _ := time.LoadLocation("")
    53  	testCases := []struct {
    54  		t      time.Time
    55  		tag    string
    56  		errStr string
    57  	}{
    58  		{
    59  			time.Date(2017, time.September, 29, 19, 16, 56, 0, utcLoc),
    60  			"RELEASE.2017-09-29T19-16-56Z", "",
    61  		},
    62  		{
    63  			time.Date(2017, time.August, 5, 0, 0, 53, 0, utcLoc),
    64  			"RELEASE.2017-08-05T00-00-53Z", "",
    65  		},
    66  		{
    67  			time.Now().UTC(), "2017-09-29T19:16:56Z",
    68  			"2017-09-29T19:16:56Z is not a valid release tag",
    69  		},
    70  		{
    71  			time.Now().UTC(), "DEVELOPMENT.GOGET",
    72  			"DEVELOPMENT.GOGET is not a valid release tag",
    73  		},
    74  		{
    75  			time.Date(2017, time.August, 5, 0, 0, 53, 0, utcLoc),
    76  			"RELEASE.2017-08-05T00-00-53Z.hotfix", "",
    77  		},
    78  		{
    79  			time.Date(2017, time.August, 5, 0, 0, 53, 0, utcLoc),
    80  			"RELEASE.2017-08-05T00-00-53Z.hotfix.aaaa", "",
    81  		},
    82  	}
    83  	for i, testCase := range testCases {
    84  		if testCase.errStr != "" {
    85  			got := releaseTimeToReleaseTag(testCase.t)
    86  			if got != testCase.tag && testCase.errStr == "" {
    87  				t.Errorf("Test %d: Expected %v but got %v", i+1, testCase.tag, got)
    88  			}
    89  		}
    90  		tagTime, err := releaseTagToReleaseTime(testCase.tag)
    91  		if err != nil && err.Error() != testCase.errStr {
    92  			t.Errorf("Test %d: Expected %v but got %v", i+1, testCase.errStr, err.Error())
    93  		}
    94  		if err == nil && !tagTime.Equal(testCase.t) {
    95  			t.Errorf("Test %d: Expected %v but got %v", i+1, testCase.t, tagTime)
    96  		}
    97  	}
    98  }
    99  
   100  func TestDownloadURL(t *testing.T) {
   101  	sci := globalIsCICD
   102  	globalIsCICD = false
   103  	defer func() {
   104  		globalIsCICD = sci
   105  	}()
   106  
   107  	minioVersion1 := releaseTimeToReleaseTag(UTCNow())
   108  	durl := getDownloadURL(minioVersion1)
   109  	if IsDocker() {
   110  		if durl != "podman pull quay.io/minio/minio:"+minioVersion1 {
   111  			t.Errorf("Expected %s, got %s", "podman pull quay.io/minio/minio:"+minioVersion1, durl)
   112  		}
   113  	} else {
   114  		if runtime.GOOS == "windows" {
   115  			if durl != MinioReleaseURL+"minio.exe" {
   116  				t.Errorf("Expected %s, got %s", MinioReleaseURL+"minio.exe", durl)
   117  			}
   118  		} else {
   119  			if durl != MinioReleaseURL+"minio" {
   120  				t.Errorf("Expected %s, got %s", MinioReleaseURL+"minio", durl)
   121  			}
   122  		}
   123  	}
   124  
   125  	t.Setenv("KUBERNETES_SERVICE_HOST", "10.11.148.5")
   126  	durl = getDownloadURL(minioVersion1)
   127  	if durl != kubernetesDeploymentDoc {
   128  		t.Errorf("Expected %s, got %s", kubernetesDeploymentDoc, durl)
   129  	}
   130  
   131  	t.Setenv("MESOS_CONTAINER_NAME", "mesos-1111")
   132  	durl = getDownloadURL(minioVersion1)
   133  	if durl != mesosDeploymentDoc {
   134  		t.Errorf("Expected %s, got %s", mesosDeploymentDoc, durl)
   135  	}
   136  }
   137  
   138  // Tests user agent string.
   139  func TestUserAgent(t *testing.T) {
   140  	testCases := []struct {
   141  		envName     string
   142  		envValue    string
   143  		mode        string
   144  		expectedStr string
   145  	}{
   146  		{
   147  			envName:     "",
   148  			envValue:    "",
   149  			mode:        globalMinioModeFS,
   150  			expectedStr: fmt.Sprintf("MinIO (%s; %s; %s; source DEVELOPMENT.GOGET DEVELOPMENT.GOGET DEVELOPMENT.GOGET", runtime.GOOS, runtime.GOARCH, globalMinioModeFS),
   151  		},
   152  		{
   153  			envName:     "MESOS_CONTAINER_NAME",
   154  			envValue:    "mesos-11111",
   155  			mode:        globalMinioModeErasure,
   156  			expectedStr: fmt.Sprintf("MinIO (%s; %s; %s; %s; source DEVELOPMENT.GOGET DEVELOPMENT.GOGET DEVELOPMENT.GOGET universe-%s", runtime.GOOS, runtime.GOARCH, globalMinioModeErasure, "dcos", "mesos-1111"),
   157  		},
   158  		{
   159  			envName:     "KUBERNETES_SERVICE_HOST",
   160  			envValue:    "10.11.148.5",
   161  			mode:        globalMinioModeErasure,
   162  			expectedStr: fmt.Sprintf("MinIO (%s; %s; %s; %s; source DEVELOPMENT.GOGET DEVELOPMENT.GOGET DEVELOPMENT.GOGET", runtime.GOOS, runtime.GOARCH, globalMinioModeErasure, "kubernetes"),
   163  		},
   164  	}
   165  
   166  	for i, testCase := range testCases {
   167  		sci := globalIsCICD
   168  		globalIsCICD = false
   169  
   170  		if testCase.envName != "" {
   171  			t.Setenv(testCase.envName, testCase.envValue)
   172  			if testCase.envName == "MESOS_CONTAINER_NAME" {
   173  				t.Setenv("MARATHON_APP_LABEL_DCOS_PACKAGE_VERSION", "mesos-1111")
   174  			}
   175  		}
   176  
   177  		str := getUserAgent(testCase.mode)
   178  		expectedStr := testCase.expectedStr
   179  		if IsDocker() {
   180  			expectedStr = strings.ReplaceAll(expectedStr, "; source", "; docker; source")
   181  		}
   182  		if !strings.Contains(str, expectedStr) {
   183  			t.Errorf("Test %d: expected: %s, got: %s", i+1, expectedStr, str)
   184  		}
   185  		globalIsCICD = sci
   186  		os.Unsetenv("MARATHON_APP_LABEL_DCOS_PACKAGE_VERSION")
   187  		os.Unsetenv(testCase.envName)
   188  	}
   189  }
   190  
   191  // Tests if the environment we are running is in DCOS.
   192  func TestIsDCOS(t *testing.T) {
   193  	sci := globalIsCICD
   194  	globalIsCICD = false
   195  	defer func() {
   196  		globalIsCICD = sci
   197  	}()
   198  
   199  	t.Setenv("MESOS_CONTAINER_NAME", "mesos-1111")
   200  	dcos := IsDCOS()
   201  	if !dcos {
   202  		t.Fatalf("Expected %t, got %t", true, dcos)
   203  	}
   204  	os.Unsetenv("MESOS_CONTAINER_NAME")
   205  	dcos = IsDCOS()
   206  	if dcos {
   207  		t.Fatalf("Expected %t, got %t", false, dcos)
   208  	}
   209  }
   210  
   211  // Tests if the environment we are running is in kubernetes.
   212  func TestIsKubernetes(t *testing.T) {
   213  	sci := globalIsCICD
   214  	globalIsCICD = false
   215  	defer func() {
   216  		globalIsCICD = sci
   217  	}()
   218  
   219  	t.Setenv("KUBERNETES_SERVICE_HOST", "10.11.148.5")
   220  	kubernetes := IsKubernetes()
   221  	if !kubernetes {
   222  		t.Fatalf("Expected %t, got %t", true, kubernetes)
   223  	}
   224  	os.Unsetenv("KUBERNETES_SERVICE_HOST")
   225  
   226  	kubernetes = IsKubernetes()
   227  	if kubernetes {
   228  		t.Fatalf("Expected %t, got %t", false, kubernetes)
   229  	}
   230  }
   231  
   232  // Tests if the environment we are running is Helm chart.
   233  func TestGetHelmVersion(t *testing.T) {
   234  	createTempFile := func(content string) string {
   235  		tmpfile, err := os.CreateTemp("", "helm-testfile-")
   236  		if err != nil {
   237  			t.Fatalf("Unable to create temporary file. %s", err)
   238  		}
   239  		if _, err = tmpfile.WriteString(content); err != nil {
   240  			t.Fatalf("Unable to create temporary file. %s", err)
   241  		}
   242  		if err = tmpfile.Close(); err != nil {
   243  			t.Fatalf("Unable to create temporary file. %s", err)
   244  		}
   245  		return tmpfile.Name()
   246  	}
   247  
   248  	filename := createTempFile(
   249  		`app="virtuous-rat-minio"
   250  chart="minio-0.1.3"
   251  heritage="Tiller"
   252  pod-template-hash="818089471"`)
   253  
   254  	defer os.Remove(filename)
   255  
   256  	testCases := []struct {
   257  		filename       string
   258  		expectedResult string
   259  	}{
   260  		{"", ""},
   261  		{"/tmp/non-existing-file", ""},
   262  		{filename, "minio-0.1.3"},
   263  	}
   264  
   265  	for _, testCase := range testCases {
   266  		result := getHelmVersion(testCase.filename)
   267  
   268  		if testCase.expectedResult != result {
   269  			t.Fatalf("result: expected: %v, got: %v", testCase.expectedResult, result)
   270  		}
   271  	}
   272  }
   273  
   274  func TestDownloadReleaseData(t *testing.T) {
   275  	httpServer1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
   276  	defer httpServer1.Close()
   277  	httpServer2 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   278  		fmt.Fprintln(w, "fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z")
   279  	}))
   280  	defer httpServer2.Close()
   281  	httpServer3 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   282  		http.Error(w, "", http.StatusNotFound)
   283  	}))
   284  	defer httpServer3.Close()
   285  
   286  	testCases := []struct {
   287  		releaseChecksumURL string
   288  		expectedResult     string
   289  		expectedErr        error
   290  	}{
   291  		{httpServer1.URL, "", nil},
   292  		{httpServer2.URL, "fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z\n", nil},
   293  		{httpServer3.URL, "", fmt.Errorf("Error downloading URL " + httpServer3.URL + ". Response: 404 Not Found")},
   294  	}
   295  
   296  	for _, testCase := range testCases {
   297  		u, err := url.Parse(testCase.releaseChecksumURL)
   298  		if err != nil {
   299  			t.Fatal(err)
   300  		}
   301  
   302  		result, err := downloadReleaseURL(u, 1*time.Second, "")
   303  		switch {
   304  		case testCase.expectedErr == nil:
   305  			if err != nil {
   306  				t.Fatalf("error: expected: %v, got: %v", testCase.expectedErr, err)
   307  			}
   308  		case err == nil:
   309  			t.Fatalf("error: expected: %v, got: %v", testCase.expectedErr, err)
   310  		case testCase.expectedErr.Error() != err.Error():
   311  			t.Fatalf("error: expected: %v, got: %v", testCase.expectedErr, err)
   312  		}
   313  
   314  		if testCase.expectedResult != result {
   315  			t.Fatalf("result: expected: %v, got: %v", testCase.expectedResult, result)
   316  		}
   317  	}
   318  }
   319  
   320  func TestParseReleaseData(t *testing.T) {
   321  	releaseTime, _ := releaseTagToReleaseTime("RELEASE.2016-10-07T01-16-39Z")
   322  	testCases := []struct {
   323  		data                string
   324  		expectedResult      time.Time
   325  		expectedSha256hex   string
   326  		expectedReleaseInfo string
   327  		expectedErr         bool
   328  	}{
   329  		{"more than two fields", time.Time{}, "", "", true},
   330  		{"more than", time.Time{}, "", "", true},
   331  		{"more than.two.fields", time.Time{}, "", "", true},
   332  		{"more minio.RELEASE.fields", time.Time{}, "", "", true},
   333  		{"more minio.RELEASE.2016-10-07T01-16-39Z", time.Time{}, "", "", true},
   334  		{
   335  			"fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z\n", releaseTime, "fbe246edbd382902db9a4035df7dce8cb441357d",
   336  			"minio.RELEASE.2016-10-07T01-16-39Z", false,
   337  		},
   338  		{
   339  			"fbe246edbd382902db9a4035df7dce8cb441357d minio.RELEASE.2016-10-07T01-16-39Z.customer-hotfix\n", releaseTime, "fbe246edbd382902db9a4035df7dce8cb441357d",
   340  			"minio.RELEASE.2016-10-07T01-16-39Z.customer-hotfix", false,
   341  		},
   342  	}
   343  
   344  	for i, testCase := range testCases {
   345  		sha256Sum, result, releaseInfo, err := parseReleaseData(testCase.data)
   346  		if !testCase.expectedErr {
   347  			if err != nil {
   348  				t.Errorf("error case %d: expected no error, got: %v", i+1, err)
   349  			}
   350  		} else if err == nil {
   351  			t.Errorf("error case %d: expected error got: %v", i+1, err)
   352  		}
   353  		if err == nil {
   354  			if hex.EncodeToString(sha256Sum) != testCase.expectedSha256hex {
   355  				t.Errorf("case %d: result: expected: %v, got: %x", i+1, testCase.expectedSha256hex, sha256Sum)
   356  			}
   357  			if !testCase.expectedResult.Equal(result) {
   358  				t.Errorf("case %d: result: expected: %v, got: %v", i+1, testCase.expectedResult, result)
   359  			}
   360  			if testCase.expectedReleaseInfo != releaseInfo {
   361  				t.Errorf("case %d: result: expected: %v, got: %v", i+1, testCase.expectedReleaseInfo, releaseInfo)
   362  			}
   363  		}
   364  	}
   365  }