internal/version/order_test.go
Ref: Size: 5.4 KiB History
package version
import "testing"
func TestLess(t *testing.T) {
cases := []struct {
a, b string
want bool
}{
{"v0.0.1", "v0.0.2", true},
{"v0.0.2", "v0.0.1", false},
{"v0.0.2", "v0.0.2", false},
{"v0.9.0", "v0.10.0", true}, // numeric, not lexicographic
{"dev", "v0.0.2", false}, // unparsable never upgrades
{"v0.0.1", "dev", false},
{"", "v0.0.2", false},
{"v0.0.2", "", false},
}
for _, c := range cases {
if got := Less(c.a, c.b); got != c.want {
t.Errorf("Less(%q,%q) = %v, want %v", c.a, c.b, got, c.want)
}
}
}
// TestLessOrdersGitDescribeBuilds pins the ordering of a git-describe build
// ("vX.Y.Z-N-g<hex>", N commits past tag vX.Y.Z) against a release tag: it
// sorts by (X, Y, Z, N), so a build derived from an older tag takes the
// upgrade while a build ahead of the latest release is never offered one.
func TestLessOrdersGitDescribeBuilds(t *testing.T) {
cases := []struct {
a, b string
want bool
}{
// A hand-deployed agent two commits past v0.0.2 upgrades to v0.0.3.
{"v0.0.2-2-g68f804d", "v0.0.3", true},
{"v0.0.3", "v0.0.2-2-g68f804d", false},
// A dev build ahead of the latest release is never downgraded onto it.
{"v0.0.3-5-gabc1234", "v0.0.3", false},
{"v0.0.3", "v0.0.3-5-gabc1234", true},
// The commit count breaks ties within one tag.
{"v0.0.3-2-gabc1234", "v0.0.3-5-gabc1234", true},
{"v0.0.3-5-gabc1234", "v0.0.3-2-gabc1234", false},
{"v0.0.3-5-gabc1234", "v0.0.3-5-gabc1234", false},
// A plain tag is the same build as zero commits past it.
{"v0.0.3-0-gabc1234", "v0.0.3", false},
{"v0.0.3", "v0.0.3-0-gabc1234", false},
// Release components still outrank the commit count.
{"v0.0.2-99-gabc1234", "v0.1.0", true},
{"v0.1.0-1-gabc1234", "v0.0.2-99-gabc1234", false},
// Uppercase hex is still a hex abbrev.
{"v0.0.2-2-gABC1234", "v0.0.3", true},
}
for _, c := range cases {
if got := Less(c.a, c.b); got != c.want {
t.Errorf("Less(%q,%q) = %v, want %v", c.a, c.b, got, c.want)
}
}
}
// TestLessOrdersPreReleases pins the chain a release cycle walks: each
// pre-release, the builds derived from it, the next pre-release, the release
// itself, and builds past that. An agent on a pre-release takes the next one
// and eventually the release, which is what lets a staging plane rehearse the
// upgrade path on the same tags the cycle produces.
func TestLessOrdersPreReleases(t *testing.T) {
// Every entry orders strictly before every entry after it.
chain := []string{
"v0.0.3",
"v0.0.4-pre.1",
"v0.0.4-pre.1-3-gabc1234",
"v0.0.4-pre.2",
"v0.0.4-pre.10", // numeric, not lexicographic
"v0.0.4",
"v0.0.4-2-gabc1234",
"v0.0.5-pre.1",
}
for i, a := range chain {
for j, b := range chain {
want := i < j
if got := Less(a, b); got != want {
t.Errorf("Less(%q,%q) = %v, want %v", a, b, got, want)
}
}
}
}
// TestLessLeavesUnstampedBuildsUnordered pins the shapes that stay
// unparsable: a dirty working tree or a malformed version never orders before
// anything, in either direction, so it is never offered an upgrade.
func TestLessLeavesUnstampedBuildsUnordered(t *testing.T) {
unstamped := []string{
"",
"dev",
"v0.0.3-dirty",
"v0.0.2-2-g68f804d-dirty",
"v0.0.4-pre", // no pre number
"v0.0.4-pre.", // empty pre number
"v0.0.4-pre.x", // pre number is not a number
"v0.0.4-pre.1.2", // pre number is not one component
"v0.0.4-pre.-1", // negative pre number
"v0.0.4-pre.1-dirty", // dirty past a pre-release
"v0.0.4-pre.1-3", // no g-abbrev past a pre-release
"v0.0.4-pre.1-g abc", // no commit count past a pre-release
"v0.0.4-prerelease.1", // not the pre. prefix
"v0.0.4-rc.1", // only "pre" is spelled this way
"v0.0.4-pre.99999999999999999999", // pre number out of range
"v0.0.2-x-g123", // commit count is not a number
"v0.0.2--2-g68f804d", // negative commit count
"v0.0.2-2", // no g-abbrev
"v0.0.2-2-g", // empty abbrev
"v0.0.2-2-gZZZ", // abbrev is not hex
"v0.0.2-2-68f804d", // abbrev missing its g
"v0.0.2-2-g68f804d-3", // trailing junk
"v-1.0.0", // negative major
"v0.-1.2", // negative minor
"v0.0", // too few components
"v0.0.2.1", // too many components
"v0.0.+2", // signed component
"v0.0.99999999999999999999", // component out of range
"v0.0.2-99999999999999999999-gabc", // commit count out of range
}
for _, u := range unstamped {
if Less(u, "v0.0.3") {
t.Errorf("Less(%q, %q) = true, want false", u, "v0.0.3")
}
if Less("v0.0.3", u) {
t.Errorf("Less(%q, %q) = true, want false", "v0.0.3", u)
}
}
}
// Ordered is the predicate behind Less's unparsable rule: it must agree with
// what Less can and cannot order, so a constant asserted well-formed through it
// is one Less will really rank.
func TestOrderedAgreesWithLess(t *testing.T) {
for _, v := range []string{"v0.0.3", "v0.0.4-pre.1", "v0.0.2-2-g68f804d"} {
if !Ordered(v) {
t.Errorf("Ordered(%q) = false, want true", v)
}
}
for _, v := range []string{"", "dev", "v0.0.3-dirty", "v0.0.4-rc.1"} {
if Ordered(v) {
t.Errorf("Ordered(%q) = true, want false", v)
}
}
}