app: composition root (A1-A4), Run(ctx), handleIncoming (вариант A), фикс config.Load(""), GetActiveTaskByChatID, main.go обновлён
All checks were successful
build-test / build (push) Successful in 35s

This commit is contained in:
Hermes
2026-08-15 09:51:03 +05:00
parent 4641090398
commit c72b41b2c5
7 changed files with 392 additions and 47 deletions

View File

@@ -1,15 +1,117 @@
package app
import "testing"
import (
"context"
"os"
"path/filepath"
"strings"
"testing"
)
// Контракт: process_turn (после внедрения) должен возвращать 3 значения.
// Здесь — placeholder-проверка, что composition root собирается без сбоев.
// TestNew проверяет, что composition root собирается без ошибок.
// Использует :memory: (? или file-based с t.TempDir).
func TestNew(t *testing.T) {
tmp := t.TempDir()
dbPath := filepath.Join(tmp, "test.db")
// Настраиваем минимальные env для обязательных полей
t.Setenv("TG_TOKEN", "test:token")
t.Setenv("TG_CHAT_ID", "12345")
t.Setenv("GITEA_URL", "http://gitea.test")
t.Setenv("GITEA_TOKEN", "test-token")
t.Setenv("RATATOSKR_DB", dbPath)
// Загружаем без config-файла (дефолты + env)
a, err := New("")
if err != nil {
t.Fatalf("New() err = %v", err)
}
if a.Config.IssueRepo == "" {
t.Fatal("IssueRepo пуст — каркас не инициализирован")
if a.Store == nil {
t.Fatal("Store не создан")
}
if a.Router == nil {
t.Fatal("Router не создан")
}
if a.CoreCtx == nil {
t.Fatal("Core не создан")
}
if a.Worker == nil {
t.Fatal("Worker не создан")
}
if a.tg == nil {
t.Fatal("Telegram-канал не создан")
}
t.Logf("app OK: db=%s", a.Config.Paths.DB)
}
// TestNew_MissingToken проверяет ошибку при пустом токене.
func TestNew_MissingToken(t *testing.T) {
tmp := t.TempDir()
dbPath := filepath.Join(tmp, "test.db")
t.Setenv("TG_TOKEN", "")
t.Setenv("TG_CHAT_ID", "12345")
t.Setenv("GITEA_URL", "http://gitea.test")
t.Setenv("GITEA_TOKEN", "test-token")
t.Setenv("RATATOSKR_DB", dbPath)
_, err := New("")
if err == nil {
t.Fatal("expected error for missing token")
}
t.Logf("got expected error: %v", err)
}
// TestNew_BadDB проверяет ошибку при пути к БД, который нельзя создать.
func TestNew_BadDB(t *testing.T) {
tmp := t.TempDir()
dbPath := filepath.Join(tmp, "nonexistent", "test.db") // родителя нет
t.Setenv("TG_TOKEN", "test:token")
t.Setenv("TG_CHAT_ID", "12345")
t.Setenv("GITEA_URL", "http://gitea.test")
t.Setenv("GITEA_TOKEN", "test-token")
t.Setenv("RATATOSKR_DB", dbPath)
_, err := New("")
if err == nil {
t.Fatal("expected error for invalid db path")
}
if !strings.Contains(err.Error(), "db open error") {
t.Errorf("expected 'db open error' in message, got %v", err)
}
}
// TestNew_CtxCancel проверяет, что Run завершается на отмене контекста.
func TestNew_RunCtxCancel(t *testing.T) {
tmp := t.TempDir()
dbPath := filepath.Join(tmp, "test-runcancel.db")
t.Setenv("TG_TOKEN", "test:token")
t.Setenv("TG_CHAT_ID", "12345")
t.Setenv("GITEA_URL", "http://gitea.test")
t.Setenv("GITEA_TOKEN", "test-token")
t.Setenv("RATATOSKR_DB", dbPath)
a, err := New("")
if err != nil {
t.Fatalf("New() err = %v", err)
}
ctx, cancel := context.WithCancel(context.Background())
cancel() // сразу отменяем
err = a.Run(ctx)
if err != nil {
t.Fatalf("Run() expected nil, got %v", err)
}
t.Log("Run OK on cancelled context")
}
// TestMain — дёргает fatalf, нормально что os.Exit не тестируется.
// Просто тест, что main.go компилируется.
func TestMain(t *testing.T) {
// main() не вызываем — он бы os.Exit
_, err := os.Stat("../../cmd/ratatoskr/main.go")
if err != nil {
t.Fatalf("main.go not found: %v", err)
}
t.Log("main.go exists")
}