Files
BackupX/server/internal/backup/mongodb_runner_test.go
Wu Qing f584a0802a feat(backup): 新增 MongoDB 备份与恢复支持 (#87)
通过 mongodump/mongorestore --archive 流式管线接入 MongoDB 数据源,与现有数据库运行器架构一致;注册到 Master 与 Agent,含任务校验、默认端口与前端表单/恢复确认。5 个单测覆盖参数构造、全库、空产物与缺工具分支。
2026-05-27 18:35:10 +08:00

103 lines
3.8 KiB
Go

package backup
import (
"context"
"errors"
"io"
"os"
"strings"
"testing"
)
func argIndex(args []string, target string) int {
for i, a := range args {
if a == target {
return i
}
}
return -1
}
func TestMongoDBRunnerRunUsesMongodump(t *testing.T) {
executor := &fakeCommandExecutor{runFunc: func(name string, args []string, options CommandOptions) error {
if options.Stdout != nil {
_, _ = io.WriteString(options.Stdout, "mongo archive bytes")
}
return nil
}}
runner := NewMongoDBRunner(executor)
result, err := runner.Run(context.Background(), TaskSpec{Name: "mongo", Type: "mongodb", Database: DatabaseSpec{Host: "127.0.0.1", Port: 27017, User: "admin", Password: "secret", Names: []string{"app"}}}, NopLogWriter{})
if err != nil {
t.Fatalf("Run returned error: %v", err)
}
if executor.lastName != "mongodump" {
t.Fatalf("expected mongodump, got %s", executor.lastName)
}
args := executor.lastArgs
if argIndex(args, "--archive") < 0 {
t.Fatalf("expected --archive flag, got %#v", args)
}
if i := argIndex(args, "--db"); i < 0 || i+1 >= len(args) || args[i+1] != "app" {
t.Fatalf("expected --db app, got %#v", args)
}
if i := argIndex(args, "--username"); i < 0 || args[i+1] != "admin" {
t.Fatalf("expected --username admin, got %#v", args)
}
if argIndex(args, "--authenticationDatabase") < 0 || argIndex(args, "--password") < 0 {
t.Fatalf("expected auth args, got %#v", args)
}
if _, err := os.Stat(result.ArtifactPath); err != nil {
t.Fatalf("artifact file missing: %v", err)
}
if result.StorageKey == "" || !strings.HasSuffix(result.FileName, ".archive") {
t.Fatalf("unexpected result metadata: %#v", result)
}
}
func TestMongoDBRunnerRunBackupsAllWhenNoDatabase(t *testing.T) {
executor := &fakeCommandExecutor{runFunc: func(name string, args []string, options CommandOptions) error {
_, _ = io.WriteString(options.Stdout, "all dbs")
return nil
}}
runner := NewMongoDBRunner(executor)
_, err := runner.Run(context.Background(), TaskSpec{Name: "mongo", Type: "mongodb", Database: DatabaseSpec{Host: "127.0.0.1", Port: 27017}}, NopLogWriter{})
if err != nil {
t.Fatalf("Run returned error: %v", err)
}
if argIndex(executor.lastArgs, "--db") >= 0 {
t.Fatalf("expected no --db when backing up all databases, got %#v", executor.lastArgs)
}
}
func TestMongoDBRunnerRunRejectsEmptyOutput(t *testing.T) {
executor := &fakeCommandExecutor{} // runFunc nil → writes nothing
runner := NewMongoDBRunner(executor)
_, err := runner.Run(context.Background(), TaskSpec{Name: "mongo", Type: "mongodb", Database: DatabaseSpec{Host: "127.0.0.1", Port: 27017, Names: []string{"app"}}}, NopLogWriter{})
if err == nil {
t.Fatal("expected error for empty mongodump output")
}
}
func TestMongoDBRunnerRestoreUsesMongorestore(t *testing.T) {
executor := &fakeCommandExecutor{}
runner := NewMongoDBRunner(executor)
artifact := filepathJoinTempFile(t, "dump.archive", "mongo archive bytes")
if err := runner.Restore(context.Background(), TaskSpec{Name: "mongo", Type: "mongodb", Database: DatabaseSpec{Host: "127.0.0.1", Port: 27017, User: "admin", Password: "secret"}}, artifact, NopLogWriter{}); err != nil {
t.Fatalf("Restore returned error: %v", err)
}
if executor.lastName != "mongorestore" {
t.Fatalf("expected mongorestore, got %s", executor.lastName)
}
if argIndex(executor.lastArgs, "--drop") < 0 || argIndex(executor.lastArgs, "--archive") < 0 {
t.Fatalf("expected --drop --archive, got %#v", executor.lastArgs)
}
}
func TestMongoDBRunnerRunReturnsLookupError(t *testing.T) {
runner := NewMongoDBRunner(&fakeCommandExecutor{lookupErr: errors.New("missing")})
_, err := runner.Run(context.Background(), TaskSpec{Name: "mongo", Type: "mongodb", Database: DatabaseSpec{Host: "127.0.0.1", Port: 27017, Names: []string{"app"}}}, NopLogWriter{})
if err == nil {
t.Fatal("expected error when mongodump is missing")
}
}