Files
wild-cloud/api/internal/apps/drift_test.go

315 lines
8.2 KiB
Go

package apps
import (
"os"
"path/filepath"
"testing"
"gopkg.in/yaml.v3"
)
func TestParseSourceDir(t *testing.T) {
tests := []struct {
name string
source string
want string
}{
{"file URI", "file:///opt/wild-cloud/apps/myapp", "/opt/wild-cloud/apps/myapp"},
{"empty string", "", ""},
{"no scheme", "/opt/wild-cloud/apps/myapp", ""},
{"unsupported scheme", "git://example.com/repo", ""},
{"http scheme", "http://example.com/app", ""},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := parseSourceDir(tt.source)
if got != tt.want {
t.Errorf("parseSourceDir(%q) = %q, want %q", tt.source, got, tt.want)
}
})
}
}
func TestFilesDiffer(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "drift-files-*")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
fileA := filepath.Join(tmpDir, "a.txt")
fileB := filepath.Join(tmpDir, "b.txt")
fileC := filepath.Join(tmpDir, "c.txt")
fileMissing := filepath.Join(tmpDir, "missing.txt")
os.WriteFile(fileA, []byte("hello"), 0644)
os.WriteFile(fileB, []byte("hello"), 0644)
os.WriteFile(fileC, []byte("world"), 0644)
t.Run("identical files", func(t *testing.T) {
if filesDiffer(fileA, fileB) {
t.Error("expected identical files to not differ")
}
})
t.Run("different files", func(t *testing.T) {
if !filesDiffer(fileA, fileC) {
t.Error("expected different files to differ")
}
})
t.Run("one missing", func(t *testing.T) {
if !filesDiffer(fileA, fileMissing) {
t.Error("expected missing file to differ")
}
})
t.Run("both missing", func(t *testing.T) {
if filesDiffer(fileMissing, filepath.Join(tmpDir, "also-missing.txt")) {
t.Error("expected both missing to not differ")
}
})
}
func TestDirsDiffer(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "drift-dirs-*")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
// Create two identical directories
dirA := filepath.Join(tmpDir, "a")
dirB := filepath.Join(tmpDir, "b")
os.MkdirAll(dirA, 0755)
os.MkdirAll(dirB, 0755)
os.WriteFile(filepath.Join(dirA, "file.txt"), []byte("same"), 0644)
os.WriteFile(filepath.Join(dirB, "file.txt"), []byte("same"), 0644)
t.Run("identical directories", func(t *testing.T) {
if dirsDiffer(dirA, dirB) {
t.Error("expected identical directories to not differ")
}
})
// Create a directory with different content
dirC := filepath.Join(tmpDir, "c")
os.MkdirAll(dirC, 0755)
os.WriteFile(filepath.Join(dirC, "file.txt"), []byte("different"), 0644)
t.Run("different content", func(t *testing.T) {
if !dirsDiffer(dirA, dirC) {
t.Error("expected directories with different content to differ")
}
})
// Directory with extra file
dirD := filepath.Join(tmpDir, "d")
os.MkdirAll(dirD, 0755)
os.WriteFile(filepath.Join(dirD, "file.txt"), []byte("same"), 0644)
os.WriteFile(filepath.Join(dirD, "extra.txt"), []byte("extra"), 0644)
t.Run("extra file in second", func(t *testing.T) {
if !dirsDiffer(dirA, dirD) {
t.Error("expected directories with different file counts to differ")
}
})
}
func TestCheckSourceDrift_NoDrift(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "drift-source-*")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
// Create source directory with manifest
sourceDir := filepath.Join(tmpDir, "source", "myapp")
os.MkdirAll(sourceDir, 0755)
sourceManifest := AppManifest{Version: "1.0.0"}
data, _ := yaml.Marshal(sourceManifest)
os.WriteFile(filepath.Join(sourceDir, "manifest.yaml"), data, 0644)
// Create package dir (it exists)
packageDir := filepath.Join(tmpDir, "package")
os.MkdirAll(packageDir, 0755)
// Installed manifest with same version
manifest := &AppManifest{
Version: "1.0.0",
Source: "file://" + sourceDir,
}
m := &Manager{}
result := m.checkSourceDrift(manifest, packageDir)
if result != nil {
t.Errorf("expected no drift, got %+v", result)
}
}
func TestCheckSourceDrift_VersionDrift(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "drift-source-*")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
// Create source directory with newer version
sourceDir := filepath.Join(tmpDir, "source", "myapp")
os.MkdirAll(sourceDir, 0755)
sourceManifest := AppManifest{Version: "2.0.0"}
data, _ := yaml.Marshal(sourceManifest)
os.WriteFile(filepath.Join(sourceDir, "manifest.yaml"), data, 0644)
// Create package dir
packageDir := filepath.Join(tmpDir, "package")
os.MkdirAll(packageDir, 0755)
// Installed manifest with older version
manifest := &AppManifest{
Version: "1.0.0",
Source: "file://" + sourceDir,
}
m := &Manager{}
result := m.checkSourceDrift(manifest, packageDir)
if result == nil {
t.Fatal("expected drift, got nil")
}
if !result.Drifted {
t.Error("expected Drifted to be true")
}
if result.CurrentVersion != "1.0.0" {
t.Errorf("expected CurrentVersion '1.0.0', got %q", result.CurrentVersion)
}
if result.AvailableVersion != "2.0.0" {
t.Errorf("expected AvailableVersion '2.0.0', got %q", result.AvailableVersion)
}
}
func TestCheckSourceDrift_NoSource(t *testing.T) {
manifest := &AppManifest{
Version: "1.0.0",
Source: "", // ejected app
}
m := &Manager{}
result := m.checkSourceDrift(manifest, "/nonexistent")
if result != nil {
t.Errorf("expected nil for ejected app, got %+v", result)
}
}
func TestCheckSourceDrift_PackageMissing(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "drift-source-*")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
// Source exists but .package/ does not
sourceDir := filepath.Join(tmpDir, "source", "myapp")
os.MkdirAll(sourceDir, 0755)
manifest := &AppManifest{
Version: "1.0.0",
Source: "file://" + sourceDir,
}
packageDir := filepath.Join(tmpDir, "nonexistent-package")
m := &Manager{}
result := m.checkSourceDrift(manifest, packageDir)
if result == nil {
t.Fatal("expected drift for missing package dir, got nil")
}
if !result.Drifted {
t.Error("expected Drifted to be true")
}
}
func TestCheckSourceDrift_SourceDirMissing(t *testing.T) {
// Source URI points to a directory that doesn't exist
manifest := &AppManifest{
Version: "1.0.0",
Source: "file:///nonexistent/path/myapp",
}
packageDir := "/tmp" // exists but irrelevant
m := &Manager{}
result := m.checkSourceDrift(manifest, packageDir)
if result != nil {
t.Errorf("expected nil when source dir is missing, got %+v", result)
}
}
func TestComputeDrift_EjectedApp(t *testing.T) {
// Ejected app: Source is empty, so source and compilation drift should be nil
manifest := &AppManifest{
Version: "1.0.0",
Source: "",
}
m := &Manager{}
result := m.computeDrift("test-instance", "myapp", "/tmp", "", "added", manifest)
// For an ejected app with status "added", nothing to check — should be nil
if result != nil {
t.Errorf("expected nil drift for ejected 'added' app, got %+v", result)
}
}
func TestComputeDrift_NotDeployed(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "drift-compute-*")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
// Source-managed app that is only "added" (not deployed)
sourceDir := filepath.Join(tmpDir, "source")
os.MkdirAll(sourceDir, 0755)
// Source manifest with newer version
sourceManifest := AppManifest{Version: "2.0.0"}
data, _ := yaml.Marshal(sourceManifest)
os.WriteFile(filepath.Join(sourceDir, "manifest.yaml"), data, 0644)
// App directory with .package
appDir := filepath.Join(tmpDir, "app")
packageDir := filepath.Join(appDir, ".package")
os.MkdirAll(packageDir, 0755)
manifest := &AppManifest{
Version: "1.0.0",
Source: "file://" + sourceDir,
}
m := &Manager{}
result := m.computeDrift("test-instance", "myapp", appDir, "", "added", manifest)
if result == nil {
t.Fatal("expected drift info, got nil")
}
// Should have source drift (version mismatch)
if result.Source == nil || !result.Source.Drifted {
t.Error("expected source drift for version mismatch")
}
// Should NOT have deploy drift (status is "added")
if result.Deploy != nil {
t.Error("expected no deploy drift for 'added' status")
}
}
func TestComputeDrift_NilManifest(t *testing.T) {
m := &Manager{}
result := m.computeDrift("test-instance", "myapp", "/tmp", "", "running", nil)
if result != nil {
t.Errorf("expected nil drift for nil manifest, got %+v", result)
}
}