dana-medical-site/internal/prodoctorov/client_test.go
2026-10-14 13:33:13 +00:00

146 lines
4.9 KiB
Go

package prodoctorov
import (
"bytes"
"context"
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
)
func TestConfig(t *testing.T) {
c, err := New("", "")
if err != nil || c.Configured() {
t.Fatal("empty configuration must disable the connector")
}
for _, args := range [][2]string{{"", "82347"}, {"session=test", ""}, {"session=x\r\nInjected: bad", "82347"}, {"session=test", "-1"}, {"session=test", "82347&lpu=other"}, {"Cookie", "82347"}} {
if _, err := New(args[0], args[1]); err == nil {
t.Fatal("malformed configuration accepted")
}
}
}
func TestDownloadQueryAndCookie(t *testing.T) {
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/api/cabinet/lpu/appointments/direct/download/" || r.Method != "GET" ||
r.URL.Query().Get("month") != "10" || r.URL.Query().Get("year") != "2026" || r.URL.Query().Get("lpu") != "82347" ||
r.Header.Get("Cookie") != "session=synthetic" {
t.Error("wrong export request")
}
_, _ = w.Write([]byte{'P', 'K', 3, 4, 'x'})
}))
defer s.Close()
c, _ := New("session=synthetic", "82347")
c.endpoint = s.URL + "/api/cabinet/lpu/appointments/direct/download/"
data, err := c.Download(context.Background(), 2026, time.October)
if err != nil || !bytes.HasPrefix(data, []byte("PK")) {
t.Fatal("valid export failed", err)
}
}
func TestDownloadErrorsDoNotLeakResponse(t *testing.T) {
for _, status := range []int{200, 401, 403, 429, 500} {
t.Run(http.StatusText(status), func(t *testing.T) {
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(status)
_, _ = io.WriteString(w, "<html>patient-secret session=synthetic</html>")
}))
defer s.Close()
c, _ := New("session=synthetic", "82347")
c.endpoint = s.URL
_, err := c.Download(context.Background(), 2026, time.October)
if err == nil || strings.Contains(err.Error(), "patient-secret") || strings.Contains(err.Error(), "synthetic") {
t.Fatal("missing or leaking error")
}
})
}
}
func TestDownloadProtectionIsNotExpiredSession(t *testing.T) {
for _, tc := range []struct {
name string
status int
body string
want string
}{
{"forbidden", http.StatusForbidden, "<html>private challenge</html>", "HTTP 403, ответ через Servicepipe"},
{"challenge page", http.StatusOK, "<html>private challenge</html>", "другая страница через Servicepipe"},
} {
t.Run(tc.name, func(t *testing.T) {
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-SP-CRID", "private-request-id")
w.WriteHeader(tc.status)
_, _ = io.WriteString(w, tc.body)
}))
defer s.Close()
c, _ := New("session=synthetic", "82347")
c.endpoint = s.URL
_, err := c.Download(context.Background(), 2026, time.October)
if err == nil || !strings.Contains(err.Error(), tc.want) ||
strings.Contains(err.Error(), "private") || strings.Contains(err.Error(), "synthetic") {
t.Fatal("protection was misreported or secret data leaked")
}
})
}
}
func TestDownloadProtectionHeaderDoesNotRejectXLSX(t *testing.T) {
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-SP-CRID", "synthetic-request-id")
_, _ = w.Write([]byte{'P', 'K', 3, 4, 'x'})
}))
defer s.Close()
c, _ := New("session=synthetic", "82347")
c.endpoint = s.URL
if _, err := c.Download(context.Background(), 2026, time.October); err != nil {
t.Fatal("valid export rejected solely because of proxy header", err)
}
}
func TestRedirectDoesNotForwardSession(t *testing.T) {
for _, sameHost := range []bool{false, true} {
calls := 0
target := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { calls++ }))
var source *httptest.Server
source = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/login" {
calls++
return
}
location := target.URL
if sameHost {
location = source.URL + "/login"
}
http.Redirect(w, r, location, http.StatusFound)
}))
c, _ := New("session=synthetic", "82347")
c.endpoint = source.URL
_, err := c.Download(context.Background(), 2026, time.October)
source.Close()
target.Close()
if err == nil || calls != 0 {
t.Fatal("redirect followed or accepted")
}
}
}
func TestDownloadBoundAndCancellation(t *testing.T) {
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write(append([]byte{'P', 'K', 3, 4}, bytes.Repeat([]byte{'x'}, maxDownload)...))
}))
defer s.Close()
c, _ := New("session=synthetic", "82347")
c.endpoint = s.URL
if _, err := c.Download(context.Background(), 2026, time.October); err == nil {
t.Fatal("oversized export accepted")
}
ctx, cancel := context.WithCancel(context.Background())
cancel()
if _, err := c.Download(ctx, 2026, time.October); err != context.Canceled {
t.Fatal("cancellation lost", err)
}
}