158 lines
5.7 KiB
Go
158 lines
5.7 KiB
Go
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", "<html><table><tr><td>synthetic</td></tr></table></html>", "text/html", `attachment; filename="requests.xls"`, "html"},
|
|
{"html-excel-mime", "<table><tr><td>synthetic</td></tr></table>", "application/vnd.ms-excel", "", "html"},
|
|
{"login-table", "<html><table>private-secret Login</table></html>", "text/html", "", ""},
|
|
{"login-attachment", "<html>private-secret Login</html>", "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)
|
|
}
|
|
}
|