Files
kata-containers/src/runtime/cli/release_test.go
James O. D. Hunt 1a77f69e15 runtime: make kata-check check for newer release
Update `kata-check` to see if there is a newer version available for
download. Useful for users installing static packages (without a package
manager).

Fixes: #734.

Signed-off-by: James O. D. Hunt <james.o.hunt@intel.com>
2020-09-21 13:47:29 +01:00

499 lines
12 KiB
Go

// Copyright (c) 2020 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package main
import (
"fmt"
"os"
"strings"
"testing"
"github.com/blang/semver"
"github.com/stretchr/testify/assert"
)
var currentSemver semver.Version
var expectedReleasesURL string
func init() {
var err error
currentSemver, err = semver.Make(version)
if err != nil {
panic(fmt.Sprintf("failed to create semver for testing: %v", err))
}
if currentSemver.Major == 1 {
expectedReleasesURL = kataLegacyReleaseURL
} else {
expectedReleasesURL = kataReleaseURL
}
}
func TestReleaseCmd(t *testing.T) {
assert := assert.New(t)
for i, value := range []ReleaseCmd{RelCmdCheck, RelCmdList} {
assert.True(value.Valid(), "test[%d]: %+v", i, value)
}
for i, value := range []int{-1, 2, 42, 255} {
invalid := ReleaseCmd(i)
assert.False(invalid.Valid(), "test[%d]: %+v", i, value)
}
}
func TestGetReleaseURL(t *testing.T) {
assert := assert.New(t)
const kata1xURL = "https://api.github.com/repos/kata-containers/runtime/releases"
const kata2xURL = "https://api.github.com/repos/kata-containers/kata-containers/releases"
type testData struct {
currentVersion string
expectError bool
expectedURL string
}
data := []testData{
{"0.0.0", true, ""},
{"1.0.0", false, kata1xURL},
{"1.9999.9999", false, kata1xURL},
{"2.0.0-alpha3", false, kata2xURL},
{"2.9999.9999", false, kata2xURL},
}
for i, d := range data {
msg := fmt.Sprintf("test[%d]: %+v", i, d)
ver, err := semver.Make(d.currentVersion)
msg = fmt.Sprintf("%s, version: %v, error: %v", msg, ver, err)
assert.NoError(err, msg)
url, err := getReleaseURL(ver)
if d.expectError {
assert.Error(err, msg)
} else {
assert.NoError(err, msg)
assert.Equal(url, d.expectedURL, msg)
assert.True(strings.HasPrefix(url, projectAPIURL), msg)
}
}
url, err := getReleaseURL(currentSemver)
assert.NoError(err)
assert.Equal(url, expectedReleasesURL)
assert.True(strings.HasPrefix(url, projectAPIURL))
}
func TestGetReleaseURLEnvVar(t *testing.T) {
assert := assert.New(t)
type testData struct {
envVarValue string
expectError bool
expectedURL string
}
data := []testData{
{"", false, expectedReleasesURL},
{"http://google.com", true, ""},
{"https://katacontainers.io", true, ""},
{"https://github.com/kata-containers/runtime/releases/latest", true, ""},
{"https://github.com/kata-containers/kata-containers/releases/latest", true, ""},
{expectedReleasesURL, false, expectedReleasesURL},
}
assert.Equal(os.Getenv("KATA_RELEASE_URL"), "")
defer os.Setenv("KATA_RELEASE_URL", "")
for i, d := range data {
msg := fmt.Sprintf("test[%d]: %+v", i, d)
err := os.Setenv("KATA_RELEASE_URL", d.envVarValue)
msg = fmt.Sprintf("%s, error: %v", msg, err)
assert.NoError(err, msg)
url, err := getReleaseURL(currentSemver)
if d.expectError {
assert.Errorf(err, msg)
} else {
assert.NoErrorf(err, msg)
assert.Equal(d.expectedURL, url, msg)
}
}
}
func TestMakeRelease(t *testing.T) {
assert := assert.New(t)
type testData struct {
release map[string]interface{}
expectError bool
expectedVersion string
expectedDetails releaseDetails
}
invalidRel1 := map[string]interface{}{"foo": 1}
invalidRel2 := map[string]interface{}{"foo": "bar"}
invalidRel3 := map[string]interface{}{"foo": true}
testDate := "2020-09-01T22:10:44Z"
testRelVersion := "1.2.3"
testFilename := "kata-static-1.12.0-alpha1-x86_64.tar.xz"
testURL := fmt.Sprintf("https://github.com/kata-containers/runtime/releases/download/%s/%s", testRelVersion, testFilename)
testSemver, err := semver.Make(testRelVersion)
assert.NoError(err)
invalidRelMissingVersion := map[string]interface{}{}
invalidRelInvalidVersion := map[string]interface{}{
"tag_name": "not.valid.semver",
}
invalidRelMissingAssets := map[string]interface{}{
"tag_name": testRelVersion,
"name": testFilename,
"assets": []interface{}{},
}
invalidAssetsMissingURL := []interface{}{
map[string]interface{}{
"name": testFilename,
"created_at": testDate,
},
}
invalidAssetsMissingFile := []interface{}{
map[string]interface{}{
"browser_download_url": testURL,
"created_at": testDate,
},
}
invalidAssetsMissingDate := []interface{}{
map[string]interface{}{
"name": testFilename,
"browser_download_url": testURL,
},
}
validAssets := []interface{}{
map[string]interface{}{
"browser_download_url": testURL,
"name": testFilename,
"created_at": testDate,
},
}
invalidRelAssetsMissingURL := map[string]interface{}{
"tag_name": testRelVersion,
"name": testFilename,
"assets": invalidAssetsMissingURL,
}
invalidRelAssetsMissingFile := map[string]interface{}{
"tag_name": testRelVersion,
"name": testFilename,
"assets": invalidAssetsMissingFile,
}
invalidRelAssetsMissingDate := map[string]interface{}{
"tag_name": testRelVersion,
"name": testFilename,
"assets": invalidAssetsMissingDate,
}
validRel := map[string]interface{}{
"tag_name": testRelVersion,
"name": testFilename,
"assets": validAssets,
}
validReleaseDetails := releaseDetails{
version: testSemver,
date: testDate,
url: testURL,
filename: testFilename,
}
data := []testData{
{invalidRel1, true, "", releaseDetails{}},
{invalidRel2, true, "", releaseDetails{}},
{invalidRel3, true, "", releaseDetails{}},
{invalidRelMissingVersion, true, "", releaseDetails{}},
{invalidRelInvalidVersion, true, "", releaseDetails{}},
{invalidRelMissingAssets, true, "", releaseDetails{}},
{invalidRelAssetsMissingURL, true, "", releaseDetails{}},
{invalidRelAssetsMissingFile, true, "", releaseDetails{}},
{invalidRelAssetsMissingDate, true, "", releaseDetails{}},
{validRel, false, testRelVersion, validReleaseDetails},
}
for i, d := range data {
msg := fmt.Sprintf("test[%d]: %+v", i, d)
version, details, err := makeRelease(d.release)
msg = fmt.Sprintf("%s, version: %v, details: %+v, error: %v", msg, version, details, err)
if d.expectError {
assert.Error(err, msg)
continue
}
assert.NoError(err, msg)
assert.Equal(d.expectedVersion, version, msg)
assert.Equal(d.expectedDetails, details, msg)
}
}
func TestReleaseURLIsValid(t *testing.T) {
assert := assert.New(t)
type testData struct {
url string
expectError bool
}
data := []testData{
{"", true},
{"foo", true},
{"foo bar", true},
{"https://google.com", true},
{projectAPIURL, true},
{kataLegacyReleaseURL, false},
{kataReleaseURL, false},
}
for i, d := range data {
msg := fmt.Sprintf("test[%d]: %+v", i, d)
err := releaseURLIsValid(d.url)
msg = fmt.Sprintf("%s, error: %v", msg, err)
if d.expectError {
assert.Error(err, msg)
} else {
assert.NoError(err, msg)
}
}
}
func TestDownloadURLIsValid(t *testing.T) {
assert := assert.New(t)
type testData struct {
url string
expectError bool
}
validKata1xDownload := "https://github.com/kata-containers/runtime/releases/download/1.12.0-alpha1/kata-static-1.12.0-alpha1-x86_64.tar.xz"
validKata2xDownload := "https://github.com/kata-containers/kata-containers/releases/download/2.0.0-alpha3/kata-static-2.0.0-alpha3-x86_64.tar.xz"
data := []testData{
{"", true},
{"foo", true},
{"foo bar", true},
{"https://google.com", true},
{projectURL, true},
{validKata1xDownload, false},
{validKata2xDownload, false},
}
for i, d := range data {
msg := fmt.Sprintf("test[%d]: %+v", i, d)
err := downloadURLIsValid(d.url)
msg = fmt.Sprintf("%s, error: %v", msg, err)
if d.expectError {
assert.Error(err, msg)
} else {
assert.NoError(err, msg)
}
}
}
func TestIgnoreRelease(t *testing.T) {
assert := assert.New(t)
type testData struct {
details releaseDetails
includeAll bool
expectIgnore bool
}
verWithoutPreRelease, err := semver.Make("2.0.0")
assert.NoError(err)
verWithPreRelease, err := semver.Make("2.0.0-alpha3")
assert.NoError(err)
relWithoutPreRelease := releaseDetails{
version: verWithoutPreRelease,
}
relWithPreRelease := releaseDetails{
version: verWithPreRelease,
}
data := []testData{
{relWithoutPreRelease, false, false},
{relWithoutPreRelease, true, false},
{relWithPreRelease, false, true},
{relWithPreRelease, true, false},
}
for i, d := range data {
msg := fmt.Sprintf("test[%d]: %+v", i, d)
ignore := ignoreRelease(d.details, d.includeAll)
if d.expectIgnore {
assert.True(ignore, msg)
} else {
assert.False(ignore, msg)
}
}
}
func TestGetReleases(t *testing.T) {
assert := assert.New(t)
url := "foo"
expectedErrMsg := "unsupported protocol scheme"
for _, includeAll := range []bool{true, false} {
euid := os.Geteuid()
msg := fmt.Sprintf("includeAll: %v, euid: %v", includeAll, euid)
_, _, err := getReleases(url, includeAll)
msg = fmt.Sprintf("%s, error: %v", msg, err)
assert.Error(err, msg)
if euid == 0 {
assert.Equal(err.Error(), errNoNetChecksAsRoot, msg)
} else {
assert.True(strings.Contains(err.Error(), expectedErrMsg), msg)
}
}
}
func TestFindNewestRelease(t *testing.T) {
assert := assert.New(t)
type testData struct {
currentVer semver.Version
versions []semver.Version
expectAvailable bool
expectVersion semver.Version
expectError bool
}
ver1, err := semver.Make("1.11.1")
assert.NoError(err)
ver2, err := semver.Make("1.11.3")
assert.NoError(err)
ver3, err := semver.Make("2.0.0")
assert.NoError(err)
data := []testData{
{semver.Version{}, []semver.Version{}, false, semver.Version{}, true},
{ver1, []semver.Version{}, false, semver.Version{}, true},
{ver1, []semver.Version{ver1}, false, semver.Version{}, false},
{ver2, []semver.Version{ver1}, false, semver.Version{}, false},
{ver1, []semver.Version{ver2}, true, ver2, false},
{ver1, []semver.Version{ver3}, true, ver3, false},
{ver1, []semver.Version{ver2, ver3}, true, ver3, false},
{ver2, []semver.Version{ver1, ver3}, true, ver3, false},
{ver2, []semver.Version{ver1}, false, semver.Version{}, false},
}
for i, d := range data {
msg := fmt.Sprintf("test[%d]: %+v", i, d)
available, version, err := findNewestRelease(d.currentVer, d.versions)
msg = fmt.Sprintf("%s, available: %v, version: %v, error: %v", msg, available, version, err)
if d.expectError {
assert.Error(err, msg)
continue
}
assert.NoError(err, msg)
if !d.expectAvailable {
assert.False(available, msg)
continue
}
assert.Equal(d.expectVersion, version)
}
}
func TestGetNewReleaseType(t *testing.T) {
assert := assert.New(t)
type testData struct {
currentVer string
latestVer string
expectError bool
result string
}
data := []testData{
{"2.0.0-alpha3", "1.0.0", true, ""},
{"1.0.0", "1.0.0", true, ""},
{"2.0.0", "1.0.0", true, ""},
{"1.0.0", "2.0.0", false, "major"},
{"2.0.0-alpha3", "2.0.0-alpha4", false, "pre-release"},
{"1.0.0", "2.0.0-alpha3", false, "major pre-release"},
{"1.0.0", "1.1.2", false, "minor"},
{"1.0.0", "1.1.2-pre2", false, "minor pre-release"},
{"1.0.0", "1.1.2-foo", false, "minor pre-release"},
{"1.0.0", "1.0.3", false, "patch"},
{"1.0.0-beta29", "1.0.0-beta30", false, "pre-release"},
{"1.0.0", "1.0.3-alpha99.1b", false, "patch pre-release"},
}
for i, d := range data {
msg := fmt.Sprintf("test[%d]: %+v", i, d)
current, err := semver.Make(d.currentVer)
msg = fmt.Sprintf("%s, current: %v, error: %v", msg, current, err)
assert.NoError(err, msg)
latest, err := semver.Make(d.latestVer)
assert.NoError(err, msg)
desc, err := getNewReleaseType(current, latest)
if d.expectError {
assert.Error(err, msg)
continue
}
assert.NoError(err, msg)
assert.Equal(d.result, desc, msg)
}
}