DockerCLI/e2e/cli-plugins/run_test.go

239 lines
7.0 KiB
Go
Raw Normal View History

package cliplugins
import (
"testing"
"gotest.tools/assert"
is "gotest.tools/assert/cmp"
"gotest.tools/golden"
"gotest.tools/icmd"
)
cli-plugins: Reinstate deprecated `-h` short form of `--help`. In the initial implementation I thought it would be good to not pass on the deprecation to plugins (since they are new). However it turns out this causes `docker helloworld -h` to print a spurious "pflag: help requested" line: $ docker helloworld -h pflag: help requested See 'docker helloworld --help'. Usage: docker helloworld [OPTIONS] COMMAND A basic Hello World plugin for tests ... Compared with: $ docker ps -h Flag shorthand -h has been deprecated, please use --help Usage: docker ps [OPTIONS] This is in essence because having the flag undefined hits a different path within cobra, causing `c.execute()` to return early due to getting an error (`flag.ErrHelp`) from `c.ParseFlags`, which launders the error through our `FlagErrorFunc` which wraps it in a `StatusError` which in turn defeats an `if err == flag.ErrHelp` check further up the call chain. If the flag is defined we instead hit a path which returns a bare `flag.ErrHelp` without wrapping it. I considered updating our `FlagErrorFunc` to not wrap `flag.ErrHelp` (and then following the chain to the next thing) however while doing that I realised that the code for `-h` (and `--help`) is deeply embedded into cobra (and its flags library) such that actually using `-h` as a plugin argument meaning something other than `help` is basically impossible/impractical. Therefore we may as well have plugins behave identically to the monolithic CLI and support (deprecated) the `-h` argument. With this changed the help related blocks of `SetupRootCommand` and `SetupPluginRootCommand` are now identical, so consolidate into `setupCommonRootCommand`. Tests are updated to check `-h` in a variety of scenarios, including the happy case here. Signed-off-by: Ian Campbell <ijc@docker.com>
2019-03-28 11:32:23 -04:00
const shortHFlagDeprecated = "Flag shorthand -h has been deprecated, please use --help\n"
// TestRunNonexisting ensures correct behaviour when running a nonexistent plugin.
func TestRunNonexisting(t *testing.T) {
run, _, cleanup := prepare(t)
defer cleanup()
res := icmd.RunCmd(run("nonexistent"))
res.Assert(t, icmd.Expected{
ExitCode: 1,
Out: icmd.None,
})
golden.Assert(t, res.Stderr(), "docker-nonexistent-err.golden")
}
// TestHelpNonexisting ensures correct behaviour when invoking help on a nonexistent plugin.
func TestHelpNonexisting(t *testing.T) {
run, _, cleanup := prepare(t)
defer cleanup()
res := icmd.RunCmd(run("help", "nonexistent"))
res.Assert(t, icmd.Expected{
ExitCode: 1,
Out: icmd.None,
})
golden.Assert(t, res.Stderr(), "docker-help-nonexistent-err.golden")
}
// TestNonexistingHelp ensures correct behaviour when invoking a
// nonexistent plugin with `--help`.
func TestNonexistingHelp(t *testing.T) {
run, _, cleanup := prepare(t)
defer cleanup()
res := icmd.RunCmd(run("nonexistent", "--help"))
res.Assert(t, icmd.Expected{
ExitCode: 0,
// This should actually be the whole docker help
// output, so spot check instead having of a golden
// with everything in, which will change too frequently.
Out: "Usage: docker [OPTIONS] COMMAND\n\nA self-sufficient runtime for containers",
Err: icmd.None,
})
cli-plugins: Reinstate deprecated `-h` short form of `--help`. In the initial implementation I thought it would be good to not pass on the deprecation to plugins (since they are new). However it turns out this causes `docker helloworld -h` to print a spurious "pflag: help requested" line: $ docker helloworld -h pflag: help requested See 'docker helloworld --help'. Usage: docker helloworld [OPTIONS] COMMAND A basic Hello World plugin for tests ... Compared with: $ docker ps -h Flag shorthand -h has been deprecated, please use --help Usage: docker ps [OPTIONS] This is in essence because having the flag undefined hits a different path within cobra, causing `c.execute()` to return early due to getting an error (`flag.ErrHelp`) from `c.ParseFlags`, which launders the error through our `FlagErrorFunc` which wraps it in a `StatusError` which in turn defeats an `if err == flag.ErrHelp` check further up the call chain. If the flag is defined we instead hit a path which returns a bare `flag.ErrHelp` without wrapping it. I considered updating our `FlagErrorFunc` to not wrap `flag.ErrHelp` (and then following the chain to the next thing) however while doing that I realised that the code for `-h` (and `--help`) is deeply embedded into cobra (and its flags library) such that actually using `-h` as a plugin argument meaning something other than `help` is basically impossible/impractical. Therefore we may as well have plugins behave identically to the monolithic CLI and support (deprecated) the `-h` argument. With this changed the help related blocks of `SetupRootCommand` and `SetupPluginRootCommand` are now identical, so consolidate into `setupCommonRootCommand`. Tests are updated to check `-h` in a variety of scenarios, including the happy case here. Signed-off-by: Ian Campbell <ijc@docker.com>
2019-03-28 11:32:23 -04:00
// Short -h should be the same, modulo the deprecation message
exp := shortHFlagDeprecated + res.Stdout()
res = icmd.RunCmd(run("nonexistent", "-h"))
res.Assert(t, icmd.Expected{
ExitCode: 0,
// This should be identical to the --help case above
Out: exp,
Err: icmd.None,
})
}
// TestRunBad ensures correct behaviour when running an existent but invalid plugin
func TestRunBad(t *testing.T) {
run, _, cleanup := prepare(t)
defer cleanup()
res := icmd.RunCmd(run("badmeta"))
res.Assert(t, icmd.Expected{
ExitCode: 1,
Out: icmd.None,
})
golden.Assert(t, res.Stderr(), "docker-badmeta-err.golden")
}
// TestHelpBad ensures correct behaviour when invoking help on a existent but invalid plugin.
func TestHelpBad(t *testing.T) {
run, _, cleanup := prepare(t)
defer cleanup()
res := icmd.RunCmd(run("help", "badmeta"))
res.Assert(t, icmd.Expected{
ExitCode: 1,
Out: icmd.None,
})
golden.Assert(t, res.Stderr(), "docker-help-badmeta-err.golden")
}
// TestBadHelp ensures correct behaviour when invoking an
// existent but invalid plugin with `--help`.
func TestBadHelp(t *testing.T) {
run, _, cleanup := prepare(t)
defer cleanup()
res := icmd.RunCmd(run("badmeta", "--help"))
res.Assert(t, icmd.Expected{
ExitCode: 0,
// This should be literally the whole docker help
// output, so spot check instead of a golden with
// everything in which will change all the time.
Out: "Usage: docker [OPTIONS] COMMAND\n\nA self-sufficient runtime for containers",
Err: icmd.None,
})
cli-plugins: Reinstate deprecated `-h` short form of `--help`. In the initial implementation I thought it would be good to not pass on the deprecation to plugins (since they are new). However it turns out this causes `docker helloworld -h` to print a spurious "pflag: help requested" line: $ docker helloworld -h pflag: help requested See 'docker helloworld --help'. Usage: docker helloworld [OPTIONS] COMMAND A basic Hello World plugin for tests ... Compared with: $ docker ps -h Flag shorthand -h has been deprecated, please use --help Usage: docker ps [OPTIONS] This is in essence because having the flag undefined hits a different path within cobra, causing `c.execute()` to return early due to getting an error (`flag.ErrHelp`) from `c.ParseFlags`, which launders the error through our `FlagErrorFunc` which wraps it in a `StatusError` which in turn defeats an `if err == flag.ErrHelp` check further up the call chain. If the flag is defined we instead hit a path which returns a bare `flag.ErrHelp` without wrapping it. I considered updating our `FlagErrorFunc` to not wrap `flag.ErrHelp` (and then following the chain to the next thing) however while doing that I realised that the code for `-h` (and `--help`) is deeply embedded into cobra (and its flags library) such that actually using `-h` as a plugin argument meaning something other than `help` is basically impossible/impractical. Therefore we may as well have plugins behave identically to the monolithic CLI and support (deprecated) the `-h` argument. With this changed the help related blocks of `SetupRootCommand` and `SetupPluginRootCommand` are now identical, so consolidate into `setupCommonRootCommand`. Tests are updated to check `-h` in a variety of scenarios, including the happy case here. Signed-off-by: Ian Campbell <ijc@docker.com>
2019-03-28 11:32:23 -04:00
// Short -h should be the same, modulo the deprecation message
exp := shortHFlagDeprecated + res.Stdout()
res = icmd.RunCmd(run("badmeta", "-h"))
res.Assert(t, icmd.Expected{
ExitCode: 0,
// This should be identical to the --help case above
Out: exp,
Err: icmd.None,
})
}
// TestRunGood ensures correct behaviour when running a valid plugin
func TestRunGood(t *testing.T) {
run, _, cleanup := prepare(t)
defer cleanup()
res := icmd.RunCmd(run("helloworld"))
res.Assert(t, icmd.Expected{
ExitCode: 0,
Out: "Hello World!",
Err: icmd.None,
})
}
// TestHelpGood ensures correct behaviour when invoking help on a
// valid plugin. A global argument is included to ensure it does not
// interfere.
func TestHelpGood(t *testing.T) {
run, _, cleanup := prepare(t)
defer cleanup()
res := icmd.RunCmd(run("-l", "info", "help", "helloworld"))
res.Assert(t, icmd.Expected{
ExitCode: 0,
Err: icmd.None,
})
golden.Assert(t, res.Stdout(), "docker-help-helloworld.golden")
}
// TestGoodHelp ensures correct behaviour when calling a valid plugin
// with `--help`. A global argument is used to ensure it does not
// interfere.
func TestGoodHelp(t *testing.T) {
run, _, cleanup := prepare(t)
defer cleanup()
res := icmd.RunCmd(run("-l", "info", "helloworld", "--help"))
res.Assert(t, icmd.Expected{
ExitCode: 0,
Err: icmd.None,
})
// This is the same golden file as `TestHelpGood`, above.
golden.Assert(t, res.Stdout(), "docker-help-helloworld.golden")
cli-plugins: Reinstate deprecated `-h` short form of `--help`. In the initial implementation I thought it would be good to not pass on the deprecation to plugins (since they are new). However it turns out this causes `docker helloworld -h` to print a spurious "pflag: help requested" line: $ docker helloworld -h pflag: help requested See 'docker helloworld --help'. Usage: docker helloworld [OPTIONS] COMMAND A basic Hello World plugin for tests ... Compared with: $ docker ps -h Flag shorthand -h has been deprecated, please use --help Usage: docker ps [OPTIONS] This is in essence because having the flag undefined hits a different path within cobra, causing `c.execute()` to return early due to getting an error (`flag.ErrHelp`) from `c.ParseFlags`, which launders the error through our `FlagErrorFunc` which wraps it in a `StatusError` which in turn defeats an `if err == flag.ErrHelp` check further up the call chain. If the flag is defined we instead hit a path which returns a bare `flag.ErrHelp` without wrapping it. I considered updating our `FlagErrorFunc` to not wrap `flag.ErrHelp` (and then following the chain to the next thing) however while doing that I realised that the code for `-h` (and `--help`) is deeply embedded into cobra (and its flags library) such that actually using `-h` as a plugin argument meaning something other than `help` is basically impossible/impractical. Therefore we may as well have plugins behave identically to the monolithic CLI and support (deprecated) the `-h` argument. With this changed the help related blocks of `SetupRootCommand` and `SetupPluginRootCommand` are now identical, so consolidate into `setupCommonRootCommand`. Tests are updated to check `-h` in a variety of scenarios, including the happy case here. Signed-off-by: Ian Campbell <ijc@docker.com>
2019-03-28 11:32:23 -04:00
// Short -h should be the same, modulo the deprecation message
exp := shortHFlagDeprecated + res.Stdout()
res = icmd.RunCmd(run("-l", "info", "helloworld", "-h"))
cli-plugins: Reinstate deprecated `-h` short form of `--help`. In the initial implementation I thought it would be good to not pass on the deprecation to plugins (since they are new). However it turns out this causes `docker helloworld -h` to print a spurious "pflag: help requested" line: $ docker helloworld -h pflag: help requested See 'docker helloworld --help'. Usage: docker helloworld [OPTIONS] COMMAND A basic Hello World plugin for tests ... Compared with: $ docker ps -h Flag shorthand -h has been deprecated, please use --help Usage: docker ps [OPTIONS] This is in essence because having the flag undefined hits a different path within cobra, causing `c.execute()` to return early due to getting an error (`flag.ErrHelp`) from `c.ParseFlags`, which launders the error through our `FlagErrorFunc` which wraps it in a `StatusError` which in turn defeats an `if err == flag.ErrHelp` check further up the call chain. If the flag is defined we instead hit a path which returns a bare `flag.ErrHelp` without wrapping it. I considered updating our `FlagErrorFunc` to not wrap `flag.ErrHelp` (and then following the chain to the next thing) however while doing that I realised that the code for `-h` (and `--help`) is deeply embedded into cobra (and its flags library) such that actually using `-h` as a plugin argument meaning something other than `help` is basically impossible/impractical. Therefore we may as well have plugins behave identically to the monolithic CLI and support (deprecated) the `-h` argument. With this changed the help related blocks of `SetupRootCommand` and `SetupPluginRootCommand` are now identical, so consolidate into `setupCommonRootCommand`. Tests are updated to check `-h` in a variety of scenarios, including the happy case here. Signed-off-by: Ian Campbell <ijc@docker.com>
2019-03-28 11:32:23 -04:00
res.Assert(t, icmd.Expected{
ExitCode: 0,
// This should be identical to the --help case above
Out: exp,
Err: icmd.None,
})
}
// TestRunGoodSubcommand ensures correct behaviour when running a valid plugin with a subcommand
func TestRunGoodSubcommand(t *testing.T) {
run, _, cleanup := prepare(t)
defer cleanup()
res := icmd.RunCmd(run("helloworld", "goodbye"))
res.Assert(t, icmd.Expected{
ExitCode: 0,
Out: "Goodbye World!",
Err: icmd.None,
})
}
// TestHelpGoodSubcommand ensures correct behaviour when invoking help on a
// valid plugin subcommand. A global argument is included to ensure it does not
// interfere.
func TestHelpGoodSubcommand(t *testing.T) {
run, _, cleanup := prepare(t)
defer cleanup()
res := icmd.RunCmd(run("-l", "info", "help", "helloworld", "goodbye"))
res.Assert(t, icmd.Expected{
ExitCode: 0,
Err: icmd.None,
})
golden.Assert(t, res.Stdout(), "docker-help-helloworld-goodbye.golden")
}
// TestGoodSubcommandHelp ensures correct behaviour when calling a valid plugin
// with a subcommand and `--help`. A global argument is used to ensure it does not
// interfere.
func TestGoodSubcommandHelp(t *testing.T) {
run, _, cleanup := prepare(t)
defer cleanup()
res := icmd.RunCmd(run("-l", "info", "helloworld", "goodbye", "--help"))
res.Assert(t, icmd.Expected{
ExitCode: 0,
Err: icmd.None,
})
// This is the same golden file as `TestHelpGoodSubcommand`, above.
golden.Assert(t, res.Stdout(), "docker-help-helloworld-goodbye.golden")
}
// TestCliInitialized tests the code paths which ensure that the Cli
// object is initialized even if the plugin uses PersistentRunE
func TestCliInitialized(t *testing.T) {
run, _, cleanup := prepare(t)
defer cleanup()
res := icmd.RunCmd(run("helloworld", "--pre-run", "apiversion"))
res.Assert(t, icmd.Success)
assert.Assert(t, res.Stdout() != "")
assert.Assert(t, is.Equal(res.Stderr(), "Plugin PersistentPreRunE called"))
}
// TestPluginErrorCode tests when the plugin return with a given exit status.
// We want to verify that the exit status does not get output to stdout and also that we return the exit code.
func TestPluginErrorCode(t *testing.T) {
run, _, cleanup := prepare(t)
defer cleanup()
res := icmd.RunCmd(run("helloworld", "exitstatus2"))
res.Assert(t, icmd.Expected{
ExitCode: 2,
Out: icmd.None,
Err: "Exiting with error status 2",
})
}