Files
sub2api-cn-relay-manager/internal/overlay/executor_extra_test.go
phamnazage-jpg 77b7f7f660
Some checks failed
CI / Build & Test (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / Docker Build (push) Has been cancelled
CI / Release (push) Has been cancelled
feat: harden runtime import and frontend verification workflows
2026-06-04 20:02:36 +08:00

263 lines
6.8 KiB
Go

package overlay
import (
"context"
"os"
"path/filepath"
"strings"
"testing"
"sub2api-cn-relay-manager/internal/pack"
)
func TestApplyEmptyPackDir(t *testing.T) {
_, err := Apply(context.Background(), ApplyRequest{
PackDir: "",
SourceDir: t.TempDir(),
Overlays: []pack.HostOverlay{{OverlayID: "test"}},
})
if err == nil || err.Error() != "pack dir is required" {
t.Errorf("Apply() error = %v, want 'pack dir is required'", err)
}
}
func TestApplyEmptySourceDir(t *testing.T) {
_, err := Apply(context.Background(), ApplyRequest{
PackDir: t.TempDir(),
SourceDir: "",
Overlays: []pack.HostOverlay{{OverlayID: "test"}},
})
if err == nil || err.Error() != "source dir is required" {
t.Errorf("Apply() error = %v, want 'source dir is required'", err)
}
}
func TestApplyEmptyOverlays(t *testing.T) {
_, err := Apply(context.Background(), ApplyRequest{
PackDir: t.TempDir(),
SourceDir: t.TempDir(),
Overlays: []pack.HostOverlay{},
})
if err == nil || err.Error() != "at least one host overlay is required" {
t.Errorf("Apply() error = %v, want 'at least one host overlay is required'", err)
}
}
func TestApplyOutputSameAsSource(t *testing.T) {
sourceDir := t.TempDir()
_, err := Apply(context.Background(), ApplyRequest{
PackDir: t.TempDir(),
SourceDir: sourceDir,
OutputDir: sourceDir,
Overlays: []pack.HostOverlay{{OverlayID: "test", PatchPath: "test.patch"}},
})
if err == nil || !strings.Contains(err.Error(), "must differ from source dir") {
t.Errorf("Apply() error = %v, want 'must differ from source dir'", err)
}
}
func TestApplyMissingSourceDir(t *testing.T) {
_, err := Apply(context.Background(), ApplyRequest{
PackDir: t.TempDir(),
SourceDir: "/nonexistent/path/that/does/not/exist",
Overlays: []pack.HostOverlay{{OverlayID: "test", PatchPath: "test.patch"}},
})
if err == nil {
t.Error("Apply() expected error for missing source dir")
}
}
func TestApplyStatOutputError(t *testing.T) {
// This tests the path where os.Stat returns an error other than IsNotExist
// Create a file as sourceDir to test non-directory source
filePath := filepath.Join(t.TempDir(), "notadir")
os.WriteFile(filePath, []byte("test"), 0644)
_, err := Apply(context.Background(), ApplyRequest{
PackDir: t.TempDir(),
SourceDir: filePath,
Overlays: []pack.HostOverlay{{OverlayID: "test", PatchPath: "test.patch"}},
})
if err == nil || !strings.Contains(err.Error(), "must be a directory") {
t.Errorf("Apply() error = %v, want 'must be a directory'", err)
}
}
func TestApplyCleanupOnFailure(t *testing.T) {
sourceDir := t.TempDir()
packDir := t.TempDir()
// Create a valid source structure
os.MkdirAll(filepath.Join(sourceDir, "backend"), 0755)
os.WriteFile(filepath.Join(sourceDir, "backend", "hello.txt"), []byte("hello\n"), 0644)
// Create an invalid patch that will fail
os.WriteFile(filepath.Join(packDir, "bad.patch"), []byte("invalid patch content"), 0644)
_, err := Apply(context.Background(), ApplyRequest{
PackDir: packDir,
SourceDir: sourceDir,
Overlays: []pack.HostOverlay{{OverlayID: "test", PatchPath: "bad.patch"}},
})
if err == nil {
t.Error("Apply() expected error for invalid patch")
}
// Output dir should be cleaned up
// We can't directly test this, but coverage will show the defer cleanupOutput path
}
func TestDefaultOutputDir(t *testing.T) {
overlays := []pack.HostOverlay{
{OverlayID: "overlay1"},
{OverlayID: "overlay2"},
{OverlayID: "test-overlay"},
}
result := defaultOutputDir("/tmp/source", overlays)
// Check that result contains source path and sanitized overlay IDs
if !strings.Contains(result, "source") {
t.Errorf("defaultOutputDir() = %v, should contain 'source'", result)
}
}
func TestDefaultOutputDirEmptyOverlayID(t *testing.T) {
overlays := []pack.HostOverlay{
{OverlayID: ""},
{OverlayID: "test"},
}
result := defaultOutputDir("/tmp/source", overlays)
// Should still work with empty overlay IDs
if result == "" {
t.Error("defaultOutputDir() returned empty string")
}
}
func TestSanitizePathToken(t *testing.T) {
tests := []struct {
input string
expected string
}{
{"normal", "normal"},
{"with/slash", "with-slash"},
{"with\\backslash", "with-backslash"},
{"with spaces", "with-spaces"},
{"with:colon", "with-colon"},
{"UPPER", "upper"},
{"MiXeD", "mixed"},
{"", ""},
}
for _, tt := range tests {
result := sanitizePathToken(tt.input)
if result != tt.expected {
t.Errorf("sanitizePathToken(%q) = %q, want %q", tt.input, result, tt.expected)
}
}
}
func TestIsPathWithin(t *testing.T) {
tests := []struct {
path string
parent string
expected bool
}{
{"/a/b/c", "/a/b", true},
{"/a/b/c/d", "/a/b", true},
{"/a/b", "/a/b", true}, // Same path - returns true based on actual implementation
{"/a/bc", "/a/b", false}, // Prefix but not subdirectory
{"/x/y/z", "/a/b", false},
}
for _, tt := range tests {
result := isPathWithin(tt.path, tt.parent)
if result != tt.expected {
t.Errorf("isPathWithin(%q, %q) = %v, want %v", tt.path, tt.parent, result, tt.expected)
}
}
}
func TestFilterOverlays(t *testing.T) {
tests := []struct {
name string
overlays []pack.HostOverlay
filter string
wantCount int
wantErr bool
}{
{
name: "single match",
overlays: []pack.HostOverlay{{OverlayID: "test"}},
filter: "test",
wantCount: 1,
wantErr: false,
},
{
name: "no match",
overlays: []pack.HostOverlay{{OverlayID: "foo"}},
filter: "bar",
wantCount: 0,
wantErr: true,
},
{
name: "multiple with one match",
overlays: []pack.HostOverlay{{OverlayID: "a"}, {OverlayID: "b"}},
filter: "a",
wantCount: 1,
wantErr: false,
},
{
name: "first match taken",
overlays: []pack.HostOverlay{{OverlayID: "a", PatchPath: "1"}, {OverlayID: "a", PatchPath: "2"}},
filter: "a",
wantCount: 2, // Returns all matching items, not just first
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := FilterOverlays(tt.overlays, tt.filter)
if (err != nil) != tt.wantErr {
t.Errorf("FilterOverlays() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && len(result) != tt.wantCount {
t.Errorf("FilterOverlays() = %v, want %d items", result, tt.wantCount)
}
})
}
}
func TestContainsHelper(t *testing.T) {
// Test the contains helper function from executor.go
tests := []struct {
slice []string
item string
expected bool
}{
{[]string{"a", "b", "c"}, "b", true},
{[]string{"a", "b", "c"}, "d", false},
{[]string{}, "a", false},
{[]string{"a"}, "a", true},
}
for _, tt := range tests {
found := false
for _, s := range tt.slice {
if s == tt.item {
found = true
break
}
}
if found != tt.expected {
t.Errorf("contains check for %q in %v = %v, want %v", tt.item, tt.slice, found, tt.expected)
}
}
}