Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions framework/cli/cmd/inproc_audit_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package cmd

import (
"os"
"path/filepath"
"strings"
"testing"

"github.com/izo/ulk/internal/installer"
)

// TestRunAuditReportWritesJSON exercises runAuditReport directly with a
// tmpdir as cwd so the .ulk-reports/ folder is created in isolation.
func TestRunAuditReportWritesJSON(t *testing.T) {
prev, _ := os.Getwd()
defer os.Chdir(prev) //nolint:errcheck
tmp := t.TempDir()
_ = os.Chdir(tmp)

state := &installer.State{
Version: "test",
Modules: map[string]bool{"vps": true, "statusline": false},
}
out := captureStdout(func() {
err := runAuditReport(state, "/fake/source", "/fake/claude", true)
if err != nil {
t.Fatalf("audit failed: %v", err)
}
})

// Output must mention the file path and counters.
if !strings.Contains(out, "[audit-only]") {
t.Errorf("expected audit-only marker, got: %s", out)
}
if !strings.Contains(out, "first run: true") {
t.Errorf("expected first run marker, got: %s", out)
}

// File should exist under .ulk-reports/audit-*.json.
entries, err := os.ReadDir(filepath.Join(tmp, ".ulk-reports"))
if err != nil {
t.Fatalf("audit dir not created: %v", err)
}
if len(entries) == 0 {
t.Error("expected at least one audit-*.json file")
}
for _, e := range entries {
if !strings.HasPrefix(e.Name(), "audit-") || !strings.HasSuffix(e.Name(), ".json") {
t.Errorf("unexpected file in .ulk-reports: %s", e.Name())
}
}
}

// TestRunAuditReportManagedAgentsBranch exercises the ma-audit prefix +
// collectManagedAgentsInfo call path when the managed-agents module is on.
func TestRunAuditReportManagedAgentsBranch(t *testing.T) {
prev, _ := os.Getwd()
defer os.Chdir(prev) //nolint:errcheck
tmp := t.TempDir()
_ = os.Chdir(tmp)

state := &installer.State{
Version: "test",
Modules: map[string]bool{"managed-agents": true},
}
out := captureStdout(func() {
_ = runAuditReport(state, "/fake/source", "/fake/claude", false)
})
if !strings.Contains(out, "ma agents") {
t.Errorf("expected ma agents counter, got: %s", out)
}

entries, _ := os.ReadDir(filepath.Join(tmp, ".ulk-reports"))
foundMA := false
for _, e := range entries {
if strings.HasPrefix(e.Name(), "ma-audit-") {
foundMA = true
break
}
}
if !foundMA {
t.Errorf("expected ma-audit-*.json prefix, got: %v", entries)
}
}

// TestCollectManagedAgentsInfoMissingDir falls into the "no agents" branch
// when the source dir doesn't contain framework/managed-agents/orchestrators.
func TestCollectManagedAgentsInfoMissingDir(t *testing.T) {
info := collectManagedAgentsInfo("/nonexistent")
if info == nil {
t.Skip("nil result allowed when source missing — no panic is the success criterion")
}
}
110 changes: 110 additions & 0 deletions framework/cli/cmd/inproc_install_deps_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package cmd

import (
"os"
"path/filepath"
"strings"
"testing"

"github.com/spf13/cobra"
)

func TestRunInstallDepsSourceMissing(t *testing.T) {
t.Setenv("ULK_SOURCE", "/definitely-nowhere-xyz")
c := &cobra.Command{Use: "install-deps"}
c.Flags().Bool("required", false, "")
c.Flags().Bool("recommended", false, "")
c.Flags().Bool("all", false, "")
c.Flags().Bool("yes", false, "")
c.Flags().String("source", "", "")
_ = c.Flags().Set("source", "/nonexistent/dir")

err := runInstallDeps(c, nil)
if err == nil {
t.Fatal("expected error for missing source dir")
}
if !strings.Contains(err.Error(), "cannot locate ulk source") {
t.Errorf("error must point to source dir issue, got: %v", err)
}
}

func TestRunInstallDepsRegistryMissing(t *testing.T) {
tmp := t.TempDir()
// Make it look like an ulk source dir (has framework/commands).
_ = os.MkdirAll(filepath.Join(tmp, "framework", "commands"), 0755)

c := &cobra.Command{Use: "install-deps"}
c.Flags().Bool("required", false, "")
c.Flags().Bool("recommended", false, "")
c.Flags().Bool("all", false, "")
c.Flags().Bool("yes", false, "")
c.Flags().String("source", "", "")
_ = c.Flags().Set("source", tmp)

err := runInstallDeps(c, nil)
if err == nil {
t.Fatal("expected error for missing cli-registry.json")
}
if !strings.Contains(err.Error(), "cli-registry.json") {
t.Errorf("error must mention cli-registry.json, got: %v", err)
}
}

func TestRunInstallDepsEmptyFilter(t *testing.T) {
tmp := t.TempDir()
_ = os.MkdirAll(filepath.Join(tmp, "framework", "commands"), 0755)
_ = os.MkdirAll(filepath.Join(tmp, "framework", "tools"), 0755)

// Registry with only optional tools — neither --required nor default
// selects them, so the priority filter returns empty.
regJSON := `{"version":"1","tools":[
{"name":"x","command":"x","priority":"optional",
"install":{"macos":"true","linux":"true"}}]}`
regPath := filepath.Join(tmp, "framework", "tools", "cli-registry.json")
_ = os.WriteFile(regPath, []byte(regJSON), 0644)

c := &cobra.Command{Use: "install-deps"}
c.Flags().Bool("required", false, "")
c.Flags().Bool("recommended", false, "")
c.Flags().Bool("all", false, "")
c.Flags().Bool("yes", false, "")
c.Flags().String("source", "", "")
_ = c.Flags().Set("source", tmp)
_ = c.Flags().Set("required", "true")

out := captureStdout(func() {
_ = runInstallDeps(c, nil)
})
if !strings.Contains(out, "No tools match") {
t.Errorf("expected 'No tools match' message, got: %s", out)
}
}

func TestRunInstallDepsAllPresent(t *testing.T) {
tmp := t.TempDir()
_ = os.MkdirAll(filepath.Join(tmp, "framework", "commands"), 0755)
_ = os.MkdirAll(filepath.Join(tmp, "framework", "tools"), 0755)

// Tool whose `command` definitely exists on every supported platform: sh.
regJSON := `{"version":"1","tools":[
{"name":"sh","command":"sh","priority":"required",
"install":{"macos":"echo present","linux":"echo present"}}]}`
regPath := filepath.Join(tmp, "framework", "tools", "cli-registry.json")
_ = os.WriteFile(regPath, []byte(regJSON), 0644)

c := &cobra.Command{Use: "install-deps"}
c.Flags().Bool("required", false, "")
c.Flags().Bool("recommended", false, "")
c.Flags().Bool("all", false, "")
c.Flags().Bool("yes", false, "")
c.Flags().String("source", "", "")
_ = c.Flags().Set("source", tmp)
_ = c.Flags().Set("required", "true")

out := captureStdout(func() {
_ = runInstallDeps(c, nil)
})
if !strings.Contains(out, "already installed") {
t.Errorf("expected 'already installed' message when all tools present, got: %s", out)
}
}
67 changes: 67 additions & 0 deletions framework/cli/cmd/inproc_install_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package cmd

import (
"os"
"path/filepath"
"strings"
"testing"
)

// TestRunInstallSourceMissing exercises the early "cannot locate source"
// branch of runInstall via the existing installCmd (which already has all
// flags registered, no need to re-mirror them).
func TestRunInstallSourceMissing(t *testing.T) {
t.Setenv("ULK_SOURCE", "/definitely-nowhere")
t.Setenv("HOME", t.TempDir())

// Force resolveSourceDir to fail by overriding --source AND moving cwd
// somewhere with no framework/commands.
prev, _ := os.Getwd()
defer os.Chdir(prev) //nolint:errcheck
_ = os.Chdir(t.TempDir())

_ = installCmd.Flags().Set("source", "/nonexistent/path")
defer func() { _ = installCmd.Flags().Set("source", "") }()

err := runInstall(installCmd, nil)
if err == nil {
t.Fatal("expected error when source dir cannot be located")
}
if !strings.Contains(err.Error(), "cannot locate ulk source") {
t.Errorf("error must mention source dir, got: %v", err)
}
}

// TestRunInstallDryRunInProcess covers ~50 lines of runInstall by exercising
// the parseFlags → resolveSourceDir → loadOrNewState → applyFlags →
// applyProfile → printModules path. We make the cwd look like an ulk repo
// source by creating framework/commands, and force --dry-run + --no-tui to
// avoid the wizard and any actual writes.
func TestRunInstallDryRunInProcess(t *testing.T) {
tmp := t.TempDir()
_ = os.MkdirAll(filepath.Join(tmp, "framework", "commands"), 0755)
t.Setenv("HOME", t.TempDir())
t.Setenv("ULK_SOURCE", tmp)
t.Setenv("ULK_HOME", filepath.Join(tmp, ".ulk-fake"))

// All install flags are pre-registered on installCmd via init().
_ = installCmd.Flags().Set("dry-run", "true")
_ = installCmd.Flags().Set("no-tui", "true")
defer func() {
_ = installCmd.Flags().Set("dry-run", "false")
_ = installCmd.Flags().Set("no-tui", "false")
}()

out := captureStdout(func() {
err := runInstall(installCmd, nil)
if err != nil {
t.Fatalf("dry-run install failed: %v", err)
}
})
if !strings.Contains(out, "[dry-run]") {
t.Errorf("expected dry-run banner, got: %s", out)
}
if !strings.Contains(out, "Modules:") {
t.Errorf("expected printModules output, got: %s", out)
}
}
Loading