Skip to content

Commit 14f842d

Browse files
authored
feat: add test utilities for helm
1 parent 8a877ec commit 14f842d

File tree

5 files changed

+1224
-0
lines changed

5 files changed

+1224
-0
lines changed

test/colors.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package test
2+
3+
// ANSI color codes for terminal output
4+
const (
5+
colorReset = "\033[0m"
6+
colorGray = "\033[90m"
7+
colorRed = "\033[91m"
8+
colorYellow = "\033[93m"
9+
colorBlue = "\033[94m"
10+
colorBold = "\033[1m"
11+
)

test/command.go

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package test
2+
3+
import (
4+
"bufio"
5+
"bytes"
6+
"fmt"
7+
"io"
8+
"os/exec"
9+
"strings"
10+
"sync"
11+
)
12+
13+
// CommandResult holds the result of a command execution
14+
type CommandResult struct {
15+
Stdout string
16+
Stderr string
17+
ExitCode int
18+
Err error
19+
}
20+
21+
// String returns a formatted string of the command result
22+
func (r CommandResult) String() string {
23+
return fmt.Sprintf("ExitCode: %d\nStdout:\n%s\nStderr:\n%s\nError: %v",
24+
r.ExitCode, r.Stdout, r.Stderr, r.Err)
25+
}
26+
27+
// CommandRunner provides command execution with optional colored output
28+
type CommandRunner struct {
29+
ColorOutput bool
30+
}
31+
32+
// NewCommandRunner creates a new CommandRunner
33+
func NewCommandRunner(colorOutput bool) *CommandRunner {
34+
return &CommandRunner{ColorOutput: colorOutput}
35+
}
36+
37+
// RunCommand executes a command and returns the result
38+
func (c *CommandRunner) RunCommand(name string, args ...string) CommandResult {
39+
if c.ColorOutput {
40+
fmt.Printf("%s%s>>> Executing: %s %s%s\n", colorBlue, colorBold, name, strings.Join(args, " "), colorReset)
41+
}
42+
43+
cmd := exec.Command(name, args...)
44+
45+
// Create pipes for stdout and stderr
46+
stdoutPipe, err := cmd.StdoutPipe()
47+
if err != nil {
48+
return CommandResult{
49+
Err: fmt.Errorf("failed to create stdout pipe: %w", err),
50+
ExitCode: -1,
51+
}
52+
}
53+
54+
stderrPipe, err := cmd.StderrPipe()
55+
if err != nil {
56+
return CommandResult{
57+
Err: fmt.Errorf("failed to create stderr pipe: %w", err),
58+
ExitCode: -1,
59+
}
60+
}
61+
62+
// Buffers to capture output
63+
var stdout, stderr bytes.Buffer
64+
65+
// Start the command
66+
if err := cmd.Start(); err != nil {
67+
return CommandResult{
68+
Err: fmt.Errorf("failed to start command: %w", err),
69+
ExitCode: -1,
70+
}
71+
}
72+
73+
// Stream output in real-time with colors
74+
var wg sync.WaitGroup
75+
wg.Add(2)
76+
77+
go c.streamOutput(stdoutPipe, "stdout", colorGray, &stdout, &wg)
78+
go c.streamOutput(stderrPipe, "stderr", colorRed, &stderr, &wg)
79+
80+
// Wait for output streaming to complete
81+
wg.Wait()
82+
83+
// Wait for command to complete
84+
err = cmd.Wait()
85+
exitCode := 0
86+
if exitErr, ok := err.(*exec.ExitError); ok {
87+
exitCode = exitErr.ExitCode()
88+
}
89+
90+
result := CommandResult{
91+
Stdout: stdout.String(),
92+
Stderr: stderr.String(),
93+
ExitCode: exitCode,
94+
Err: err,
95+
}
96+
97+
// Print exit status
98+
if c.ColorOutput {
99+
if result.Err != nil {
100+
fmt.Printf("%s%s<<< Command failed with exit code %d%s\n", colorRed, colorBold, result.ExitCode, colorReset)
101+
} else {
102+
fmt.Printf("%s<<< Command completed successfully%s\n", colorGray, colorReset)
103+
}
104+
fmt.Println() // Add blank line for readability
105+
}
106+
107+
return result
108+
}
109+
110+
// RunCommandQuiet executes a command without output streaming
111+
func (c *CommandRunner) RunCommandQuiet(name string, args ...string) CommandResult {
112+
cmd := exec.Command(name, args...)
113+
var stdout, stderr bytes.Buffer
114+
cmd.Stdout = &stdout
115+
cmd.Stderr = &stderr
116+
117+
err := cmd.Run()
118+
exitCode := 0
119+
if exitErr, ok := err.(*exec.ExitError); ok {
120+
exitCode = exitErr.ExitCode()
121+
}
122+
123+
return CommandResult{
124+
Stdout: stdout.String(),
125+
Stderr: stderr.String(),
126+
ExitCode: exitCode,
127+
Err: err,
128+
}
129+
}
130+
131+
func (c *CommandRunner) streamOutput(reader io.Reader, prefix string, color string, buffer *bytes.Buffer, wg *sync.WaitGroup) {
132+
defer wg.Done()
133+
scanner := bufio.NewScanner(reader)
134+
for scanner.Scan() {
135+
line := scanner.Text()
136+
buffer.WriteString(line + "\n")
137+
if c.ColorOutput {
138+
fmt.Printf("%s%s%s: %s%s\n", color, prefix, colorReset, color, line+colorReset)
139+
}
140+
}
141+
}
142+
143+
// Printf prints a formatted colored message
144+
func (c *CommandRunner) Printf(color, style, format string, args ...interface{}) {
145+
if c.ColorOutput {
146+
fmt.Printf("%s%s%s%s\n", color, style, fmt.Sprintf(format, args...), colorReset)
147+
} else {
148+
fmt.Printf(format+"\n", args...)
149+
}
150+
}

0 commit comments

Comments
 (0)