|
| 1 | +package cmdtest |
| 2 | + |
| 3 | +import ( |
| 4 | + "context" |
| 5 | + "fmt" |
| 6 | + "github.com/cisco-open/go-lanai/cmd/lanai-cli/cmdutils" |
| 7 | + "github.com/cisco-open/go-lanai/test" |
| 8 | + "github.com/spf13/cobra" |
| 9 | + "os" |
| 10 | + "path/filepath" |
| 11 | + "testing" |
| 12 | +) |
| 13 | + |
| 14 | +const ( |
| 15 | + TestTmpDir = ".tmp" |
| 16 | + TestOutputDir = "output" |
| 17 | +) |
| 18 | + |
| 19 | +var ( |
| 20 | + testRootCmd = &cobra.Command{ |
| 21 | + Use: "lanai-cli-test", |
| 22 | + Short: "lanai-cli for test", |
| 23 | + FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true}, |
| 24 | + PersistentPreRunE: cmdutils.MergeRunE( |
| 25 | + cmdutils.EnsureGlobalDirectories(), |
| 26 | + cmdutils.PrintEnvironment(), |
| 27 | + ), |
| 28 | + } |
| 29 | +) |
| 30 | + |
| 31 | +func init() { |
| 32 | + cmdutils.PersistentFlags(testRootCmd, &cmdutils.GlobalArgs) |
| 33 | +} |
| 34 | + |
| 35 | +func SetupResetPackageVars() test.SetupFunc { |
| 36 | + return func(ctx context.Context, t *testing.T) (context.Context, error) { |
| 37 | + cmdutils.ResetGoCmd() |
| 38 | + return ctx, nil |
| 39 | + } |
| 40 | +} |
| 41 | + |
| 42 | +// DryRunCobraCommand Run given cobra.Command in given work dir relative to "testdata" |
| 43 | +func DryRunCobraCommand(ctx context.Context, wd string, cmd *cobra.Command, handler TestDryRunHandler, args ...string) error { |
| 44 | + // prepare global args |
| 45 | + originalArgs := cmdutils.GlobalArgs |
| 46 | + defer func() { cmdutils.GlobalArgs = originalArgs }() |
| 47 | + |
| 48 | + cmdutils.GlobalArgs = cmdutils.Global{ |
| 49 | + WorkingDir: PathRelativeToTestdata(wd), |
| 50 | + TmpDir: PathRelativeToTestdata(wd, TestTmpDir), |
| 51 | + OutputDir: PathRelativeToTestdata(wd, TestOutputDir), |
| 52 | + Verbose: true, |
| 53 | + DryRun: true, |
| 54 | + } |
| 55 | + |
| 56 | + // setup dry run handler |
| 57 | + if handler != nil { |
| 58 | + cmdutils.GlobalArgs.DryRunFunc = handler.Handle |
| 59 | + } else { |
| 60 | + cmdutils.GlobalArgs.DryRunFunc = originalArgs.DryRunFunc |
| 61 | + } |
| 62 | + |
| 63 | + // clean up FS |
| 64 | + if e := os.RemoveAll(cmdutils.GlobalArgs.OutputDir); e != nil { |
| 65 | + return fmt.Errorf("unable to start command with clean FS: %w", e) |
| 66 | + } |
| 67 | + |
| 68 | + // run command |
| 69 | + if len(args) == 0 { |
| 70 | + args = []string{} |
| 71 | + } |
| 72 | + cmdCopy, _ := CopyCommandChain(cmd, args...) |
| 73 | + return cmdCopy.ExecuteContext(ctx) |
| 74 | +} |
| 75 | + |
| 76 | +// CopyCommandChain do following things: |
| 77 | +// - Make copy of given command and its parents/ancestors. |
| 78 | +// - Fix arguments of its ancestors. |
| 79 | +// - Attach the given command chain to a copy of predefined test root command (to mimic how main() function works) |
| 80 | +// This function returns copied command and a copy of its root command. Two values may be same if they are the root |
| 81 | +func CopyCommandChain(cmd *cobra.Command, args...string) (cmdCpy, rootCpy *cobra.Command) { |
| 82 | + cmdCpy = copyCmd(cmd) |
| 83 | + var cpy, prev *cobra.Command |
| 84 | + for cpy, prev = cmdCpy, nil; cpy != nil; cpy = copyCmd(cpy.Parent()) { |
| 85 | + if prev != nil { |
| 86 | + args = append([]string{prev.Name()}, args...) |
| 87 | + cpy.ResetCommands() |
| 88 | + cpy.AddCommand(prev) |
| 89 | + } |
| 90 | + cpy.SetArgs(args) |
| 91 | + prev = cpy |
| 92 | + } |
| 93 | + rootCpy = copyCmd(testRootCmd) |
| 94 | + if prev != nil { |
| 95 | + args = append([]string{prev.Name()}, args...) |
| 96 | + rootCpy.ResetCommands() |
| 97 | + rootCpy.AddCommand(prev) |
| 98 | + } |
| 99 | + rootCpy.SetArgs(args) |
| 100 | + return |
| 101 | +} |
| 102 | + |
| 103 | +func copyCmd(cmd *cobra.Command) *cobra.Command { |
| 104 | + if cmd == nil { |
| 105 | + return nil |
| 106 | + } |
| 107 | + vCopy := *cmd |
| 108 | + return &vCopy |
| 109 | +} |
| 110 | + |
| 111 | +func PathRelativeToTestdata(pathComponents ...string) string { |
| 112 | + if base, e := os.Getwd(); e != nil { |
| 113 | + pathComponents = append([]string{"testdata"}, pathComponents...) |
| 114 | + } else { |
| 115 | + pathComponents = append([]string{base, "testdata"}, pathComponents...) |
| 116 | + } |
| 117 | + return filepath.Join(pathComponents...) |
| 118 | +} |
0 commit comments