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

mindersec / minder / 24254057669

10 Apr 2026 04:52PM UTC coverage: 59.781% (+0.5%) from 59.314%
24254057669

Pull #6286

github

web-flow
Merge c89556145 into 8fb1b27b7
Pull Request #6286: Implement Isolated, Deterministic Test Suite for ruletype CLI Subcommands

72 of 79 new or added lines in 2 files covered. (91.14%)

19867 of 33233 relevant lines covered (59.78%)

36.33 hits per line

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

90.0
/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
        "flag"
10
        "os"
11
        "path/filepath"
12
        "testing"
13

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

23
        minderv1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1"
24
        mockv1 "github.com/mindersec/minder/pkg/api/protobuf/go/minder/v1/mock"
25
)
26

27
var update = flag.Bool("update", false, "update golden files")
28

29
// CmdTestCase is the shared struct for all rule type CLI tests
30
type CmdTestCase struct {
31
        Name           string
32
        Args           []string
33
        MockSetup      func(t *testing.T, client *mockv1.MockRuleTypeServiceClient)
34
        GoldenFileName string
35
        ExpectedError  string
36
}
37

38
// RunCmdTests iterates over a slice of test cases and executes them
39
func RunCmdTests(
40
        t *testing.T,
41
        tests []CmdTestCase,
42
        cmd *cobra.Command,
43
        execFunc func(ctx context.Context, c *cobra.Command) error,
44
) {
6✔
45

6✔
46
        t.Helper()
6✔
47
        const zeroUUID = "00000000-0000-0000-0000-000000000000"
6✔
48

6✔
49
        for _, tc := range tests {
24✔
50
                t.Run(tc.Name, func(t *testing.T) {
36✔
51
                        viper.Reset()
18✔
52
                        cmd.Flags().VisitAll(func(f *pflag.Flag) {
109✔
53
                                if slice, ok := f.Value.(pflag.SliceValue); ok {
96✔
54
                                        _ = slice.Replace([]string{})
5✔
55
                                } else {
91✔
56
                                        _ = f.Value.Set(f.DefValue)
86✔
57
                                }
86✔
58
                                f.Changed = false
91✔
59
                        })
60

61
                        ctrl := gomock.NewController(t)
18✔
62
                        defer ctrl.Finish()
18✔
63

18✔
64
                        mockClient := mockv1.NewMockRuleTypeServiceClient(ctrl)
18✔
65
                        if tc.MockSetup != nil {
36✔
66
                                tc.MockSetup(t, mockClient)
18✔
67
                        }
18✔
68

69
                        ctx := WithRPCClient[minderv1.RuleTypeServiceClient](context.Background(), mockClient)
18✔
70
                        cmd.SetContext(ctx)
18✔
71

18✔
72
                        buf := new(bytes.Buffer)
18✔
73
                        cmd.SetOut(buf)
18✔
74
                        cmd.SetErr(buf)
18✔
75

18✔
76
                        err := cmd.Flags().Parse(tc.Args)
18✔
77
                        require.NoError(t, err, "flag parsing should not fail")
18✔
78

18✔
79
                        _ = viper.BindPFlags(cmd.Flags())
18✔
80
                        viper.Set("project", zeroUUID)
18✔
81

18✔
82
                        err = execFunc(ctx, cmd)
18✔
83

18✔
84
                        if tc.ExpectedError != "" {
24✔
85
                                require.Error(t, err)
6✔
86
                                assert.Contains(t, err.Error(), tc.ExpectedError)
6✔
87
                                return
6✔
88
                        }
6✔
89

90
                        require.NoError(t, err, "command execution should not fail")
12✔
91
                        checkGoldenFile(t, tc.GoldenFileName, buf.String())
12✔
92
                })
93
        }
94
}
95

96
func checkGoldenFile(t *testing.T, filename string, actual string) {
12✔
97
        t.Helper()
12✔
98
        goldenPath := filepath.Join("testdata", filename+".golden")
12✔
99

12✔
100
        if *update {
12✔
NEW
101
                err := os.MkdirAll("testdata", 0750)
×
NEW
102
                require.NoError(t, err)
×
NEW
103

×
NEW
104
                err = os.WriteFile(goldenPath, []byte(actual), 0600)
×
NEW
105
                require.NoError(t, err)
×
NEW
106
                t.Logf("Updated golden file: %s", goldenPath)
×
NEW
107
        }
×
108

109
        // #nosec G304
110
        expected, err := os.ReadFile(goldenPath)
12✔
111
        require.NoError(t, err, "could not read golden file. Run 'go test ./... -update' to generate it")
12✔
112

12✔
113
        assert.Equal(t, string(expected), actual, "Output does not match golden file")
12✔
114
}
115

116
// LoadFixture reads a JSON file from the "fixture" directory and unmarshals
117
func LoadFixture(t *testing.T, filename string, target proto.Message) {
10✔
118
        t.Helper()
10✔
119

10✔
120
        // #nosec G304
10✔
121
        data, err := os.ReadFile(filepath.Join("fixture", filename))
10✔
122
        require.NoError(t, err, "failed to read fixture file. Check if 'fixture/%s' exists", filename)
10✔
123

10✔
124
        err = protojson.Unmarshal(data, target)
10✔
125
        require.NoError(t, err, "failed to unmarshal fixture into protobuf")
10✔
126
}
10✔
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