package liturgy import ( "net/http" "net/http/httptest" "os" "strings" "testing" "time" ) func TestHarvestAndOffline(t *testing.T) { html, _ := os.ReadFile("testdata/2026-07-22.html") srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.Contains(r.URL.Path, "2026-07-22") { w.Write(html) } else { w.Write([]byte("Przykro nam")) // horizon } })) defer srv.Close() t.Setenv("XDG_CACHE_HOME", t.TempDir()) t.Setenv("XDG_DATA_HOME", t.TempDir()) baseURL = srv.URL + "/liturgia/%s/Ewangelia" added, _, err := Harvest("2026-07-22", 3) if err != nil || added < 1 { t.Fatalf("harvest: added=%d err=%v", added, err) } secs, err := LoadOffline("2026-07-22") if err != nil { t.Fatal(err) } var haveGospel bool var haveFirstCzytanie bool for _, s := range secs { if s.Citation == "J 20, 1. 11-18" && s.PartID == "ewangelia" { haveGospel = true } if strings.HasPrefix(s.Heading, "1. czytanie") && s.PartID == "pierwsze_czytanie" { haveFirstCzytanie = true } } if !haveGospel { t.Error("offline gospel citation or PartID missing") } if !haveFirstCzytanie { t.Error("offline first czytanie PartID missing") } } // TestHarvestFetchErrorSavesPartialProgress exercises the transient-error // path: a genuine network/transport failure on a date must NOT be mistaken // for the unpublished horizon (that is Parse's job, on a "Przykro nam" page // -- see TestHarvestAndOffline above, which stays nil-error). It must // instead surface as a returned error, after writeSigla has still saved // whatever was harvested before the failing date. func TestHarvestFetchErrorSavesPartialProgress(t *testing.T) { html, _ := os.ReadFile("testdata/2026-07-22.html") srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if strings.Contains(r.URL.Path, "2026-07-22") { w.Write(html) return } // Simulate a network/transport error (not a "Przykro nam" horizon // page) by hijacking the connection and closing it without a // response, so the client sees a read/EOF error. hj, ok := w.(http.Hijacker) if !ok { t.Fatal("test server ResponseWriter does not support hijacking") } conn, _, err := hj.Hijack() if err != nil { t.Fatal(err) } conn.Close() })) defer srv.Close() t.Setenv("XDG_CACHE_HOME", t.TempDir()) t.Setenv("XDG_DATA_HOME", t.TempDir()) baseURL = srv.URL + "/liturgia/%s/Ewangelia" origRetries, origDelay := harvestRetries, harvestRetryDelay harvestRetries, harvestRetryDelay = 2, time.Millisecond defer func() { harvestRetries, harvestRetryDelay = origRetries, origDelay }() added, furthest, err := Harvest("2026-07-22", 0) if err == nil { t.Fatal("harvest: want error on a fetch failure, got nil") } if added != 1 || furthest != "2026-07-22" { t.Errorf("harvest: added=%d furthest=%q, want added=1 furthest=2026-07-22 (only the one date fetched before the network error)", added, furthest) } // Progress made before the failing date must still be on disk. secs, offErr := LoadOffline("2026-07-22") if offErr != nil || len(secs) == 0 { t.Errorf("harvest: partial progress not saved: offErr=%v secs=%v", offErr, secs) } }