package lkgateway import ( "net/http" "net/http/httptest" "path/filepath" "strings" "testing" "time" ) func TestLKPaperTypeAndPairs(t *testing.T) { for cfi, want := range map[string]string{"ESVXFR": "share", "EDSXFR": "depositary_receipt", "DBFXFR": "bond", "CEOGMR": "fund"} { if got := lkPaperType(cfi, ""); got != want { t.Fatalf("%s: %s", cfi, got) } } if lkPaperType("", "ОФЗ 26238 ПД обл") != "bond" || lkPaperType("", "БПИФ «Ликвидность» фонд") != "fund" { t.Fatal("по названию") } p := LKPortfolioSyncSettings{Pairs: "ДД-816=БР-859; мусор ;ДД-1 = БР-1"}.pairs() if len(p) != 2 || p[0].LK != "ДД-816" || p[0].Depo != "БР-859" || p[1].Depo != "БР-1" { t.Fatalf("%+v", p) } } func TestLKContractByAccount(t *testing.T) { def := LKPortfolioSyncSettings{} if got := lkContractByAccount(def, "ВТНКЦ00000816"); got != "ДД-816" { t.Fatalf("по умолчанию: %q", got) } if got := lkContractByAccount(def, "В00000816"); got != "" { t.Fatalf("не торговый счёт: %q", got) } other := LKPortfolioSyncSettings{AccountPrefix: "TR-", ContractTemplate: "D/{n}/2024"} if got := lkContractByAccount(other, "TR-0042"); got != "D/42/2024" { t.Fatalf("другое именование: %q", got) } } // Остатки общего запроса раскладываются по портфелям пар как в Dp01: совпадение или «портфель + пробел». func TestLKPortfolioByPort(t *testing.T) { all := map[string][]DepoPosition{ "БР-1001 Гравс Геннадий": {{AccountNum: "ВТНКЦ01", ISIN: "RU2", SecurityName: "Б"}, {AccountNum: "ВТНКЦ01", ISIN: "RU1", SecurityName: "А"}}, "БР-10011 Другой": {{AccountNum: "ВТНКЦ02", ISIN: "RU3", SecurityName: "В"}}, "БР-7": {{AccountNum: "ВТНКЦ07", ISIN: "RU4", SecurityName: "Г"}}, } by := lkPortfolioByPort(all, []lkPortfolioPair{{LK: "ДД-1", Depo: "БР-1001"}, {LK: "ДД-7", Depo: "БР-7"}, {LK: "ДД-9", Depo: "БР-9"}}) if p := by["БР-1001"]; len(p) != 2 || p[0].ISIN != "RU1" || p[1].ISIN != "RU2" { t.Fatalf("БР-1001: %+v", p) } if len(by["БР-7"]) != 1 || len(by["БР-9"]) != 0 || len(by) != 2 { t.Fatalf("%+v", by) } } // Итог заполнения: «нечего отправлять» — не ошибка, все договоры — под раскрытием. func TestLKPortfolioSummaryView(t *testing.T) { lkPortfolioState.Lock() saved := lkPortfolioState.m now := time.Now() lkPortfolioState.m = map[string]*LKPortfolioSyncState{ "ДД-1": {LK: "ДД-1", Depo: "БР-1-1", CheckedAt: now, Nothing: lkPortfolioNothing([]string{"x"}), Skipped: []string{"x"}}, "ДД-1006": {LK: "ДД-1006", Depo: "БР-1047", CheckedAt: now, PushedAt: now, Lines: 1}, "ДД-1007": {LK: "ДД-1007", Depo: "БР-1048", CheckedAt: now, Err: "DEPO: i/o timeout"}, "ДД-816": {LK: "ДД-816", Depo: "БР-859", CheckedAt: now, PushedAt: now, Lines: 3, manual: true}, } lkPortfolioState.Unlock() defer func() { lkPortfolioState.Lock(); lkPortfolioState.m = saved; lkPortfolioState.Unlock() }() sm := lkPortfolioSummary() if sm.Total != 3 || sm.Sent != 1 || sm.Nothing != 1 || sm.Errors != 1 || sm.Skipped != 1 || sm.Manual == nil || len(sm.Recent) != 1 { t.Fatalf("%+v", sm) } a, err := newAdmin() if err != nil { t.Fatal(err) } rec := httptest.NewRecorder() render(rec, a.setup, SetupData{page: nowPage("Настройка", "setup")}) body := rec.Body.String() for _, want := range []string{"Итог заполнения", "Все договоры (3)", "Договоры с ошибкой (1)", "Последние обновления", "Заливка одному клиенту"} { if !strings.Contains(body, want) { t.Errorf("нет %q", want) } } if strings.Contains(body, "ошибка — отправлять нечего") { t.Error("«отправлять нечего» показано как ошибка") } } // Маршруты карточки «Заполнение портфеля ДЕПО» зарегистрированы (29.09–22.10 их не было — 404). func TestLKPortfolioRoutes(t *testing.T) { mux := http.NewServeMux() rc, err := NewRuntimeConfig(filepath.Join(t.TempDir(), "setup.json")) if err != nil { t.Fatal(err) } registerSetup(mux, &admin{}, rc, nil) for _, p := range []string{"/admin/setup/lk-portfolio", "/admin/setup/lk-portfolio/clients"} { if _, pat := mux.Handler(httptest.NewRequest("GET", p, nil)); pat != p { t.Errorf("%s: маршрут %q", p, pat) } } }