Учёт DEPO: задание SQL Server Agent — своё у каждой базы (bj2depo_<база>), имя в мастере

На одном сервере бывает несколько баз DEPO (боевая и тестовая): общее имя
bj2depo давало ложную зелёную проверку — тестовой базе засчитывалось боевое
задание, а своё не создавалось.
- Имя задания — настройка DepoJobName; в мастере, пункт 3, поле «Имя задания
  SQL Server Agent», по умолчанию bj2depo_<имя базы> (меняется вместе с базой,
  пока его не поправили). Установки старше — bj2depo, как было.
- Скрипт до любых изменений останавливается, если задание с этим именем
  обрабатывает другую базу или эту базу уже обрабатывает задание с другим именем
  (иначе двойная обработка событий).
- Проверка задания сравнивает его базу (sp_help_jobstep) с базой bj.
Синтаксис проверен на SQL Server без выполнения (SET PARSEONLY); проверка
задания на боевом сервере — зелёная (bj2depo ↔ BJ_DEPO_DATA).

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 16:09:14 +03:00
parent 42524f6a4f
commit 21d87fb530
8 changed files with 135 additions and 25 deletions
+28
View File
@@ -375,6 +375,21 @@ func TestDepoSetupScript(t *testing.T) {
}
}
}
// задание — по базе: своё имя, и до любых изменений — стоп, если имя занято другой базой или эту базу
// уже обрабатывает другое задание
named := depoSetupScript(FancyMSSQLSettings{DepoJobName: "bj2depo_DEPO_DATA"}, "DEPO_DATA", "bj_user", "Pass1word", true)
for _, want := range []string{"sp_add_job @job_name = N'bj2depo_DEPO_DATA'", "WHERE j.name = N'bj2depo_DEPO_DATA' AND s.database_name <> @db",
"s.command LIKE N'%FTV_M2M_JOB%' AND j.name <> N'bj2depo_DEPO_DATA'", "уже запускает задание %s"} {
if !strings.Contains(named, want) {
t.Fatalf("задание по базе: в скрипте нет %q", want)
}
}
if strings.Index(named, "s.database_name <> @db") > strings.Index(named, "-- 1. Логин bj") {
t.Fatal("проверка задания должна стоять до создания логина")
}
if depoJobName(FancyMSSQLSettings{}) != "bj2depo" || depoJobNameFor("BJ2_DEPO_DATA") != "bj2depo_BJ2_DEPO_DATA" {
t.Fatal("имя задания: прежние установки — bj2depo, новые — bj2depo_<база>")
}
bj := depoSetupScript(f, "DEPO_X", "bj_user", "Pass1word", false)
if strings.Contains(bj, "sp_add_job") || !strings.Contains(bj, "GRANT EXECUTE ON dbo.FTV_M2M_JOB") || !strings.Contains(bj, "N'DEPO_X'") {
t.Fatal("обработка силами bj: без задания, с правом на процедуру и указанной базой")
@@ -514,6 +529,19 @@ func TestDepoScriptView(t *testing.T) {
if f := rc.Snapshot().Fancy; f.User != "bj_user" || f.Password != "Working1x" || f.DepoNewUser != "bj_user" || f.DepoNewPass != "Secret123x" || f.Server != "10.0.0.5" || f.DepoTablesMode != "script" {
t.Fatalf("файл: рабочие логин/пароль должны остаться, новые — черновиком: %q/%q, черновик %q", f.User, f.Password, f.DepoNewUser)
}
if f := rc.Snapshot().Fancy; f.DepoJobName != "bj2depo_DEPO_X" {
t.Fatalf("имя задания по умолчанию — по базе: %q", f.DepoJobName)
}
form.Set("view", "1")
form.Set("depo_job_name", "bj2depo test;")
if w := post(form); w.Code != http.StatusBadRequest || !strings.Contains(w.Body.String(), "имя задания") {
t.Fatalf("недопустимое имя задания: %d %s", w.Code, w.Body.String())
}
form.Set("depo_job_name", "bj2depo")
if w := post(form); w.Code != http.StatusOK || !strings.Contains(w.Body.String(), "sp_add_job @job_name = N'bj2depo'") {
t.Fatalf("имя задания с экрана: %d", w.Code)
}
form.Del("view")
form.Set("view", "1")
form.Set("bj_password", "short")
if w := post(form); w.Code != http.StatusBadRequest || !strings.Contains(w.Body.String(), "8 знаков") {