TestApplyReportsRestoreFailure covers the doubly-bad path: the promote rename fails AND the restore of the moved-aside binary also fails. Apply must surface the restore failure (not just the promote one) so the message reflects reality: execPath is now empty. Forced by occupying execPath with a dire
(t *testing.T)
| 152 | // reflects reality: execPath is now empty. Forced by occupying execPath with |
| 153 | // a directory inside the seam, so the restore os.Rename hits EISDIR. |
| 154 | func TestApplyReportsRestoreFailure(t *testing.T) { |
| 155 | asset := platformAsset(t) |
| 156 | body := []byte("verified new binary\n") |
| 157 | r := newFakeRelease(t, asset, body, hashOf(body)) |
| 158 | withReleaseURLs(t, r.srv.URL) |
| 159 | |
| 160 | tmpDir := t.TempDir() |
| 161 | exec := filepath.Join(tmpDir, "codehamr") |
| 162 | if err := os.WriteFile(exec, []byte("the original running binary\n"), 0o755); err != nil { |
| 163 | t.Fatal(err) |
| 164 | } |
| 165 | |
| 166 | orig := promoteRename |
| 167 | // Occupy the now-vacant execPath with a directory so the restore can't succeed. |
| 168 | promoteRename = func(_, to string) error { |
| 169 | _ = os.Mkdir(to, 0o755) |
| 170 | return fmt.Errorf("simulated promote failure") |
| 171 | } |
| 172 | t.Cleanup(func() { promoteRename = orig }) |
| 173 | |
| 174 | err := Apply(context.Background(), exec) |
| 175 | if err == nil { |
| 176 | t.Fatal("Apply must surface the failure") |
| 177 | } |
| 178 | if !strings.Contains(err.Error(), "restore") { |
| 179 | t.Fatalf("error must name the restore failure (binary may be missing), got: %v", err) |
| 180 | } |
| 181 | } |
| 182 | |
| 183 | // TestApplyAcceptsMatchingChecksum: positive case, a download whose hash |
| 184 | // equals the manifest entry promotes the binary into place. |
nothing calls this directly
no test coverage detected