| 1 | package main |
| 2 | |
| 3 | import ( |
| 4 | "encoding/json" |
| 5 | "fmt" |
| 6 | "testing" |
| 7 | |
| 8 | "github.com/carlosframework/platform/internal/rolloutwords" |
| 9 | "github.com/carlosframework/platform/internal/updatewords" |
| 10 | ) |
| 11 | |
| 12 | // Astra I1 #12: the reason is the EFFECTIVE one the box reports, whether the |
| 13 | // record set it or the app's default did; an inherited major hold names its |
| 14 | // number from the report. |
| 15 | func TestUpdatesReason(t *testing.T) { |
| 16 | two := 2 |
| 17 | tx := updatewords.Text |
| 18 | for _, c := range []struct { |
| 19 | u *apiUpdatesJoin |
| 20 | settingsDefault bool |
| 21 | want string |
| 22 | }{ |
| 23 | {nil, true, ""}, |
| 24 | {&apiUpdatesJoin{Reason: "adopt", Enforced: true}, true, ""}, |
| 25 | {&apiUpdatesJoin{Reason: "manual", Detail: "v1", Enforced: true}, false, fmt.Sprintf(tx("settings.box.reason.manual"), "v1")}, |
| 26 | {&apiUpdatesJoin{Reason: "pin", Detail: "v3", Enforced: true}, false, fmt.Sprintf(tx("settings.box.reason.pin"), "v3")}, |
| 27 | {&apiUpdatesJoin{Reason: "request", Detail: "v5", Enforced: true}, false, fmt.Sprintf(tx("settings.box.reason.request"), "v5")}, |
| 28 | {&apiUpdatesJoin{Reason: "failed", Detail: "v6", Enforced: true}, false, fmt.Sprintf(tx("settings.box.reason.failed"), "v6")}, |
| 29 | {&apiUpdatesJoin{Reason: "major", Detail: "v2", Major: &two, Enforced: true}, false, fmt.Sprintf(tx("settings.box.reason.major"), 2, "v2")}, |
| 30 | {&apiUpdatesJoin{Reason: "major", Detail: "v2", Major: &two, Baking: "v4", Enforced: true}, false, fmt.Sprintf(tx("settings.box.reason.major"), 2, "v2") + "; " + fmt.Sprintf(tx("settings.box.reason.baking"), "v4")}, |
| 31 | {&apiUpdatesJoin{Baking: "v4", Enforced: true}, false, fmt.Sprintf(tx("settings.box.reason.baking"), "v4")}, |
| 32 | {&apiUpdatesJoin{Enforced: false}, false, tx("settings.cli.not-enforced-reason")}, |
| 33 | {&apiUpdatesJoin{Enforced: false}, true, ""}, |
| 34 | {&apiUpdatesJoin{Reason: "unknown", Enforced: true}, false, tx("settings.box.reason.unknown")}, |
| 35 | {&apiUpdatesJoin{Reason: "new", Enforced: true}, false, tx("settings.box.reason.new")}, |
| 36 | // A reason word from a newer box renders nothing, and never panics. |
| 37 | {&apiUpdatesJoin{Reason: "from-the-future", Detail: "v9", Enforced: true}, false, ""}, |
| 38 | } { |
| 39 | if got := updatesReason(c.u, c.settingsDefault); got != c.want { |
| 40 | t.Errorf("updatesReason(%+v, %v) = %q, want %q", c.u, c.settingsDefault, got, c.want) |
| 41 | } |
| 42 | } |
| 43 | } |
| 44 | |
| 45 | // Astra I1 #11: the list record carries the report under update_report and |
| 46 | // the record's own setting under updates; both decode. |
| 47 | func TestTheListRecordDecodesBothUpdatesFields(t *testing.T) { |
| 48 | var r apiInstanceRecord |
| 49 | body := `{"host":"a.shop.example.com","updates":"manual","settings_default":false, |
| 50 | "update_report":{"reason":"manual","detail":"v1","enforced":true}}` |
| 51 | if err := json.Unmarshal([]byte(body), &r); err != nil { |
| 52 | t.Fatalf("decode: %v", err) |
| 53 | } |
| 54 | if r.UpdatesSetting != "manual" || r.Updates == nil || r.Updates.Reason != "manual" || r.SettingsDefault { |
| 55 | t.Fatalf("decoded %+v / %+v / %v", r.UpdatesSetting, r.Updates, r.SettingsDefault) |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | // The REASON cell: a rollout reason (a failure hold above all) outranks a |
| 60 | // preference; with none, the settings reason shows. |
| 61 | func TestReasonCellOrder(t *testing.T) { |
| 62 | manual := &apiUpdatesJoin{Reason: "manual", Detail: "v1", Enforced: true} |
| 63 | manualText := fmt.Sprintf(updatewords.Text("settings.box.reason.manual"), "v1") |
| 64 | held := &apiRollout{Installed: "v2", Serving: "v1", Awake: true, HeldBy: "v2"} |
| 65 | for _, c := range []struct { |
| 66 | name string |
| 67 | r apiInstanceRecord |
| 68 | want string |
| 69 | }{ |
| 70 | {"held outranks manual", apiInstanceRecord{Rollout: held, Updates: manual}, fmt.Sprintf(rolloutwords.StateHeld, "v2")}, |
| 71 | {"no rollout reason shows manual", apiInstanceRecord{Rollout: &apiRollout{Installed: "v1", Serving: "v1", Awake: true}, Updates: manual}, manualText}, |
| 72 | {"no rollout at all shows manual", apiInstanceRecord{Updates: manual}, manualText}, |
| 73 | {"nothing to say", apiInstanceRecord{}, ""}, |
| 74 | {"an old box on a default record", apiInstanceRecord{Updates: &apiUpdatesJoin{}, SettingsDefault: true}, ""}, |
| 75 | {"an old box on a held record", apiInstanceRecord{Updates: &apiUpdatesJoin{}}, updatewords.Text("settings.cli.not-enforced-reason")}, |
| 76 | } { |
| 77 | if got := reasonCell(c.r); got != c.want { |
| 78 | t.Errorf("%s: reasonCell = %q, want %q", c.name, got, c.want) |
| 79 | } |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | // Astra r1 (R18): a report the console cannot attribute to this instance's |
| 84 | // tenant reaches the list as whether the box enforces settings and nothing |
| 85 | // else. Enforced, it says nothing; not enforced, a non-default record still |
| 86 | // reads "settings not enforced". |
| 87 | func TestAnEnforcedOnlyReportReadsCorrectly(t *testing.T) { |
| 88 | for _, c := range []struct { |
| 89 | body string |
| 90 | want string |
| 91 | }{ |
| 92 | {`{"host":"h","settings_default":false,"update_report":{"enforced":true}}`, ""}, |
| 93 | {`{"host":"h","settings_default":true,"update_report":{"enforced":true}}`, ""}, |
| 94 | {`{"host":"h","settings_default":false,"update_report":{"enforced":false}}`, updatewords.Text("settings.cli.not-enforced-reason")}, |
| 95 | {`{"host":"h","settings_default":true,"update_report":{"enforced":false}}`, ""}, |
| 96 | } { |
| 97 | var r apiInstanceRecord |
| 98 | if err := json.Unmarshal([]byte(c.body), &r); err != nil { |
| 99 | t.Fatalf("decode %s: %v", c.body, err) |
| 100 | } |
| 101 | if got := reasonCell(r); got != c.want { |
| 102 | t.Errorf("%s: reasonCell = %q, want %q", c.body, got, c.want) |
| 103 | } |
| 104 | } |
| 105 | } |
| 106 | |