Учёт DEPO в мастере: поле базы, логин и пароль bj на экране, скрипт показывается на странице

База DEPO — видимое поле (необязательно: пусто — найдётся по учётным таблицам), порт заполнен
по умолчанию. «Отдать скрипт администратору»: логин и пароль bj видны и меняются, «Показать
скрипт» выводит его на странице с кнопкой «Скопировать». В начале скрипта — блок «Проверьте
перед запуском»: @db и @pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
zuevav
2026-10-06 13:35:01 +03:00
parent 46cbebaff7
commit be83b86747
6 changed files with 155 additions and 35 deletions
+39 -1
View File
@@ -351,7 +351,7 @@ func TestFromLocalBundle(t *testing.T) {
func TestDepoSetupScript(t *testing.T) {
f := FancyMSSQLSettings{}
s := depoSetupScript(f, "", "bj_user", "Pass1word", true)
for _, want := range []string{"DECLARE @db sysname = N'';", "OD_FACES", "CREATE LOGIN [bj_user] WITH PASSWORD = N''Pass1word''", "FTV_M2M_EVENTS", "db_datareader", "sp_add_job @job_name = N'bj2depo'", "@database_name = @db", "SQLAgentReaderRole"} {
for _, want := range []string{"DECLARE @db sysname = N'';", "DECLARE @pass nvarchar(128) = N'Pass1word';", "OD_FACES", "CREATE LOGIN [bj_user] WITH PASSWORD = N''' + REPLACE(@pass, N'''', N'''''')", "FTV_M2M_EVENTS", "db_datareader", "sp_add_job @job_name = N'bj2depo'", "@database_name = @db", "SQLAgentReaderRole"} {
if !strings.Contains(s, want) {
t.Fatalf("в скрипте нет %q", want)
}
@@ -443,6 +443,7 @@ func TestDumpOnboardingPages(t *testing.T) {
t.Fatal(err)
}
_ = os.WriteFile(filepath.Join(dir, "prepare.html"), []byte(b.String()), 0o644)
_ = os.WriteFile(filepath.Join(dir, "depo-script.sql"), []byte(depoSetupScript(FancyMSSQLSettings{}, "", "bj_user", "Xk7pQ2mN9vR4tL8wZ3hB6cJd", true)), 0o644)
}
// Первая страница (администратор) — для снимка в TestDumpOnboardingPages.
@@ -457,3 +458,40 @@ func TestDumpFirstRunPage(t *testing.T) {
}
_ = os.WriteFile(filepath.Join(dir, "first-run.html"), []byte(b.String()), 0o644)
}
// «Отдать скрипт администратору»: скрипт показывается на странице с базой и паролем с экрана, пароль
// запоминается (с ним bj потом проверяет подключение); короткий пароль не принимается.
func TestDepoScriptView(t *testing.T) {
priv := testLicenseKey(t)
rc := testRC(t)
now := time.Now().UTC()
tok := signTestLicense(t, priv, &license.License{Schema: 1, ID: "lic-1", Tenant: "Тест", Product: "bj-server", Plan: license.PlanPro,
IssuedAt: now, ExpiresAt: now.Add(30 * 24 * time.Hour), ContractUntil: now.AddDate(1, 0, 0), Features: []string{"updates", "quik-mnp"}})
if err := rc.SaveLicense(LicenseSettings{Key: tok}); err != nil {
t.Fatal(err)
}
old := globalRC
globalRC = rc
defer func() { globalRC = old }()
h := &setupHandlers{rc: rc}
post := func(form url.Values) *httptest.ResponseRecorder {
r := httptest.NewRequest(http.MethodPost, "/admin/setup/wizard-depo/script.sql", strings.NewReader(form.Encode()))
r.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder()
h.wizardDepoScript(w, r)
return w
}
form := url.Values{"server": {"10.0.0.5"}, "port": {"1433"}, "db_type": {"mssql"}, "depo_database": {"DEPO_X"},
"mode": {"script"}, "bj_user": {"bj_user"}, "bj_password": {"Secret123x"}, "depo_job": {"agent"}, "view": {"1"}}
w := post(form)
if w.Code != http.StatusOK || !strings.Contains(w.Body.String(), "DECLARE @db sysname = N'DEPO_X';") || !strings.Contains(w.Body.String(), "N'Secret123x';") {
t.Fatalf("показ скрипта: %d %s", w.Code, w.Body.String()[:min(300, w.Body.Len())])
}
if f := rc.Snapshot().Fancy; f.User != "bj_user" || f.Password != "Secret123x" || f.DepoTablesMode != "script" {
t.Fatalf("логин и пароль bj не запомнились: %+v", f.User)
}
form.Set("bj_password", "short")
if w := post(form); w.Code != http.StatusBadRequest || !strings.Contains(w.Body.String(), "8 знаков") {
t.Fatalf("короткий пароль: %d %s", w.Code, w.Body.String())
}
}