Skip to content

Commit 844b491

Browse files
committed
fix: address PR review comments
- Fix temp file leak in prepareStdinValues on error paths - Use %q for quoted chart paths in error messages - Nil out manifest byte slices after parsing to reduce peak memory - Refactor tests to use captureStdout helper - Add tests for prepareStdinValues stdin handling Signed-off-by: yxxhero <aiopsclub@163.com>
1 parent ae67779 commit 844b491

2 files changed

Lines changed: 110 additions & 44 deletions

File tree

cmd/local.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,12 @@ func (l *local) run() error {
119119

120120
manifest1, err := l.renderChart(l.chart1)
121121
if err != nil {
122-
return fmt.Errorf("failed to render chart %s: %w", l.chart1, err)
122+
return fmt.Errorf("failed to render chart %q: %w", l.chart1, err)
123123
}
124124

125125
manifest2, err := l.renderChart(l.chart2)
126126
if err != nil {
127-
return fmt.Errorf("failed to render chart %s: %w", l.chart2, err)
127+
return fmt.Errorf("failed to render chart %q: %w", l.chart2, err)
128128
}
129129

130130
excludes := []string{manifest.Helm3TestHook, manifest.Helm2TestSuccessHook}
@@ -134,6 +134,8 @@ func (l *local) run() error {
134134

135135
specs1 := manifest.Parse(manifest1, l.namespace, l.normalizeManifests, excludes...)
136136
specs2 := manifest.Parse(manifest2, l.namespace, l.normalizeManifests, excludes...)
137+
manifest1 = nil
138+
manifest2 = nil
137139

138140
seenAnyChanges := diff.Manifests(specs1, specs2, &l.Options, os.Stdout)
139141

@@ -165,10 +167,12 @@ func (l *local) prepareStdinValues() (func(), error) {
165167

166168
if _, err := tmpfile.Write(data); err != nil {
167169
_ = tmpfile.Close()
170+
_ = os.Remove(tmpfile.Name())
168171
return nil, err
169172
}
170173

171174
if err := tmpfile.Close(); err != nil {
175+
_ = os.Remove(tmpfile.Name())
172176
return nil, err
173177
}
174178

cmd/local_test.go

Lines changed: 104 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package cmd
22

33
import (
4-
"bytes"
54
"errors"
65
"os"
76
"strings"
@@ -86,31 +85,20 @@ data:
8685
chart1 := t.TempDir()
8786
chart2 := t.TempDir()
8887

89-
oldStdout := os.Stdout
90-
r, w, err := os.Pipe()
91-
if err != nil {
92-
t.Fatalf("Failed to create pipe: %v", err)
93-
}
94-
os.Stdout = w
95-
96-
cmd := localCmd()
97-
cmd.SetArgs([]string{chart1, chart2})
88+
output, err := captureStdout(func() {
89+
cmd := localCmd()
90+
cmd.SetArgs([]string{chart1, chart2})
9891

99-
err = cmd.Execute()
100-
w.Close()
101-
os.Stdout = oldStdout
92+
if execErr := cmd.Execute(); execErr != nil {
93+
t.Errorf("Expected no error but got: %v", execErr)
94+
}
95+
})
10296

10397
if err != nil {
104-
t.Fatalf("Expected no error but got: %v", err)
105-
}
106-
107-
var buf bytes.Buffer
108-
if _, err := buf.ReadFrom(r); err != nil {
109-
t.Fatalf("Failed to read from pipe: %v", err)
98+
t.Fatalf("Failed to capture stdout: %v", err)
11099
}
111-
r.Close()
112-
if buf.String() != "" {
113-
t.Errorf("Expected no output when charts are identical, got: %q", buf.String())
100+
if output != "" {
101+
t.Errorf("Expected no output when charts are identical, got: %q", output)
114102
}
115103
}
116104

@@ -138,30 +126,18 @@ data:
138126
chart1 := t.TempDir()
139127
chart2 := t.TempDir()
140128

141-
oldStdout := os.Stdout
142-
r, w, err := os.Pipe()
143-
if err != nil {
144-
t.Fatalf("Failed to create pipe: %v", err)
145-
}
146-
os.Stdout = w
129+
output, err := captureStdout(func() {
130+
cmd := localCmd()
131+
cmd.SetArgs([]string{chart1, chart2})
147132

148-
cmd := localCmd()
149-
cmd.SetArgs([]string{chart1, chart2})
150-
151-
err = cmd.Execute()
152-
w.Close()
153-
os.Stdout = oldStdout
133+
if execErr := cmd.Execute(); execErr != nil {
134+
t.Errorf("Expected no error but got: %v", execErr)
135+
}
136+
})
154137

155138
if err != nil {
156-
t.Fatalf("Expected no error but got: %v", err)
157-
}
158-
159-
var buf bytes.Buffer
160-
if _, err := buf.ReadFrom(r); err != nil {
161-
t.Fatalf("Failed to read from pipe: %v", err)
139+
t.Fatalf("Failed to capture stdout: %v", err)
162140
}
163-
r.Close()
164-
output := buf.String()
165141

166142
if !strings.Contains(output, "value1") || !strings.Contains(output, "value2") {
167143
t.Errorf("Expected diff output containing value1 and value2, got: %q", output)
@@ -280,6 +256,92 @@ func TestLocalCmdHelmTemplateError(t *testing.T) {
280256
}
281257
}
282258

259+
func TestPrepareStdinValues(t *testing.T) {
260+
l := &local{
261+
valueFiles: valueFiles{"-", "-", "real-values.yaml"},
262+
}
263+
264+
stdinContent := `key: stdin-value
265+
`
266+
tmpStdin, err := os.CreateTemp("", "fake-stdin")
267+
if err != nil {
268+
t.Fatal(err)
269+
}
270+
defer os.Remove(tmpStdin.Name())
271+
if _, err := tmpStdin.WriteString(stdinContent); err != nil {
272+
t.Fatal(err)
273+
}
274+
if err := tmpStdin.Close(); err != nil {
275+
t.Fatal(err)
276+
}
277+
278+
oldStdin := os.Stdin
279+
f, err := os.Open(tmpStdin.Name())
280+
if err != nil {
281+
t.Fatal(err)
282+
}
283+
os.Stdin = f
284+
defer func() {
285+
os.Stdin = oldStdin
286+
f.Close()
287+
}()
288+
289+
cleanup, err := l.prepareStdinValues()
290+
if err != nil {
291+
t.Fatalf("Expected no error but got: %v", err)
292+
}
293+
if cleanup == nil {
294+
t.Fatal("Expected cleanup function but got nil")
295+
}
296+
297+
if l.valueFiles[0] == "-" {
298+
t.Error("Expected first valueFile to be replaced with temp file path")
299+
}
300+
if l.valueFiles[1] == "-" {
301+
t.Error("Expected second valueFile to be replaced with temp file path")
302+
}
303+
if l.valueFiles[0] != l.valueFiles[1] {
304+
t.Errorf("Expected both '-' entries to point to the same temp file, got %q and %q", l.valueFiles[0], l.valueFiles[1])
305+
}
306+
if _, err := os.Stat(l.valueFiles[0]); os.IsNotExist(err) {
307+
t.Errorf("Expected temp file %q to exist", l.valueFiles[0])
308+
}
309+
if l.valueFiles[2] != "real-values.yaml" {
310+
t.Errorf("Expected third valueFile to be unchanged, got %q", l.valueFiles[2])
311+
}
312+
313+
data, err := os.ReadFile(l.valueFiles[0])
314+
if err != nil {
315+
t.Fatalf("Failed to read temp file: %v", err)
316+
}
317+
if string(data) != stdinContent {
318+
t.Errorf("Expected temp file to contain stdin content %q, got %q", stdinContent, string(data))
319+
}
320+
321+
cleanup()
322+
323+
if _, err := os.Stat(l.valueFiles[0]); !os.IsNotExist(err) {
324+
t.Errorf("Expected temp file %q to be removed after cleanup", l.valueFiles[0])
325+
}
326+
}
327+
328+
func TestPrepareStdinValuesNoStdin(t *testing.T) {
329+
l := &local{
330+
valueFiles: valueFiles{"values1.yaml", "values2.yaml"},
331+
}
332+
333+
cleanup, err := l.prepareStdinValues()
334+
if err != nil {
335+
t.Fatalf("Expected no error but got: %v", err)
336+
}
337+
if cleanup != nil {
338+
t.Error("Expected nil cleanup function when no stdin values")
339+
}
340+
if l.valueFiles[0] != "values1.yaml" || l.valueFiles[1] != "values2.yaml" {
341+
t.Errorf("Expected valueFiles to be unchanged, got %v", l.valueFiles)
342+
}
343+
}
344+
283345
func setupFakeHelm(t *testing.T, mode, output, argsFile, countFile string) {
284346
t.Helper()
285347
t.Setenv("HELM_DIFF_FAKE_HELM", "1")

0 commit comments

Comments
 (0)