Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding tests for version.go #206

Merged
merged 3 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ require (
github.com/gofri/go-github-ratelimit v1.1.0
github.com/google/go-containerregistry v0.19.0
github.com/google/go-github/v58 v58.0.0
github.com/stretchr/testify v1.9.0
)

require (
Expand Down Expand Up @@ -98,9 +99,10 @@ require (
github.com/opencontainers/image-spec v1.1.0-rc3 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.54.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/vbatts/tar-split v0.11.3 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
go.starlark.net v0.0.0-20240520160348-046347dcd104 // indirect
Expand Down
15 changes: 8 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -188,12 +188,12 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.54.0 h1:ZlZy0BgJhTwVZUn7dLOkwCZHUkrAqd3WYtcFCWnM1D8=
github.com/prometheus/common v0.54.0/go.mod h1:/TQgMJP5CuVYveyT7n/0Ix8yLNNXy9yRSkhnLTHPDIQ=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
Expand All @@ -208,8 +208,9 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
Expand Down
5 changes: 4 additions & 1 deletion pkg/version/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ func (v *Version) Fetch(ctx context.Context, imageURL string, _ *api.Options) (i
// latestSemver will return the latest ImageTag based on the given options
// restriction, using semver. This should not be used is UseSHA has been
// enabled.
// TODO: add tests..
func latestSemver(opts *api.Options, tags []api.ImageTag) (*api.ImageTag, error) {
var (
latestImageTag *api.ImageTag
Expand Down Expand Up @@ -153,6 +152,10 @@ func latestSemver(opts *api.Options, tags []api.ImageTag) (*api.ImageTag, error)
}
}

if latestImageTag == nil {
return nil, fmt.Errorf("no suitable version found")
}

return latestImageTag, nil
}

Expand Down
275 changes: 275 additions & 0 deletions pkg/version/version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
package version

import (
"regexp"
"testing"
"time"

"github.com/jetstack/version-checker/pkg/api"

"github.com/stretchr/testify/assert"
)

// Helper function to parse time
func parseTime(t string) time.Time {
parsedTime, _ := time.Parse(time.RFC3339, t)
return parsedTime
}

func TestLatestSemver(t *testing.T) {
// Ideal Set of Tags
tags := []api.ImageTag{
{Tag: "v1.0.0", Timestamp: parseTime("2023-06-01T00:00:00Z")},
{Tag: "v1.1.0", Timestamp: parseTime("2023-06-02T00:00:00Z")},
{Tag: "v1.1.1-alpha", Timestamp: parseTime("2023-06-03T00:00:00Z")},
{Tag: "v1.1.1", Timestamp: parseTime("2023-06-04T00:00:00Z")},
{Tag: "v2.0.0", Timestamp: parseTime("2023-06-05T00:00:00Z")},
}
tagsNoPrefix := []api.ImageTag{
{Tag: "1.0.0", Timestamp: parseTime("2023-06-01T00:00:00Z")},
{Tag: "1.1.0", Timestamp: parseTime("2023-06-02T00:00:00Z")},
{Tag: "1.1.1-alpha", Timestamp: parseTime("2023-06-03T00:00:00Z")},
{Tag: "1.1.1", Timestamp: parseTime("2023-06-04T00:00:00Z")},
{Tag: "2.0.0", Timestamp: parseTime("2023-06-05T00:00:00Z")},
}
// Include More Alpha/Beta/RC
alphaBetaTags := []api.ImageTag{
{Tag: "v1.0.0", Timestamp: parseTime("2023-06-01T00:00:00Z")},
{Tag: "v1.1.0", Timestamp: parseTime("2023-06-02T00:00:00Z")},
{Tag: "v1.1.1-alpha", Timestamp: parseTime("2023-06-03T00:00:00Z")},
{Tag: "v1.1.1", Timestamp: parseTime("2023-06-04T00:00:00Z")},
{Tag: "v2.0.0-alpha", Timestamp: parseTime("2023-06-05T00:00:00Z")},
{Tag: "v2.0.0-beta", Timestamp: parseTime("2023-06-05T00:00:00Z")},
{Tag: "v2.0.0-rc1", Timestamp: parseTime("2023-06-05T00:00:00Z")},
{Tag: "v2.0.0-rc2", Timestamp: parseTime("2023-06-05T00:00:00Z")},
}
// Images that are all numerical
nonSemVer := []api.ImageTag{
{Tag: "20230601", Timestamp: parseTime("2023-06-01T00:00:00Z")},
{Tag: "20230602", Timestamp: parseTime("2023-06-02T00:00:00Z")},
{Tag: "20230603", Timestamp: parseTime("2023-06-03T00:00:00Z")},
{Tag: "20230604", Timestamp: parseTime("2023-06-04T00:00:00Z")},
{Tag: "20230605", Timestamp: parseTime("2023-06-05T00:00:00Z")},
}
// This is to simulate an image that USED to SemVer but stopped
stoppedSemVer := []api.ImageTag{
{Tag: "v1.0.0", Timestamp: parseTime("2023-06-01T00:00:00Z")},
{Tag: "v1.1.0", Timestamp: parseTime("2023-06-02T00:00:00Z")},
{Tag: "202306030", Timestamp: parseTime("2023-06-03T00:00:00Z")},
{Tag: "202306031", Timestamp: parseTime("2023-06-03T00:00:00Z")},
{Tag: "202306040", Timestamp: parseTime("2023-06-04T00:00:00Z")},
{Tag: "202306050", Timestamp: parseTime("2023-06-05T00:00:00Z")},
{Tag: "202306060", Timestamp: parseTime("2023-06-06T00:00:00Z")},
}
// This is to simulate an image that USED to SemVer but stopped
startedSemVer := []api.ImageTag{
{Tag: "20230603", Timestamp: parseTime("2023-06-03T00:00:00Z")},
{Tag: "202306031", Timestamp: parseTime("2023-06-03T00:00:00Z")},
{Tag: "20230604", Timestamp: parseTime("2023-06-04T00:00:00Z")},
{Tag: "20230605", Timestamp: parseTime("2023-06-05T00:00:00Z")},
{Tag: "20230606", Timestamp: parseTime("2023-06-06T00:00:00Z")},
{Tag: "v1.0.0", Timestamp: parseTime("2023-06-09T00:00:00Z")},
{Tag: "v1.1.0", Timestamp: parseTime("2023-06-10T00:00:00Z")},
}
// Mixed Numerical and SemVer along with Older images pushed more recently
badTags := []api.ImageTag{
{Tag: "v1.0.0", Timestamp: parseTime("2023-06-01T00:00:00Z")},
{Tag: "v1.1.0", Timestamp: parseTime("2023-06-02T00:00:00Z")},
{Tag: "9999999", Timestamp: parseTime("2023-06-03T00:00:00Z")},
{Tag: "v1.1.1-alpha", Timestamp: parseTime("2023-06-03T00:00:00Z")},
{Tag: "v1.1.1", Timestamp: parseTime("2023-06-04T00:00:00Z")},
{Tag: "v2.0.0", Timestamp: parseTime("2023-06-05T00:00:00Z")},
{Tag: "v1.1.1", Timestamp: parseTime("2023-06-06T00:00:00Z")},
}

tests := []struct {
name string
opts *api.Options
expected string
tags []api.ImageTag
}{
{
name: "No constraints",
opts: &api.Options{},
expected: "v2.0.0",
},
{
name: "Regex match v1.*",
opts: &api.Options{
RegexMatcher: regexp.MustCompile("v1.*"),
},
expected: "v1.1.1",
},
{
name: "Pin major version 1",
opts: &api.Options{
PinMajor: intPtr(1),
},
expected: "v1.1.1",
},
{
name: "Pin minor version 1.1",
opts: &api.Options{
PinMajor: intPtr(1),
PinMinor: intPtr(1),
},
expected: "v1.1.1",
},
{
name: "Pin patch version 1.1.1",
opts: &api.Options{
PinMajor: intPtr(1),
PinMinor: intPtr(1),
PinPatch: intPtr(1),
},
expected: "v1.1.1",
},
{
name: "Exclude metadata",
opts: &api.Options{
UseMetaData: false,
},
expected: "v2.0.0",
},
{
name: "Include metadata",
opts: &api.Options{
UseMetaData: true,
},
expected: "v2.0.0",
},
{
name: "NoPrefixed Tags",
opts: &api.Options{},
tags: tagsNoPrefix,
expected: "2.0.0",
},
// Some Bad/Miss-behaving tags
{
name: "Bad Tags",
opts: &api.Options{
RegexMatcher: regexp.MustCompile(`^v(\d+)(\.\d+)?(\.\d+)?(.*)$`),
},
tags: badTags,
expected: "v2.0.0",
},
// None SemVer tags
{
name: "Non SemVer",
opts: &api.Options{
RegexMatcher: regexp.MustCompile(`^(\d+)`),
},
tags: nonSemVer,
expected: "20230605",
},
{
name: "Stopped SemVer",
opts: &api.Options{
RegexMatcher: regexp.MustCompile(`^(\d+)`),
},
tags: stoppedSemVer,
expected: "202306060",
},
{
name: "Started SemVer",
opts: &api.Options{
RegexMatcher: regexp.MustCompile(`^v(\d+)(\.\d+)?(\.\d+)?(.*)$`),
},
tags: startedSemVer,
expected: "v1.1.0",
},
{
name: "Alpha/Beta SemVer",
opts: &api.Options{
UseMetaData: true,
},
tags: alphaBetaTags,
expected: "v1.1.1",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if len(tt.tags) > 0 {
tags = tt.tags
}
tag, err := latestSemver(tt.opts, tags)
assert.NoError(t, err)
assert.NotNil(t, tag)
assert.Equal(t, tt.expected, tag.Tag)
})
}
}

func TestLatestSHA(t *testing.T) {
tests := []struct {
name string
tags []api.ImageTag
expectedSHA *string
}{
{
name: "Single tag",
tags: []api.ImageTag{
{SHA: "sha1", Timestamp: time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC)},
},
expectedSHA: strPtr("sha1"),
},
{
name: "Multiple tags, latest in the middle",
tags: []api.ImageTag{
{SHA: "sha1", Timestamp: time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC)},
{SHA: "sha2", Timestamp: time.Date(2023, time.January, 1, 0, 0, 0, 0, time.UTC)},
{SHA: "sha3", Timestamp: time.Date(2021, time.January, 1, 0, 0, 0, 0, time.UTC)},
},
expectedSHA: strPtr("sha2"),
},
{
name: "Multiple tags, latest at the end",
tags: []api.ImageTag{
{SHA: "sha1", Timestamp: time.Date(2021, time.January, 1, 0, 0, 0, 0, time.UTC)},
{SHA: "sha2", Timestamp: time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC)},
{SHA: "sha3", Timestamp: time.Date(2023, time.January, 1, 0, 0, 0, 0, time.UTC)},
},
expectedSHA: strPtr("sha3"),
},
{
name: "No tags",
tags: []api.ImageTag{},
expectedSHA: nil,
},
{
name: "All tags with the same timestamp",
tags: []api.ImageTag{
{SHA: "sha1", Timestamp: time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC)},
{SHA: "sha2", Timestamp: time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC)},
{SHA: "sha3", Timestamp: time.Date(2022, time.January, 1, 0, 0, 0, 0, time.UTC)},
},
expectedSHA: strPtr("sha1"),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := latestSHA(tt.tags)
if err != nil {
t.Errorf("latestSHA() error = %v", err)
return
}
if (got == nil && tt.expectedSHA != nil) || (got != nil && tt.expectedSHA == nil) {
t.Errorf("latestSHA() = %v, want %v", got, tt.expectedSHA)
return
}
if got != nil && got.SHA != *tt.expectedSHA {
t.Errorf("latestSHA() = %v, want %v", got.SHA, *tt.expectedSHA)
}
})
}
}

func intPtr(i int64) *int64 {
return &i
}

func strPtr(s string) *string {
return &s
}
Loading