mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-14 20:48:17 +08:00
156 lines
4.5 KiB
Go
156 lines
4.5 KiB
Go
package integration_test
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
var (
|
|
cliBinary string
|
|
coreRoot string
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
var err error
|
|
coreRoot, err = filepath.Abs("..")
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "resolve core root: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
tempDir, err := os.MkdirTemp("", "uamask-cli-test-")
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "create CLI test directory: %v\n", err)
|
|
os.Exit(1)
|
|
}
|
|
cliBinary = filepath.Join(tempDir, "UAmask")
|
|
build := exec.Command("go", "build", "-o", cliBinary, "./cmd/UAmask")
|
|
build.Dir = coreRoot
|
|
if output, err := build.CombinedOutput(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "build UAmask CLI: %v\n%s", err, output)
|
|
_ = os.RemoveAll(tempDir)
|
|
os.Exit(1)
|
|
}
|
|
|
|
code := m.Run()
|
|
if err := os.RemoveAll(tempDir); err != nil && code == 0 {
|
|
fmt.Fprintf(os.Stderr, "remove CLI test directory: %v\n", err)
|
|
code = 1
|
|
}
|
|
os.Exit(code)
|
|
}
|
|
|
|
func TestCLIContracts(t *testing.T) {
|
|
t.Run("PROC-VERSION-001/version output", func(t *testing.T) {
|
|
result := runCLI(t, "-v")
|
|
if result.exitCode != 0 {
|
|
t.Fatalf("exit code = %d, stderr=%q", result.exitCode, result.stderr)
|
|
}
|
|
if !strings.HasPrefix(result.stdout, "UA-Mask version: ") || !strings.HasSuffix(result.stdout, "\n") {
|
|
t.Fatalf("unexpected version output %q", result.stdout)
|
|
}
|
|
if result.stderr != "" {
|
|
t.Fatalf("unexpected stderr %q", result.stderr)
|
|
}
|
|
})
|
|
|
|
t.Run("PROC-CHECK-001/valid config", func(t *testing.T) {
|
|
path := configFixture(t, "valid", "schema-v1-full.json")
|
|
result := runCLI(t, "-check-config", "-config", path)
|
|
if result.exitCode != 0 || result.stdout != "configuration valid\n" || result.stderr != "" {
|
|
t.Fatalf("unexpected result: %+v", result)
|
|
}
|
|
})
|
|
|
|
t.Run("PROC-CHECK-002/invalid config includes path", func(t *testing.T) {
|
|
path := configFixture(t, "invalid", "cfg-null-001-null-scalar.json")
|
|
result := runCLI(t, "-check-config", "-config", path)
|
|
if result.exitCode == 0 {
|
|
t.Fatalf("expected failure, got %+v", result)
|
|
}
|
|
if !strings.Contains(result.stderr, path) || !strings.Contains(result.stderr, "null is not allowed at $.listen.port") {
|
|
t.Fatalf("stderr %q does not identify the file and field", result.stderr)
|
|
}
|
|
})
|
|
|
|
t.Run("PROC-DUMP-001/effective config reloads", func(t *testing.T) {
|
|
path := configFixture(t, "valid", "schema-v1-full.json")
|
|
dump := runCLI(t, "-dump-effective-config", "-config", path)
|
|
if dump.exitCode != 0 || dump.stderr != "" {
|
|
t.Fatalf("dump failed: %+v", dump)
|
|
}
|
|
|
|
var document map[string]any
|
|
if err := json.Unmarshal([]byte(dump.stdout), &document); err != nil {
|
|
t.Fatalf("dump is not JSON: %v\n%s", err, dump.stdout)
|
|
}
|
|
if document["schema_version"] != float64(1) {
|
|
t.Fatalf("schema_version = %v, want 1", document["schema_version"])
|
|
}
|
|
|
|
dumpedPath := filepath.Join(t.TempDir(), "effective.json")
|
|
if err := os.WriteFile(dumpedPath, []byte(dump.stdout), 0o600); err != nil {
|
|
t.Fatalf("write dumped config: %v", err)
|
|
}
|
|
check := runCLI(t, "-check-config", "-config", dumpedPath)
|
|
if check.exitCode != 0 || check.stdout != "configuration valid\n" {
|
|
t.Fatalf("dumped config did not reload: %+v", check)
|
|
}
|
|
})
|
|
|
|
t.Run("PROC-ARGS-001/unknown flag", func(t *testing.T) {
|
|
result := runCLI(t, "-not-a-real-flag")
|
|
if result.exitCode == 0 || !strings.Contains(result.stderr, "flag provided but not defined") {
|
|
t.Fatalf("unexpected result: %+v", result)
|
|
}
|
|
})
|
|
|
|
t.Run("PROC-ARGS-002/positional argument", func(t *testing.T) {
|
|
result := runCLI(t, "unexpected")
|
|
if result.exitCode == 0 || !strings.Contains(result.stderr, "unexpected positional arguments") {
|
|
t.Fatalf("unexpected result: %+v", result)
|
|
}
|
|
})
|
|
}
|
|
|
|
type cliResult struct {
|
|
exitCode int
|
|
stdout string
|
|
stderr string
|
|
}
|
|
|
|
func runCLI(t *testing.T, args ...string) cliResult {
|
|
t.Helper()
|
|
command := exec.Command(cliBinary, args...)
|
|
var stdout bytes.Buffer
|
|
var stderr bytes.Buffer
|
|
command.Stdout = &stdout
|
|
command.Stderr = &stderr
|
|
err := command.Run()
|
|
exitCode := 0
|
|
if err != nil {
|
|
var exitError *exec.ExitError
|
|
if !errors.As(err, &exitError) {
|
|
t.Fatalf("run CLI: %v", err)
|
|
}
|
|
exitCode = exitError.ExitCode()
|
|
}
|
|
return cliResult{exitCode: exitCode, stdout: stdout.String(), stderr: stderr.String()}
|
|
}
|
|
|
|
func configFixture(t *testing.T, category, name string) string {
|
|
t.Helper()
|
|
path := filepath.Join(coreRoot, "internal", "config", "testdata", category, name)
|
|
if _, err := os.Stat(path); err != nil {
|
|
t.Fatalf("stat fixture %q: %v", path, err)
|
|
}
|
|
return path
|
|
}
|