|
4 | 4 | "encoding/json" |
5 | 5 | "errors" |
6 | 6 | "io" |
| 7 | + "os" |
| 8 | + "path/filepath" |
7 | 9 | "strings" |
8 | 10 | "testing" |
9 | 11 |
|
@@ -98,3 +100,82 @@ func TestWriteSetupResultText(t *testing.T) { |
98 | 100 | t.Errorf("stderr = %q, want no note when the state was saved", saved.err.String()) |
99 | 101 | } |
100 | 102 | } |
| 103 | + |
| 104 | +// The table pads its columns two spaces past their widest cell. |
| 105 | +func TestWriteReportTableAlignsTheColumns(t *testing.T) { |
| 106 | + var buf strings.Builder |
| 107 | + writeReportTable(&buf, sampleReport()) |
| 108 | + want := "✔ docker-daemon Docker daemon reachable (server 27.0)\n" + |
| 109 | + "⚠ build-cache-export cannot export cache\n" + |
| 110 | + " → build-cache-export: run `devcontainer setup`\n" + |
| 111 | + "\noverall: ⚠ warn\n" |
| 112 | + if buf.String() != want { |
| 113 | + t.Errorf("table =\n%s\nwant\n%s", buf.String(), want) |
| 114 | + } |
| 115 | +} |
| 116 | + |
| 117 | +// runCheckWithoutDocker runs check against a docker CLI that does not exist, |
| 118 | +// so the daemon check fails, with the check state under stateHome. |
| 119 | +func runCheckWithoutDocker(t *testing.T, out Output, json bool, stateHome string) error { |
| 120 | + t.Helper() |
| 121 | + t.Setenv("XDG_STATE_HOME", stateHome) |
| 122 | + return runCheck(t.Context(), out, &checkOpts{json: json, dockerPath: filepath.Join(t.TempDir(), "docker")}) |
| 123 | +} |
| 124 | + |
| 125 | +// A failing host prints the table, saves the state and exits 1. |
| 126 | +func TestRunCheckFailingHostExitsOne(t *testing.T) { |
| 127 | + state := t.TempDir() |
| 128 | + out := &captureOutput{} |
| 129 | + err := runCheckWithoutDocker(t, out, false, state) |
| 130 | + if exitCode(err) != 1 { |
| 131 | + t.Fatalf("err = %v, want exit code 1 for a failing host", err) |
| 132 | + } |
| 133 | + if s := out.out.String(); !strings.HasSuffix(s, "\noverall: ✖ fail\n") { |
| 134 | + t.Errorf("stdout = %q, want the table of a failing host", s) |
| 135 | + } |
| 136 | + if out.err.Len() != 0 { |
| 137 | + t.Errorf("stderr = %q, want nothing when the state was saved", out.err.String()) |
| 138 | + } |
| 139 | + saved, ok, err := doctor.LoadFrom(filepath.Join(state, "devcontainer", "check.json")) |
| 140 | + if err != nil || !ok || saved.Overall != doctor.StatusFail { |
| 141 | + t.Errorf("saved state = %+v, %v, %v; want the failing report", saved, ok, err) |
| 142 | + } |
| 143 | +} |
| 144 | + |
| 145 | +// A state that cannot be saved is a note on stderr, not a failure of its own. |
| 146 | +func TestRunCheckNotesAStateItCouldNotSave(t *testing.T) { |
| 147 | + blocker := filepath.Join(t.TempDir(), "file") |
| 148 | + if err := os.WriteFile(blocker, nil, 0o644); err != nil { |
| 149 | + t.Fatal(err) |
| 150 | + } |
| 151 | + out := &captureOutput{} |
| 152 | + err := runCheckWithoutDocker(t, out, false, blocker) |
| 153 | + if exitCode(err) != 1 { |
| 154 | + t.Fatalf("err = %v, want exit code 1 for a failing host", err) |
| 155 | + } |
| 156 | + if s := out.err.String(); !strings.HasPrefix(s, "note: could not save check state: ") { |
| 157 | + t.Errorf("stderr = %q, want the note", s) |
| 158 | + } |
| 159 | +} |
| 160 | + |
| 161 | +// --json prints the report as JSON and still exits 1 for a failing host; a |
| 162 | +// stdout that cannot be written fails with that error. |
| 163 | +func TestRunCheckJSON(t *testing.T) { |
| 164 | + out := &captureOutput{} |
| 165 | + err := runCheckWithoutDocker(t, out, true, t.TempDir()) |
| 166 | + if exitCode(err) != 1 { |
| 167 | + t.Fatalf("err = %v, want exit code 1 for a failing host", err) |
| 168 | + } |
| 169 | + var got doctor.Report |
| 170 | + if err := json.Unmarshal(out.out.Bytes(), &got); err != nil { |
| 171 | + t.Fatalf("stdout is not JSON: %v\n%s", err, out.out.String()) |
| 172 | + } |
| 173 | + if got.Overall != doctor.StatusFail || len(got.Results) == 0 { |
| 174 | + t.Errorf("report = %+v, want a failing report", got) |
| 175 | + } |
| 176 | + |
| 177 | + err = runCheckWithoutDocker(t, &brokenStdout{}, true, t.TempDir()) |
| 178 | + if err == nil || !strings.Contains(err.Error(), "stdout closed") { |
| 179 | + t.Fatalf("err = %v, want the write error", err) |
| 180 | + } |
| 181 | +} |
0 commit comments