package appupdate import "testing" func policy() Policy { return Policy{ Enabled: true, LatestVersion: "0.1.54", MinimumVersion: "0.1.50", DownloadURL: "https://nas.example.com/memby/memby-0.1.54.apk", SHA256: "abcdef", SizeBytes: 42, Notes: "Faster home screen", } } func TestUpToDateClientIsLeftAlone(t *testing.T) { for _, version := range []string{"0.1.54", "0.1.55", "0.2.0", "1.0.0"} { if got := Decide(policy(), version).Status; got != StatusNone { t.Fatalf("client %s: got %s, want none", version, got) } } } func TestBehindLatestIsOptional(t *testing.T) { decision := Decide(policy(), "0.1.53") if decision.Status != StatusOptional { t.Fatalf("got %s, want optional", decision.Status) } if decision.Version != "0.1.54" || decision.DownloadURL == "" { t.Fatalf("decision is missing what the TV needs to act: %+v", decision) } if decision.SHA256 != "abcdef" || decision.SizeBytes != 42 { t.Fatalf("decision dropped release integrity metadata: %+v", decision) } } func TestBelowMinimumIsMandatory(t *testing.T) { if got := Decide(policy(), "0.1.49").Status; got != StatusMandatory { t.Fatalf("got %s, want mandatory", got) } } // Setting minimum = latest is how an operator forces everyone onto the current build. func TestMinimumEqualToLatestForcesEveryOldClient(t *testing.T) { p := policy() p.MinimumVersion = p.LatestVersion if got := Decide(p, "0.1.53").Status; got != StatusMandatory { t.Fatalf("got %s, want mandatory", got) } if got := Decide(p, "0.1.54").Status; got != StatusNone { t.Fatalf("a current client should still be left alone, got %s", got) } } func TestBlankMinimumKeepsUpdatesOptional(t *testing.T) { p := policy() p.MinimumVersion = "" if got := Decide(p, "0.0.1").Status; got != StatusOptional { t.Fatalf("got %s, want optional", got) } } func TestDisabledPolicySaysNothing(t *testing.T) { p := policy() p.Enabled = false if got := Decide(p, "0.0.1").Status; got != StatusNone { t.Fatalf("got %s, want none", got) } } func TestPolicyWithNoLatestVersionSaysNothing(t *testing.T) { p := policy() p.LatestVersion = " " if got := Decide(p, "0.0.1").Status; got != StatusNone { t.Fatalf("got %s, want none", got) } } // A client that cannot report its version must not be hard-blocked: it would be stuck // behind a prompt it may have no way to satisfy. func TestUnknownClientVersionIsNeverForced(t *testing.T) { p := policy() p.MinimumVersion = p.LatestVersion for _, version := range []string{"", " ", "?", "unknown"} { if got := Decide(p, version).Status; got != StatusNone { t.Fatalf("client %q: got %s, want none", version, got) } } } func TestVersionParsingIsForgiving(t *testing.T) { p := policy() // Leading "v", pre-release suffixes and short versions all compare sensibly. if got := Decide(p, "v0.1.53").Status; got != StatusOptional { t.Fatalf("v-prefixed: got %s, want optional", got) } if got := Decide(p, "0.1.54-beta").Status; got != StatusNone { t.Fatalf("pre-release suffix should compare as 0.1.54, got %s", got) } p.LatestVersion = "0.2" if got := Decide(p, "0.2.0").Status; got != StatusNone { t.Fatalf("0.2.0 should equal 0.2, got %s", got) } } func TestMandatoryOutranksOptional(t *testing.T) { p := policy() p.MinimumVersion = "0.1.53" // Below both thresholds: the stronger verdict must win. if got := Decide(p, "0.1.52").Status; got != StatusMandatory { t.Fatalf("got %s, want mandatory", got) } }