@@ -934,6 +934,37 @@ func TestUpsertCreatesSeriesFromClient(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// The wire's finished flag is derived, never stored: the Upsert's explicit
|
||||
// column list does not name finished_at — the same omission that protects
|
||||
// cover — so a client echoing a cached flag, true or false, cannot change the
|
||||
// Series' retired state (issues #157, #160).
|
||||
func TestUpsertCannotWriteSeriesFinished(t *testing.T) {
|
||||
store := newTestStore(t)
|
||||
seedFinished(t, store, "asura:done", "https://asurascans.com/comics/asura:done")
|
||||
|
||||
for _, sent := range []bool{true, false} {
|
||||
stored, err := store.Upsert(store.OwnerID(), Bookmark{
|
||||
Key: "asura:done", Site: "asura", SeriesID: "done",
|
||||
Finished: sent, UpdatedAt: 2000,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Upsert(Finished: %v): %v", sent, err)
|
||||
}
|
||||
if !stored.Finished {
|
||||
t.Fatalf("stored.Finished = false after echoing %v, want true", sent)
|
||||
}
|
||||
}
|
||||
var finishedAt int64
|
||||
if err := store.db.QueryRow(
|
||||
`SELECT finished_at FROM series WHERE site = $1 AND series_id = $2`,
|
||||
"asura", "done").Scan(&finishedAt); err != nil {
|
||||
t.Fatalf("read finished_at: %v", err)
|
||||
}
|
||||
if finishedAt != 1000 {
|
||||
t.Fatalf("series.finished_at = %v, want the seeded 1000 untouched", finishedAt)
|
||||
}
|
||||
}
|
||||
|
||||
// The hook is what starts creation-time acquisition, so it must fire exactly
|
||||
// once per Series — on the PUT that created it, and on no later one, whichever
|
||||
// Reader sends it.
|
||||
|
||||
Reference in New Issue
Block a user