package sberhealth import ( "bytes" "context" "io" "net/http" "net/http/httptest" "reflect" "strings" "testing" "time" ) func sampleDates() (time.Time, time.Time) { zone := time.FixedZone("Europe/Moscow", 10800) return time.Date(2026, 9, 28, 0, 0, 0, 0, zone), time.Date(2026, 10, 5, 0, 0, 0, 0, zone) } func TestConfig(t *testing.T) { c, err := New("", "") if err != nil || c.Configured() { t.Fatal("empty config must disable download") } for _, args := range [][2]string{{"", "294888"}, {"session=synthetic", ""}, {"Cookie", "294888"}, {"session=x\r\nInjected: x", "294888"}, {"session=x", "294888&other=1"}} { if _, err := New(args[0], args[1]); err == nil { t.Fatal("invalid config accepted") } } } func TestSuppliedURLFilters(t *testing.T) { from, till := sampleDates() s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { want := map[string][]string{ "kind": {"doctor"}, "clinic_id": {"294888"}, "periodInput": {"week"}, "crDateFrom": {"28.09.2026"}, "crDateTill": {"05.10.2026"}, "page": {"1"}, "admissionStatus": {"-1"}, "sourceType": {"-1"}, "type": {"xls"}, } if r.Method != "GET" || r.URL.Path != "/lk/requests/listOld" || !reflect.DeepEqual(map[string][]string(r.URL.Query()), want) || r.Header.Get("Cookie") != "session=synthetic" { t.Error("request does not reproduce supplied URL") } _, _ = w.Write([]byte{0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1}) })) defer s.Close() c, _ := New("session=synthetic", "294888") c.endpoint = s.URL + "/lk/requests/listOld" export, err := c.Download(context.Background(), from, till, "week") if err != nil || export.Format != "xls" { t.Fatal("XLS detection failed", err) } } func TestExportFormatDetectionAndLoginRejection(t *testing.T) { from, till := sampleDates() for _, tc := range []struct { name, body, ct, disposition, format string }{ {"xlsx", "PK\x03\x04placeholder", "application/octet-stream", "", "xlsx"}, {"html-xls", "
synthetic
", "text/html", `attachment; filename="requests.xls"`, "html"}, {"html-excel-mime", "
synthetic
", "application/vnd.ms-excel", "", "html"}, {"login-table", "private-secret Login
", "text/html", "", ""}, {"login-attachment", "private-secret Login", "text/html", `attachment; filename="requests.xls"`, ""}, {"json-error", `{"error":"private-secret"}`, "application/json", "", ""}, } { t.Run(tc.name, func(t *testing.T) { s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", tc.ct) w.Header().Set("Content-Disposition", tc.disposition) _, _ = io.WriteString(w, tc.body) })) defer s.Close() c, _ := New("session=synthetic", "294888") c.endpoint = s.URL export, err := c.Download(context.Background(), from, till, "week") if tc.format == "" { if err == nil || strings.Contains(err.Error(), "private-secret") { t.Fatal("unknown/login response accepted or leaked") } } else if err != nil || export.Format != tc.format { t.Fatal("format detection incorrect", err) } }) } } func TestErrorsAndRedirects(t *testing.T) { from, till := sampleDates() redirected := 0 target := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { redirected++ })) defer target.Close() for _, status := range []int{302, 401, 403, 429, 500} { s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Location", target.URL) w.WriteHeader(status) _, _ = io.WriteString(w, "private-secret") })) c, _ := New("session=synthetic", "294888") c.endpoint = s.URL export, err := c.Download(context.Background(), from, till, "week") s.Close() if err == nil || len(export.Data) != 0 || strings.Contains(err.Error(), "private-secret") { t.Fatal("missing or leaking error") } } if redirected != 0 { t.Fatal("redirect forwarded session") } } func TestMonthlyFiltersAndInvalidDates(t *testing.T) { zone := time.FixedZone("Europe/Moscow", 10800) from, till := time.Date(2026, 10, 1, 0, 0, 0, 0, zone), time.Date(2026, 10, 31, 0, 0, 0, 0, zone) requests := 0 s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { requests++ q := r.URL.Query() if q.Get("periodInput") != "month" || q.Get("crDateFrom") != "01.10.2026" || q.Get("crDateTill") != "31.10.2026" { t.Error("monthly date filters incorrect") } _, _ = w.Write([]byte("PK\x03\x04placeholder")) })) defer s.Close() c, _ := New("session=synthetic", "294888") c.endpoint = s.URL if _, err := c.Download(context.Background(), from, till, "month"); err != nil { t.Fatal(err) } for _, args := range []struct { from, till time.Time mode string }{{till, from, "week"}, {from.Add(time.Hour), till, "week"}, {from, till, "auto"}, {from, from.AddDate(2, 0, 0), "month"}} { if _, err := c.Download(context.Background(), args.from, args.till, args.mode); err == nil { t.Fatal("invalid filters accepted") } } if requests != 1 { t.Fatal("invalid filters reached server") } } func TestSizeLimitAndCancellation(t *testing.T) { from, till := sampleDates() s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write(append([]byte("PK\x03\x04"), bytes.Repeat([]byte{'x'}, maxDownload)...)) })) defer s.Close() c, _ := New("session=synthetic", "294888") c.endpoint = s.URL if _, err := c.Download(context.Background(), from, till, "week"); err == nil { t.Fatal("oversized download accepted") } ctx, cancel := context.WithCancel(context.Background()) cancel() if _, err := c.Download(ctx, from, till, "week"); err != context.Canceled { t.Fatal("cancellation lost", err) } }