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 }