1 package cmdx
2
3 import (
4 "bytes"
5 "context"
6 "encoding/json"
7 "fmt"
8 "io"
9 "io/ioutil"
10 "net/http"
11 "os"
12 "testing"
13
14 "github.com/spf13/cobra"
15 "github.com/stretchr/testify/require"
16
17 "github.com/pkg/errors"
18
19 "github.com/ory/x/logrusx"
20 )
21
22 var (
23
24 ErrNilDependency = errors.New("a dependency was expected to be defined but is nil. Please open an issue with the stack trace")
25
26 ErrNoPrintButFail = errors.New("this error should never be printed")
27 )
28
29
30
31 func FailSilently(cmd *cobra.Command) error {
32 cmd.SilenceErrors = true
33 cmd.SilenceUsage = true
34 return errors.WithStack(ErrNoPrintButFail)
35 }
36
37
38 func Must(err error, message string, args ...interface{}) {
39 if err == nil {
40 return
41 }
42
43 _, _ = fmt.Fprintf(os.Stderr, message+"\n", args...)
44 os.Exit(1)
45 }
46
47
48 func CheckResponse(err error, expectedStatusCode int, response *http.Response) {
49 Must(err, "Command failed because error occurred: %s", err)
50
51 if response.StatusCode != expectedStatusCode {
52 out, err := ioutil.ReadAll(response.Body)
53 if err != nil {
54 out = []byte{}
55 }
56 pretty, err := json.MarshalIndent(json.RawMessage(out), "", "\t")
57 if err == nil {
58 out = pretty
59 }
60
61 Fatalf(
62 `Command failed because status code %d was expected but code %d was received.
63
64 Response payload:
65
66 %s`,
67 expectedStatusCode,
68 response.StatusCode,
69 out,
70 )
71 }
72 }
73
74
75 func FormatResponse(o interface{}) string {
76 out, err := json.MarshalIndent(o, "", "\t")
77 Must(err, `Command failed because an error occurred while prettifying output: %s`, err)
78 return string(out)
79 }
80
81
82 func Fatalf(message string, args ...interface{}) {
83 if len(args) > 0 {
84 _, _ = fmt.Fprintf(os.Stderr, message+"\n", args...)
85 } else {
86 _, _ = fmt.Fprintln(os.Stderr, message)
87 }
88 os.Exit(1)
89 }
90
91
92 func ExpectDependency(logger *logrusx.Logger, dependencies ...interface{}) {
93 if logger == nil {
94 panic("missing logger for dependency check")
95 }
96 for _, d := range dependencies {
97 if d == nil {
98 logger.WithError(errors.WithStack(ErrNilDependency)).Fatalf("A fatal issue occurred.")
99 }
100 }
101 }
102
103
104
105 func Exec(t testing.TB, cmd *cobra.Command, stdIn io.Reader, args ...string) (string, string, error) {
106 ctx, cancel := context.WithCancel(context.Background())
107 t.Cleanup(cancel)
108
109 return ExecCtx(ctx, cmd, stdIn, args...)
110 }
111
112 func ExecCtx(ctx context.Context, cmd *cobra.Command, stdIn io.Reader, args ...string) (string, string, error) {
113 stdOut, stdErr := &bytes.Buffer{}, &bytes.Buffer{}
114 cmd.SetErr(stdErr)
115 cmd.SetOut(stdOut)
116 cmd.SetIn(stdIn)
117 defer cmd.SetIn(nil)
118 if args == nil {
119 args = []string{}
120 }
121 cmd.SetArgs(args)
122 err := cmd.ExecuteContext(ctx)
123 return stdOut.String(), stdErr.String(), err
124 }
125
126
127
128 func ExecNoErr(t testing.TB, cmd *cobra.Command, args ...string) string {
129 ctx, cancel := context.WithCancel(context.Background())
130 t.Cleanup(cancel)
131
132 return ExecNoErrCtx(ctx, t, cmd, args...)
133 }
134
135 func ExecNoErrCtx(ctx context.Context, t require.TestingT, cmd *cobra.Command, args ...string) string {
136 stdOut, stdErr, err := ExecCtx(ctx, cmd, nil, args...)
137 require.NoError(t, err, "std_out: %s\nstd_err: %s", stdOut, stdErr)
138 require.Len(t, stdErr, 0, stdOut)
139 return stdOut
140 }
141
142
143
144 func ExecExpectedErr(t testing.TB, cmd *cobra.Command, args ...string) string {
145 ctx, cancel := context.WithCancel(context.Background())
146 t.Cleanup(cancel)
147
148 return ExecExpectedErrCtx(ctx, t, cmd, args...)
149 }
150
151 func ExecExpectedErrCtx(ctx context.Context, t require.TestingT, cmd *cobra.Command, args ...string) string {
152 stdOut, stdErr, err := ExecCtx(ctx, cmd, nil, args...)
153 require.True(t, errors.Is(err, ErrNoPrintButFail), "std_out: %s\nstd_err: %s", stdOut, stdErr)
154 require.Len(t, stdOut, 0, stdErr)
155 return stdErr
156 }
157
158 type CommandExecuter struct {
159 New func() *cobra.Command
160 Ctx context.Context
161 PersistentArgs []string
162 }
163
164 func (c *CommandExecuter) Exec(stdin io.Reader, args ...string) (string, string, error) {
165 return ExecCtx(c.Ctx, c.New(), stdin, append(c.PersistentArgs, args...)...)
166 }
167
168 func (c *CommandExecuter) ExecNoErr(t require.TestingT, args ...string) string {
169 return ExecNoErrCtx(c.Ctx, t, c.New(), append(c.PersistentArgs, args...)...)
170 }
171
172 func (c *CommandExecuter) ExecExpectedErr(t require.TestingT, args ...string) string {
173 return ExecExpectedErrCtx(c.Ctx, t, c.New(), append(c.PersistentArgs, args...)...)
174 }
175
View as plain text