mirror of
https://github.com/langgenius/dify.git
synced 2026-07-20 09:38:32 +08:00
183 lines
4.5 KiB
Go
183 lines
4.5 KiB
Go
package runner_exit
|
|
|
|
import (
|
|
"database/sql"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
func setupTestDB(t *testing.T, dir string) string {
|
|
t.Helper()
|
|
dbPath := filepath.Join(dir, "shellctl.db")
|
|
db, err := sql.Open("sqlite", "file:"+dbPath)
|
|
if err != nil {
|
|
t.Fatalf("open sqlite: %v", err)
|
|
}
|
|
defer func() { _ = db.Close() }()
|
|
|
|
_, err = db.Exec(`
|
|
CREATE TABLE jobs (
|
|
job_id TEXT PRIMARY KEY,
|
|
script_path TEXT NOT NULL,
|
|
output_path TEXT NOT NULL,
|
|
cwd TEXT NOT NULL,
|
|
terminal_cols INTEGER NOT NULL DEFAULT 200,
|
|
terminal_rows INTEGER NOT NULL DEFAULT 50,
|
|
status TEXT NOT NULL DEFAULT 'created',
|
|
session_name TEXT NOT NULL,
|
|
pane_target TEXT NOT NULL,
|
|
exit_code INTEGER,
|
|
reason TEXT,
|
|
message TEXT,
|
|
created_at TEXT NOT NULL,
|
|
started_at TEXT,
|
|
ended_at TEXT,
|
|
updated_at TEXT NOT NULL
|
|
)
|
|
`)
|
|
if err != nil {
|
|
t.Fatalf("create table: %v", err)
|
|
}
|
|
|
|
_, err = db.Exec(`INSERT INTO jobs (job_id, script_path, output_path, cwd, status, session_name, pane_target, created_at, updated_at)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
"test-job", "s", "o", "/tmp", "running", "sess", "pane", "2025-01-01T00:00:00Z", "2025-01-01T00:00:00Z")
|
|
if err != nil {
|
|
t.Fatalf("insert job: %v", err)
|
|
}
|
|
|
|
return dbPath
|
|
}
|
|
|
|
func TestRecordRunnerExitRunning(t *testing.T) {
|
|
dir := t.TempDir()
|
|
stateDir := dir
|
|
setupTestDB(t, dir)
|
|
|
|
err := RecordRunnerExit(stateDir, "test-job", 0, "2025-01-15T12:00:00Z", 5000)
|
|
if err != nil {
|
|
t.Fatalf("RecordRunnerExit: %v", err)
|
|
}
|
|
|
|
// Verify the row was updated
|
|
db, err := sql.Open("sqlite", "file:"+filepath.Join(dir, "shellctl.db"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() { _ = db.Close() }()
|
|
|
|
var status string
|
|
var exitCode int
|
|
if err := db.QueryRow("SELECT status, exit_code FROM jobs WHERE job_id = ?", "test-job").Scan(&status, &exitCode); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if status != "exited" {
|
|
t.Errorf("expected status=exited, got %s", status)
|
|
}
|
|
if exitCode != 0 {
|
|
t.Errorf("expected exit_code=0, got %d", exitCode)
|
|
}
|
|
}
|
|
|
|
func TestRecordRunnerExitNonZeroCode(t *testing.T) {
|
|
dir := t.TempDir()
|
|
setupTestDB(t, dir)
|
|
|
|
err := RecordRunnerExit(dir, "test-job", 42, "2025-01-15T12:00:00Z", 5000)
|
|
if err != nil {
|
|
t.Fatalf("RecordRunnerExit: %v", err)
|
|
}
|
|
|
|
db, err := sql.Open("sqlite", "file:"+filepath.Join(dir, "shellctl.db"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() { _ = db.Close() }()
|
|
|
|
var exitCode int
|
|
if err := db.QueryRow("SELECT exit_code FROM jobs WHERE job_id = ?", "test-job").Scan(&exitCode); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if exitCode != 42 {
|
|
t.Errorf("expected exit_code=42, got %d", exitCode)
|
|
}
|
|
}
|
|
|
|
func TestRecordRunnerExitJobNotFound(t *testing.T) {
|
|
dir := t.TempDir()
|
|
setupTestDB(t, dir)
|
|
|
|
err := RecordRunnerExit(dir, "nonexistent-job", 0, "2025-01-15T12:00:00Z", 5000)
|
|
if err == nil {
|
|
t.Error("expected error for nonexistent job")
|
|
}
|
|
}
|
|
|
|
func TestRecordRunnerExitDBNotFound(t *testing.T) {
|
|
dir := t.TempDir()
|
|
|
|
err := RecordRunnerExit(dir, "test-job", 0, "2025-01-15T12:00:00Z", 5000)
|
|
if err == nil {
|
|
t.Error("expected error when database doesn't exist")
|
|
}
|
|
}
|
|
|
|
func TestRecordRunnerExitTerminalIdempotent(t *testing.T) {
|
|
dir := t.TempDir()
|
|
dbPath := setupTestDB(t, dir)
|
|
|
|
// Manually set job to terminal state
|
|
db, err := sql.Open("sqlite", "file:"+dbPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := db.Exec(`UPDATE jobs SET status='terminated', exit_code=137, ended_at='2025-01-01T00:01:00Z' WHERE job_id='test-job'`); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_ = db.Close()
|
|
|
|
// Should not overwrite
|
|
err = RecordRunnerExit(dir, "test-job", 0, "2025-01-15T12:00:00Z", 5000)
|
|
if err != nil {
|
|
t.Fatalf("RecordRunnerExit on terminal: %v", err)
|
|
}
|
|
|
|
db, err = sql.Open("sqlite", "file:"+dbPath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer func() { _ = db.Close() }()
|
|
|
|
var status string
|
|
var exitCode int
|
|
if err := db.QueryRow("SELECT status, exit_code FROM jobs WHERE job_id = ?", "test-job").Scan(&status, &exitCode); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
if status != "terminated" {
|
|
t.Errorf("expected status=terminated (preserved), got %s", status)
|
|
}
|
|
if exitCode != 137 {
|
|
t.Errorf("expected exit_code=137 (preserved), got %d", exitCode)
|
|
}
|
|
}
|
|
|
|
func TestIsTerminal(t *testing.T) {
|
|
terminal := []string{"exited", "terminated", "failed", "lost"}
|
|
for _, s := range terminal {
|
|
if !isTerminal(s) {
|
|
t.Errorf("%s should be terminal", s)
|
|
}
|
|
}
|
|
nonTerminal := []string{"created", "starting", "running"}
|
|
for _, s := range nonTerminal {
|
|
if isTerminal(s) {
|
|
t.Errorf("%s should not be terminal", s)
|
|
}
|
|
}
|
|
}
|