• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mindersec / minder / 25076733413

28 Apr 2026 08:44PM UTC coverage: 60.47% (+0.5%) from 60.0%
25076733413

Pull #6278

github

web-flow
Merge 7277590bc into 45b9c0d1a
Pull Request #6278: feat: make executor event handling timeout configurable

27 of 29 new or added lines in 2 files covered. (93.1%)

427 existing lines in 13 files now uncovered.

20410 of 33752 relevant lines covered (60.47%)

37.4 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.05
/internal/util/cli/testing.go
1
// SPDX-FileCopyrightText: Copyright 2024 The Minder Authors
2
// SPDX-License-Identifier: Apache-2.0
3

4
package cli
5

6
import (
7
        "bytes"
8
        "context"
9
        "encoding/json"
10
        "flag"
11
        "os"
12
        "path/filepath"
13
        "testing"
14

15
        "github.com/spf13/cobra"
16
        "github.com/spf13/pflag"
17
        "github.com/spf13/viper"
18
        "github.com/stretchr/testify/assert"
19
        "github.com/stretchr/testify/require"
20
        "go.uber.org/mock/gomock"
21
        "google.golang.org/protobuf/encoding/protojson"
22
        "google.golang.org/protobuf/proto"
23
)
24

25
var update = flag.Bool("update", false, "update golden files")
26

27
// ResetEntireTree wipes flags and contexts so tests don't "bleed" into each other
28
func ResetEntireTree(c *cobra.Command) {
873✔
29
        //nolint:staticcheck // SA1012: Cobra requires nil to clear the context so it can resume inheriting from the root
873✔
30
        c.SetContext(nil)
873✔
31
        c.Flags().VisitAll(func(f *pflag.Flag) {
4,392✔
32
                if slice, ok := f.Value.(pflag.SliceValue); ok {
3,672✔
33
                        _ = slice.Replace([]string{})
153✔
34
                } else {
3,519✔
35
                        _ = f.Value.Set(f.DefValue)
3,366✔
36
                }
3,366✔
37
                f.Changed = false
3,519✔
38
        })
39
        for _, child := range c.Commands() {
1,703✔
40
                ResetEntireTree(child)
830✔
41
        }
830✔
42
}
43

44
// CmdTestCase is the shared struct for all rule type CLI tests
45
type CmdTestCase struct {
46
        Name           string
47
        Args           []string
48
        MockSetup      func(t *testing.T, ctrl *gomock.Controller) context.Context
49
        GoldenFileName string
50
        ExpectedError  string
51
}
52

53
// RunCmdTests iterates over a slice of test cases and executes them
54
func RunCmdTests(
55
        t *testing.T,
56
        tests []CmdTestCase,
57
        cmd *cobra.Command,
58
) {
12✔
59
        t.Helper()
12✔
60
        const zeroUUID = "00000000-0000-0000-0000-000000000000"
12✔
61

12✔
62
        cwd, _ := os.Getwd()
12✔
63
        dummyConfig := filepath.Join(cwd, "config.yaml")
12✔
64
        if _, err := os.Stat(dummyConfig); os.IsNotExist(err) {
24✔
65
                _ = os.WriteFile(dummyConfig, []byte(""), 0600)
12✔
66
                defer os.Remove(dummyConfig)
12✔
67
        }
12✔
68

69
        for _, tc := range tests {
55✔
70
                t.Run(tc.Name, func(t *testing.T) {
86✔
71
                        viper.Reset()
43✔
72

43✔
73
                        rootCmd := cmd.Root()
43✔
74
                        ResetEntireTree(rootCmd)
43✔
75

43✔
76
                        ctrl := gomock.NewController(t)
43✔
77
                        defer ctrl.Finish()
43✔
78

43✔
79
                        ctx := context.Background()
43✔
80
                        if tc.MockSetup != nil {
69✔
81
                                ctx = tc.MockSetup(t, ctrl)
26✔
82
                        }
26✔
83

84
                        buf := new(bytes.Buffer)
43✔
85
                        rootCmd.SetOut(buf)
43✔
86
                        rootCmd.SetErr(buf)
43✔
87
                        rootCmd.SetContext(ctx)
43✔
88

43✔
89
                        rootCmd.SetArgs(tc.Args)
43✔
90

43✔
91
                        _ = viper.BindPFlags(cmd.Flags())
43✔
92
                        viper.Set("project", zeroUUID)
43✔
93

43✔
94
                        _, err := cmd.ExecuteContextC(ctx)
43✔
95

43✔
96
                        if tc.ExpectedError != "" {
62✔
97
                                require.Error(t, err)
19✔
98
                                assert.Contains(t, err.Error(), tc.ExpectedError)
19✔
99
                                return
19✔
100
                        }
19✔
101

102
                        require.NoError(t, err, "command execution should not fail")
24✔
103
                        checkGoldenFile(t, tc.GoldenFileName, buf.String())
24✔
104
                })
105
        }
106
}
107

108
func checkGoldenFile(t *testing.T, filename string, actual string) {
24✔
109
        t.Helper()
24✔
110
        goldenPath := filepath.Join("testdata", filename+".golden")
24✔
111

24✔
112
        if *update {
24✔
UNCOV
113
                err := os.MkdirAll("testdata", 0750)
×
UNCOV
114
                require.NoError(t, err)
×
UNCOV
115

×
UNCOV
116
                err = os.WriteFile(goldenPath, []byte(actual), 0600)
×
UNCOV
117
                require.NoError(t, err)
×
UNCOV
118
                t.Logf("Updated golden file: %s", goldenPath)
×
UNCOV
119
        }
×
120

121
        // #nosec G304
122
        expected, err := os.ReadFile(goldenPath)
24✔
123
        require.NoError(t, err, "could not read golden file. Run 'go test ./... -update' to generate it")
24✔
124

24✔
125
        if json.Valid(expected) && json.Valid([]byte(actual)) {
26✔
126
                // if it's valid json compare the objects (ignores spaces/newlines)
2✔
127
                require.JSONEq(t, string(expected), actual, "JSON Output does not match golden file")
2✔
128
        } else {
24✔
129
                // if it's a table, txt, or yaml fallback to exact string matching
22✔
130
                require.Equal(t, string(expected), actual, "Output does not match golden file")
22✔
131
        }
22✔
132
}
133

134
// LoadFixture reads a JSON file from the "fixture" directory and unmarshals
135
func LoadFixture(t *testing.T, filename string, target proto.Message) {
21✔
136
        t.Helper()
21✔
137

21✔
138
        // #nosec G304
21✔
139
        data, err := os.ReadFile(filepath.Join("fixture", filename))
21✔
140
        require.NoError(t, err, "failed to read fixture file. Check if 'fixture/%s' exists", filename)
21✔
141

21✔
142
        err = protojson.Unmarshal(data, target)
21✔
143
        require.NoError(t, err, "failed to unmarshal fixture into protobuf")
21✔
144
}
21✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc