Merge pull request #83369 from ereslibre/feature-gates-test

kubeadm: add test to detect panics when given certain feature gates
This commit is contained in:
Kubernetes Prow Robot 2019-10-01 17:23:19 -07:00 committed by GitHub
commit 1fe922efcc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 77 additions and 28 deletions

View File

@ -37,7 +37,7 @@ func TestCmdCompletion(t *testing.T) {
for _, rt := range tests { for _, rt := range tests {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
_, _, actual := RunCmd(kubeadmPath, "completion", rt.args) _, _, _, actual := RunCmd(kubeadmPath, "completion", rt.args)
if (actual == nil) != rt.expected { if (actual == nil) != rt.expected {
t.Errorf( t.Errorf(
"failed CmdCompletion running 'kubeadm completion %s' with an error: %v\n\texpected: %t\n\t actual: %t", "failed CmdCompletion running 'kubeadm completion %s' with an error: %v\n\texpected: %t\n\t actual: %t",

View File

@ -29,7 +29,7 @@ import (
testutil "k8s.io/kubernetes/cmd/kubeadm/test" testutil "k8s.io/kubernetes/cmd/kubeadm/test"
) )
func runKubeadmInit(args ...string) (string, string, error) { func runKubeadmInit(args ...string) (string, string, int, error) {
kubeadmPath := getKubeadmPath() kubeadmPath := getKubeadmPath()
kubeadmArgs := []string{"init", "--dry-run", "--ignore-preflight-errors=all"} kubeadmArgs := []string{"init", "--dry-run", "--ignore-preflight-errors=all"}
kubeadmArgs = append(kubeadmArgs, args...) kubeadmArgs = append(kubeadmArgs, args...)
@ -66,7 +66,7 @@ func TestCmdInitToken(t *testing.T) {
for _, rt := range initTest { for _, rt := range initTest {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
_, _, err := runKubeadmInit(rt.args) _, _, _, err := runKubeadmInit(rt.args)
if (err == nil) != rt.expected { if (err == nil) != rt.expected {
t.Fatalf(dedent.Dedent(` t.Fatalf(dedent.Dedent(`
CmdInitToken test case %q failed with an error: %v CmdInitToken test case %q failed with an error: %v
@ -110,7 +110,7 @@ func TestCmdInitKubernetesVersion(t *testing.T) {
for _, rt := range initTest { for _, rt := range initTest {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
_, _, err := runKubeadmInit(rt.args) _, _, _, err := runKubeadmInit(rt.args)
if (err == nil) != rt.expected { if (err == nil) != rt.expected {
t.Fatalf(dedent.Dedent(` t.Fatalf(dedent.Dedent(`
CmdInitKubernetesVersion test case %q failed with an error: %v CmdInitKubernetesVersion test case %q failed with an error: %v
@ -184,7 +184,7 @@ func TestCmdInitConfig(t *testing.T) {
for _, rt := range initTest { for _, rt := range initTest {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
_, _, err := runKubeadmInit(rt.args) _, _, _, err := runKubeadmInit(rt.args)
if (err == nil) != rt.expected { if (err == nil) != rt.expected {
t.Fatalf(dedent.Dedent(` t.Fatalf(dedent.Dedent(`
CmdInitConfig test case %q failed with an error: %v CmdInitConfig test case %q failed with an error: %v
@ -235,7 +235,7 @@ func TestCmdInitCertPhaseCSR(t *testing.T) {
csrDir := testutil.SetupTempDir(t) csrDir := testutil.SetupTempDir(t)
cert := &certs.KubeadmCertKubeletClient cert := &certs.KubeadmCertKubeletClient
kubeadmPath := getKubeadmPath() kubeadmPath := getKubeadmPath()
_, stderr, err := RunCmd(kubeadmPath, _, stderr, _, err := RunCmd(kubeadmPath,
"init", "init",
"phase", "phase",
"certs", "certs",
@ -303,7 +303,7 @@ func TestCmdInitAPIPort(t *testing.T) {
for _, rt := range initTest { for _, rt := range initTest {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
_, _, err := runKubeadmInit(rt.args) _, _, _, err := runKubeadmInit(rt.args)
if (err == nil) != rt.expected { if (err == nil) != rt.expected {
t.Fatalf(dedent.Dedent(` t.Fatalf(dedent.Dedent(`
CmdInitAPIPort test case %q failed with an error: %v CmdInitAPIPort test case %q failed with an error: %v
@ -321,3 +321,52 @@ func TestCmdInitAPIPort(t *testing.T) {
}) })
} }
} }
// TestCmdInitFeatureGates test that feature gates won't make kubeadm panic.
// When go panics it will exit with a 2 code. While we don't expect the init
// calls to succeed in these tests, we ensure that the exit code of calling
// kubeadm with different feature gates is not 2.
func TestCmdInitFeatureGates(t *testing.T) {
const PanicExitcode = 2
if *kubeadmCmdSkip {
t.Log("kubeadm cmd tests being skipped")
t.Skip()
}
initTest := []struct {
name string
args string
}{
{
name: "no feature gates passed",
args: "",
},
{
name: "feature gate CoreDNS=true",
args: "--feature-gates=CoreDNS=true",
},
{
name: "feature gate IPv6DualStack=true",
args: "--feature-gates=IPv6DualStack=true",
},
}
for _, rt := range initTest {
t.Run(rt.name, func(t *testing.T) {
_, _, exitcode, err := runKubeadmInit(rt.args)
if exitcode == PanicExitcode {
t.Fatalf(dedent.Dedent(`
CmdInitFeatureGates test case %q failed with an error: %v
command 'kubeadm init %s'
got exit code: %t (panic); unexpected
`),
rt.name,
err,
rt.args,
PanicExitcode,
)
}
})
}
}

View File

@ -21,7 +21,7 @@ import "testing"
// kubeadmReset executes "kubeadm reset" and restarts kubelet. // kubeadmReset executes "kubeadm reset" and restarts kubelet.
func kubeadmReset() error { func kubeadmReset() error {
kubeadmPath := getKubeadmPath() kubeadmPath := getKubeadmPath()
_, _, err := RunCmd(kubeadmPath, "reset") _, _, _, err := RunCmd(kubeadmPath, "reset")
return err return err
} }
@ -43,7 +43,7 @@ func TestCmdJoinConfig(t *testing.T) {
kubeadmPath := getKubeadmPath() kubeadmPath := getKubeadmPath()
for _, rt := range initTest { for _, rt := range initTest {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
_, _, actual := RunCmd(kubeadmPath, "join", rt.args, "--ignore-preflight-errors=all") _, _, _, actual := RunCmd(kubeadmPath, "join", rt.args, "--ignore-preflight-errors=all")
if (actual == nil) != rt.expected { if (actual == nil) != rt.expected {
t.Errorf( t.Errorf(
"failed CmdJoinConfig running 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t", "failed CmdJoinConfig running 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t",
@ -76,7 +76,7 @@ func TestCmdJoinDiscoveryFile(t *testing.T) {
kubeadmPath := getKubeadmPath() kubeadmPath := getKubeadmPath()
for _, rt := range initTest { for _, rt := range initTest {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
_, _, actual := RunCmd(kubeadmPath, "join", rt.args, "--ignore-preflight-errors=all") _, _, _, actual := RunCmd(kubeadmPath, "join", rt.args, "--ignore-preflight-errors=all")
if (actual == nil) != rt.expected { if (actual == nil) != rt.expected {
t.Errorf( t.Errorf(
"failed CmdJoinDiscoveryFile running 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t", "failed CmdJoinDiscoveryFile running 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t",
@ -109,7 +109,7 @@ func TestCmdJoinDiscoveryToken(t *testing.T) {
kubeadmPath := getKubeadmPath() kubeadmPath := getKubeadmPath()
for _, rt := range initTest { for _, rt := range initTest {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
_, _, actual := RunCmd(kubeadmPath, "join", rt.args, "--ignore-preflight-errors=all") _, _, _, actual := RunCmd(kubeadmPath, "join", rt.args, "--ignore-preflight-errors=all")
if (actual == nil) != rt.expected { if (actual == nil) != rt.expected {
t.Errorf( t.Errorf(
"failed CmdJoinDiscoveryToken running 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t", "failed CmdJoinDiscoveryToken running 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t",
@ -141,7 +141,7 @@ func TestCmdJoinNodeName(t *testing.T) {
kubeadmPath := getKubeadmPath() kubeadmPath := getKubeadmPath()
for _, rt := range initTest { for _, rt := range initTest {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
_, _, actual := RunCmd(kubeadmPath, "join", rt.args, "--ignore-preflight-errors=all") _, _, _, actual := RunCmd(kubeadmPath, "join", rt.args, "--ignore-preflight-errors=all")
if (actual == nil) != rt.expected { if (actual == nil) != rt.expected {
t.Errorf( t.Errorf(
"failed CmdJoinNodeName running 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t", "failed CmdJoinNodeName running 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t",
@ -174,7 +174,7 @@ func TestCmdJoinTLSBootstrapToken(t *testing.T) {
kubeadmPath := getKubeadmPath() kubeadmPath := getKubeadmPath()
for _, rt := range initTest { for _, rt := range initTest {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
_, _, actual := RunCmd(kubeadmPath, "join", rt.args, "--ignore-preflight-errors=all") _, _, _, actual := RunCmd(kubeadmPath, "join", rt.args, "--ignore-preflight-errors=all")
if (actual == nil) != rt.expected { if (actual == nil) != rt.expected {
t.Errorf( t.Errorf(
"failed CmdJoinTLSBootstrapToken running 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t", "failed CmdJoinTLSBootstrapToken running 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t",
@ -207,7 +207,7 @@ func TestCmdJoinToken(t *testing.T) {
kubeadmPath := getKubeadmPath() kubeadmPath := getKubeadmPath()
for _, rt := range initTest { for _, rt := range initTest {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
_, _, actual := RunCmd(kubeadmPath, "join", rt.args, "--ignore-preflight-errors=all") _, _, _, actual := RunCmd(kubeadmPath, "join", rt.args, "--ignore-preflight-errors=all")
if (actual == nil) != rt.expected { if (actual == nil) != rt.expected {
t.Errorf( t.Errorf(
"failed CmdJoinToken running 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t", "failed CmdJoinToken running 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t",
@ -240,7 +240,7 @@ func TestCmdJoinBadArgs(t *testing.T) {
for _, rt := range initTest { for _, rt := range initTest {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
_, _, actual := RunCmd(kubeadmPath, "join", rt.args, "--ignore-preflight-errors=all") _, _, _, actual := RunCmd(kubeadmPath, "join", rt.args, "--ignore-preflight-errors=all")
if (actual == nil) != rt.expected { if (actual == nil) != rt.expected {
t.Errorf( t.Errorf(
"failed CmdJoinBadArgs 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t", "failed CmdJoinBadArgs 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t",
@ -272,7 +272,7 @@ func TestCmdJoinArgsMixed(t *testing.T) {
kubeadmPath := getKubeadmPath() kubeadmPath := getKubeadmPath()
for _, rt := range initTest { for _, rt := range initTest {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
_, _, actual := RunCmd(kubeadmPath, "join", rt.args, "--ignore-preflight-errors=all") _, _, _, actual := RunCmd(kubeadmPath, "join", rt.args, "--ignore-preflight-errors=all")
if (actual == nil) != rt.expected { if (actual == nil) != rt.expected {
t.Errorf( t.Errorf(
"failed CmdJoinArgsMixed running 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t", "failed CmdJoinArgsMixed running 'kubeadm join %s' with an error: %v\n\texpected: %t\n\t actual: %t",

View File

@ -48,7 +48,7 @@ func TestCmdTokenGenerate(t *testing.T) {
t.Log("kubeadm cmd tests being skipped") t.Log("kubeadm cmd tests being skipped")
t.Skip() t.Skip()
} }
stdout, _, err := RunCmd(kubeadmPath, "token", "generate") stdout, _, _, err := RunCmd(kubeadmPath, "token", "generate")
if err != nil { if err != nil {
t.Fatalf("'kubeadm token generate' exited uncleanly: %v", err) t.Fatalf("'kubeadm token generate' exited uncleanly: %v", err)
} }
@ -78,7 +78,7 @@ func TestCmdTokenGenerateTypoError(t *testing.T) {
} }
kubeadmPath := getKubeadmPath() kubeadmPath := getKubeadmPath()
_, _, err := RunCmd(kubeadmPath, "token", "genorate") // subtle typo _, _, _, err := RunCmd(kubeadmPath, "token", "genorate") // subtle typo
if err == nil { if err == nil {
t.Error("'kubeadm token genorate' (a deliberate typo) exited without an error when we expected non-zero exit status") t.Error("'kubeadm token genorate' (a deliberate typo) exited without an error when we expected non-zero exit status")
} }
@ -101,7 +101,7 @@ func TestCmdTokenDelete(t *testing.T) {
kubeadmPath := getKubeadmPath() kubeadmPath := getKubeadmPath()
for _, rt := range tests { for _, rt := range tests {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
_, _, actual := RunCmd(kubeadmPath, "token", "delete", rt.args) _, _, _, actual := RunCmd(kubeadmPath, "token", "delete", rt.args)
if (actual == nil) != rt.expected { if (actual == nil) != rt.expected {
t.Errorf( t.Errorf(
"failed CmdTokenDelete running 'kubeadm token %s' with an error: %v\n\texpected: %t\n\t actual: %t", "failed CmdTokenDelete running 'kubeadm token %s' with an error: %v\n\texpected: %t\n\t actual: %t",

View File

@ -29,24 +29,24 @@ import (
// Forked from test/e2e/framework because the e2e framework is quite bloated // Forked from test/e2e/framework because the e2e framework is quite bloated
// for our purposes here, and modified to remove undesired logging. // for our purposes here, and modified to remove undesired logging.
func runCmdNoWrap(command string, args ...string) (string, string, error) { func runCmdNoWrap(command string, args ...string) (string, string, int, error) {
var bout, berr bytes.Buffer var bout, berr bytes.Buffer
cmd := exec.Command(command, args...) cmd := exec.Command(command, args...)
cmd.Stdout = &bout cmd.Stdout = &bout
cmd.Stderr = &berr cmd.Stderr = &berr
err := cmd.Run() err := cmd.Run()
stdout, stderr := bout.String(), berr.String() stdout, stderr := bout.String(), berr.String()
return stdout, stderr, err return stdout, stderr, cmd.ProcessState.ExitCode(), err
} }
// RunCmd is a utility function for kubeadm testing that executes a specified command // RunCmd is a utility function for kubeadm testing that executes a specified command
func RunCmd(command string, args ...string) (string, string, error) { func RunCmd(command string, args ...string) (string, string, int, error) {
stdout, stderr, err := runCmdNoWrap(command, args...) stdout, stderr, retcode, err := runCmdNoWrap(command, args...)
if err != nil { if err != nil {
return stdout, stderr, errors.Wrapf(err, "error running %s %v; \nstdout %q, \nstderr %q, \ngot error", return stdout, stderr, retcode, errors.Wrapf(err, "error running %s %v; \nretcode %d, \nstdout %q, \nstderr %q, \ngot error",
command, args, stdout, stderr) command, args, retcode, stdout, stderr)
} }
return stdout, stderr, nil return stdout, stderr, retcode, nil
} }
// RunSubCommand is a utility function for kubeadm testing that executes a Cobra sub command // RunSubCommand is a utility function for kubeadm testing that executes a Cobra sub command

View File

@ -53,7 +53,7 @@ func TestCmdVersion(t *testing.T) {
kubeadmPath := getKubeadmPath() kubeadmPath := getKubeadmPath()
for _, rt := range versionTest { for _, rt := range versionTest {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
stdout, _, actual := RunCmd(kubeadmPath, "version", rt.args) stdout, _, _, actual := RunCmd(kubeadmPath, "version", rt.args)
if (actual == nil) != rt.expected { if (actual == nil) != rt.expected {
t.Errorf( t.Errorf(
"failed CmdVersion running 'kubeadm version %s' with an error: %v\n\texpected: %t\n\t actual: %t", "failed CmdVersion running 'kubeadm version %s' with an error: %v\n\texpected: %t\n\t actual: %t",
@ -96,7 +96,7 @@ func TestCmdVersionOutputJsonOrYaml(t *testing.T) {
kubeadmPath := getKubeadmPath() kubeadmPath := getKubeadmPath()
for _, rt := range versionTest { for _, rt := range versionTest {
t.Run(rt.name, func(t *testing.T) { t.Run(rt.name, func(t *testing.T) {
stdout, _, actual := RunCmd(kubeadmPath, "version", rt.args) stdout, _, _, actual := RunCmd(kubeadmPath, "version", rt.args)
if (actual == nil) != rt.expected { if (actual == nil) != rt.expected {
t.Errorf( t.Errorf(
"failed CmdVersion running 'kubeadm version %s' with an error: %v\n\texpected: %t\n\t actual: %t", "failed CmdVersion running 'kubeadm version %s' with an error: %v\n\texpected: %t\n\t actual: %t",