a8cdeeb838
- internal/nsdadapter/igw/client.go: REST-клиент ИШ (SendPackage, GetStatus, ListIncoming) с base64-JSON, ретраями на 5xx, 4xx без ретраев - internal/nsdadapter/router.go: маршрутизация MessageKind -> PackageType ЭДО (#M2MTR, #M2MTD, #M2MER, SUBBR/SUBER/SUB16, Assets_investment) - internal/nsdadapter/sender.go: реализация m2mcore.NSDSender (Send/SendDecision) через REST ИШ, сериализация Request/Decision в windows-1251 - internal/nsdadapter/config.go: профили guest/test3/prod × gost/rsa (URL ИШ, канал, контейнер ключа, retry) - internal/nsdadapter/onyx/onyx.go: скелет резервного канала WS ONYX (ждёт PR-6 crypto-service для подписи) - cmd/nsd-adapter/main.go: HTTP /healthz + фоновый поллер входящих по типам ЭДО; idle-режим без BJ_NSD_PROFILE make ci зелёный. Без внешних Go-зависимостей. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
136 lines
3.9 KiB
Go
136 lines
3.9 KiB
Go
package igw_test
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/nsdadapter/igw"
|
|
)
|
|
|
|
func TestSendPackageHappyPath(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/api/package/TEST3/file" {
|
|
t.Errorf("неожиданный путь %q", r.URL.Path)
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
_ = json.NewEncoder(w).Encode(map[string]string{"package_id": "pkg-123"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := igw.NewClient(srv.URL, igw.WithRetry(0, time.Millisecond))
|
|
id, err := c.SendPackage(context.Background(), "TEST3", "#M2MTR", []byte("<xml/>"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if id != "pkg-123" {
|
|
t.Errorf("package_id = %q, ожидалось %q", id, "pkg-123")
|
|
}
|
|
}
|
|
|
|
func TestSendPackageRetryOn500(t *testing.T) {
|
|
calls := 0
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
calls++
|
|
if calls < 2 {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
_ = json.NewEncoder(w).Encode(map[string]string{"package_id": "pkg-retry"})
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := igw.NewClient(srv.URL, igw.WithRetry(3, time.Millisecond))
|
|
id, err := c.SendPackage(context.Background(), "TEST3", "#M2MTR", []byte("x"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if id != "pkg-retry" {
|
|
t.Errorf("ожидалось pkg-retry, получено %q", id)
|
|
}
|
|
if calls < 2 {
|
|
t.Errorf("ожидалось хотя бы 2 попытки, получено %d", calls)
|
|
}
|
|
}
|
|
|
|
func TestSendPackage4xxNoRetry(t *testing.T) {
|
|
calls := 0
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
calls++
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
_, _ = w.Write([]byte(`{"error":"bad"}`))
|
|
}))
|
|
defer srv.Close()
|
|
|
|
c := igw.NewClient(srv.URL, igw.WithRetry(3, time.Millisecond))
|
|
_, err := c.SendPackage(context.Background(), "TEST3", "#M2MTR", []byte("x"))
|
|
if err == nil {
|
|
t.Fatal("ожидалась ошибка на 400")
|
|
}
|
|
if calls != 1 {
|
|
t.Errorf("4xx не должен ретраиться, попыток = %d", calls)
|
|
}
|
|
}
|
|
|
|
func TestGetStatus(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if r.URL.Path != "/api/package/status/pkg-1" {
|
|
t.Errorf("неожиданный путь %q", r.URL.Path)
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
_, _ = w.Write([]byte(`{"package_id":"pkg-1","state":"delivered","updated_at":"2026-03-02T14:30:00Z"}`))
|
|
}))
|
|
defer srv.Close()
|
|
c := igw.NewClient(srv.URL, igw.WithRetry(0, time.Millisecond))
|
|
st, err := c.GetStatus(context.Background(), "pkg-1")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if st.State != "delivered" {
|
|
t.Errorf("state = %q, ожидалось delivered", st.State)
|
|
}
|
|
}
|
|
|
|
func TestListIncoming(t *testing.T) {
|
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if !contains(r.URL.RawQuery, "channel=TEST3") {
|
|
t.Errorf("в query нет channel: %s", r.URL.RawQuery)
|
|
}
|
|
w.WriteHeader(http.StatusOK)
|
|
_, _ = w.Write([]byte(`{"items":[{"package_id":"p1","package_type":"#M2MTD","channel":"TEST3","received_at":"2026-03-02T14:00:00Z","body":""}]}`))
|
|
}))
|
|
defer srv.Close()
|
|
c := igw.NewClient(srv.URL, igw.WithRetry(0, time.Millisecond))
|
|
pkgs, err := c.ListIncoming(context.Background(), "TEST3", time.Now().Add(-time.Hour), "#M2MTD")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(pkgs) != 1 || pkgs[0].PackageType != "#M2MTD" {
|
|
t.Errorf("неожиданный результат: %+v", pkgs)
|
|
}
|
|
body, err := pkgs[0].DecodeBody()
|
|
if err != nil {
|
|
t.Errorf("DecodeBody: %v", err)
|
|
}
|
|
if body != nil {
|
|
t.Errorf("ожидалось пустое тело")
|
|
}
|
|
}
|
|
|
|
func contains(s, substr string) bool {
|
|
return len(s) >= len(substr) && (indexOf(s, substr) >= 0)
|
|
}
|
|
|
|
func indexOf(s, substr string) int {
|
|
for i := 0; i+len(substr) <= len(s); i++ {
|
|
if s[i:i+len(substr)] == substr {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|