| index 757e5eda6..f83539e28 100644 |
| --- a/internal/hostfiles/hostfiles_test.go |
| +++ b/internal/hostfiles/hostfiles_test.go |
| @@ -492,7 +492,16 @@ func TestRestoreHandlesADeepDirectoryBecomingAFile(t *testing.T) { |
| // A store whose manifest Put is applied and then reports a lost response, once. |
| type lostResponseStore struct { |
| release.Store |
| - armed bool |
| + armed bool |
| + getFail bool // the next Get of the manifest fails once |
| +} |
| + |
| +func (l *lostResponseStore) Get(ctx context.Context, key string) ([]byte, string, error) { |
| + if l.getFail && strings.HasSuffix(key, "manifest.json") { |
| + l.getFail = false |
| + return nil, "", errors.New("read timed out") |
| + } |
| + return l.Store.Get(ctx, key) |
| } |
| |
| func (l *lostResponseStore) Put(ctx context.Context, key string, body []byte, etag string) (string, error) { |
| @@ -580,3 +589,38 @@ func TestOverlappingLiveEntriesKeepTheNewerOne(t *testing.T) { |
| t.Fatalf("a/b = %q, superseded %v, written %d", got, st.Superseded, st.Written) |
| } |
| } |
| + |
| +func TestAFailedReReadAfterALostResponseIsNotASupersede(t *testing.T) { |
| + ctx := context.Background() |
| + s := &lostResponseStore{Store: release.NewDirStore(t.TempDir())} |
| + p := open(t, s) |
| + stage(t, p, "x", "1") |
| + s.armed = true |
| + if _, err := p.Commit(ctx); err == nil { |
| + t.Fatal("first commit should fail") |
| + } |
| + s.getFail = true |
| + if _, err := p.Commit(ctx); err == nil || errors.Is(err, ErrSuperseded) { |
| + t.Fatalf("second commit err = %v, want the read error, not ErrSuperseded", err) |
| + } |
| + if seq, err := p.Commit(ctx); err != nil || seq != 1 { |
| + t.Fatalf("third commit = %d, %v", seq, err) |
| + } |
| +} |
| + |
| +func TestThreeDeepOverlapKeepsTheNewestEntry(t *testing.T) { |
| + ctx, s := context.Background(), release.NewDirStore(t.TempDir()) |
| + p := open(t, s) |
| + stage(t, p, "a", "one") |
| + stage(t, p, "a/b/c", "three") |
| + stage(t, p, "a/b", "two") // the newest |
| + commit(t, p) |
| + dir := t.TempDir() |
| + _, st, err := Restore(ctx, s, pfx, dir) |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + if got := read(t, dir, "a/b"); got != "two" || st.Written != 1 || !reflect.DeepEqual(st.Superseded, []string{"a", "a/b/c"}) { |
| + t.Fatalf("a/b = %q, written %d, superseded %v", got, st.Written, st.Superseded) |
| + } |
| +} |