mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-05 10:19:50 +00:00
Merge pull request #4145 from zmerlynn/contort_shell_under_go_tests
Pervert e2e shell tests to run under Ginkgo
This commit is contained in:
commit
827dcbc623
@ -1,23 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Copyright 2014 Google Inc. All rights reserved.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
set -o errexit
|
|
||||||
set -o nounset
|
|
||||||
set -o pipefail
|
|
||||||
|
|
||||||
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
|
|
||||||
|
|
||||||
exec "${KUBE_ROOT}/hack/e2e-suite/goe2e.sh" -t TestNetwork
|
|
156
hack/e2e.go
156
hack/e2e.go
@ -30,10 +30,8 @@ import (
|
|||||||
"os/signal"
|
"os/signal"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -44,12 +42,8 @@ var (
|
|||||||
push = flag.Bool("push", false, "If true, push to e2e cluster. Has no effect if -up is true.")
|
push = flag.Bool("push", false, "If true, push to e2e cluster. Has no effect if -up is true.")
|
||||||
pushup = flag.Bool("pushup", false, "If true, push to e2e cluster if it's up, otherwise start the e2e cluster.")
|
pushup = flag.Bool("pushup", false, "If true, push to e2e cluster if it's up, otherwise start the e2e cluster.")
|
||||||
down = flag.Bool("down", false, "If true, tear down the cluster before exiting.")
|
down = flag.Bool("down", false, "If true, tear down the cluster before exiting.")
|
||||||
orderseed = flag.Int64("orderseed", 0, "If non-zero, seed of random test shuffle order. (Otherwise random.)")
|
test = flag.Bool("test", false, "Run Ginkgo tests.")
|
||||||
test = flag.Bool("test", false, "Run all tests in hack/e2e-suite.")
|
|
||||||
tests = flag.String("tests", "", "Run only tests in hack/e2e-suite matching this glob. Ignored if -test is set.")
|
|
||||||
times = flag.Int("times", 1, "Number of times each test is eligible to be run. Individual order is determined by shuffling --times instances of each test using --orderseed (like a multi-deck shoe of cards).")
|
|
||||||
root = flag.String("root", absOrDie(filepath.Clean(filepath.Join(path.Base(os.Args[0]), ".."))), "Root directory of kubernetes repository.")
|
root = flag.String("root", absOrDie(filepath.Clean(filepath.Join(path.Base(os.Args[0]), ".."))), "Root directory of kubernetes repository.")
|
||||||
tap = flag.Bool("tap", false, "Enable Test Anything Protocol (TAP) output (disables --verbose, only failure output recorded)")
|
|
||||||
verbose = flag.Bool("v", false, "If true, print all command output.")
|
verbose = flag.Bool("v", false, "If true, print all command output.")
|
||||||
trace_bash = flag.Bool("trace-bash", false, "If true, pass -x to bash to trace all bash commands")
|
trace_bash = flag.Bool("trace-bash", false, "If true, pass -x to bash to trace all bash commands")
|
||||||
checkVersionSkew = flag.Bool("check_version_skew", true, ""+
|
checkVersionSkew = flag.Bool("check_version_skew", true, ""+
|
||||||
@ -95,21 +89,6 @@ func main() {
|
|||||||
flag.Parse()
|
flag.Parse()
|
||||||
signal.Notify(signals, os.Interrupt)
|
signal.Notify(signals, os.Interrupt)
|
||||||
|
|
||||||
if *tap {
|
|
||||||
fmt.Printf("TAP version 13\n")
|
|
||||||
log.SetPrefix("# ")
|
|
||||||
|
|
||||||
// TODO: this limitation is fixable by moving runBash to
|
|
||||||
// outputing to temp files, which still lets people check on
|
|
||||||
// stuck things interactively. The current stdout/stderr
|
|
||||||
// approach isn't really going to work with TAP, though.
|
|
||||||
*verbose = false
|
|
||||||
}
|
|
||||||
|
|
||||||
if *test {
|
|
||||||
*tests = "*"
|
|
||||||
}
|
|
||||||
|
|
||||||
if *isup {
|
if *isup {
|
||||||
status := 1
|
status := 1
|
||||||
if IsUp() {
|
if IsUp() {
|
||||||
@ -168,8 +147,8 @@ func main() {
|
|||||||
switch {
|
switch {
|
||||||
case *ctlCmd != "":
|
case *ctlCmd != "":
|
||||||
failure = !runBash("'kubectl "+*ctlCmd+"'", "$KUBECTL "+*ctlCmd)
|
failure = !runBash("'kubectl "+*ctlCmd+"'", "$KUBECTL "+*ctlCmd)
|
||||||
case *tests != "":
|
case *test:
|
||||||
failure = PrintResults(Test())
|
failure = Test()
|
||||||
}
|
}
|
||||||
|
|
||||||
if *down {
|
if *down {
|
||||||
@ -278,7 +257,7 @@ func shuffleStrings(strings []string, r *rand.Rand) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test() (results ResultsByTest) {
|
func Test() bool {
|
||||||
defer runBashUntil("watchEvents", "while true; do $KUBECTL --watch-only get events; done")()
|
defer runBashUntil("watchEvents", "while true; do $KUBECTL --watch-only get events; done")()
|
||||||
|
|
||||||
if !IsUp() {
|
if !IsUp() {
|
||||||
@ -287,128 +266,7 @@ func Test() (results ResultsByTest) {
|
|||||||
|
|
||||||
ValidateClusterSize()
|
ValidateClusterSize()
|
||||||
|
|
||||||
// run tests!
|
return runBash("Ginkgo tests", filepath.Join(*root, "hack", "ginkgo-e2e.sh"))
|
||||||
dir, err := os.Open(filepath.Join(*root, "hack", "e2e-suite"))
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Couldn't open e2e-suite dir")
|
|
||||||
}
|
|
||||||
defer dir.Close()
|
|
||||||
names, err := dir.Readdirnames(0)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Couldn't read names in e2e-suite dir")
|
|
||||||
}
|
|
||||||
|
|
||||||
toRun := make([]string, 0, len(names))
|
|
||||||
for i := range names {
|
|
||||||
name := names[i]
|
|
||||||
if name == "." || name == ".." {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if match, err := path.Match(*tests, name); !match && err == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Bad test pattern: %v", *tests)
|
|
||||||
}
|
|
||||||
toRun = append(toRun, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if *orderseed == 0 {
|
|
||||||
// Use low order bits of NanoTime as the default seed. (Using
|
|
||||||
// all the bits makes for a long, very similar looking seed
|
|
||||||
// between runs.)
|
|
||||||
*orderseed = time.Now().UnixNano() & (1<<32 - 1)
|
|
||||||
}
|
|
||||||
sort.Strings(toRun)
|
|
||||||
if *times != 1 {
|
|
||||||
if *times <= 0 {
|
|
||||||
log.Fatal("Invalid --times (negative or no testing requested)!")
|
|
||||||
}
|
|
||||||
newToRun := make([]string, 0, *times*len(toRun))
|
|
||||||
for i := 0; i < *times; i++ {
|
|
||||||
newToRun = append(newToRun, toRun...)
|
|
||||||
}
|
|
||||||
toRun = newToRun
|
|
||||||
}
|
|
||||||
shuffleStrings(toRun, rand.New(rand.NewSource(*orderseed)))
|
|
||||||
log.Printf("Running tests matching %v shuffled with seed %#x: %v", *tests, *orderseed, toRun)
|
|
||||||
results = ResultsByTest{}
|
|
||||||
if *tap {
|
|
||||||
fmt.Printf("1..%v\n", len(toRun))
|
|
||||||
}
|
|
||||||
for i, name := range toRun {
|
|
||||||
absName := filepath.Join(*root, "hack", "e2e-suite", name)
|
|
||||||
log.Printf("Starting test [%v/%v]: %v", i+1, len(toRun), name)
|
|
||||||
start := time.Now()
|
|
||||||
testResult := results[name]
|
|
||||||
res, stdout, stderr := runBashWithOutputs(name, absName)
|
|
||||||
// The duration_ms output is an undocumented Jenkins TAP
|
|
||||||
// plugin feature for test duration. One might think _ms means
|
|
||||||
// milliseconds, but Jenkins interprets this field in seconds.
|
|
||||||
duration_secs := time.Now().Sub(start).Seconds()
|
|
||||||
if res {
|
|
||||||
fmt.Printf("ok %v - %v\n", i+1, name)
|
|
||||||
if *tap {
|
|
||||||
fmt.Printf(" ---\n duration_ms: %.3f\n ...\n", duration_secs)
|
|
||||||
}
|
|
||||||
testResult.Pass++
|
|
||||||
} else {
|
|
||||||
fmt.Printf("not ok %v - %v\n", i+1, name)
|
|
||||||
if *tap {
|
|
||||||
fmt.Printf(" ---\n duration_ms: %.3f\n", duration_secs)
|
|
||||||
}
|
|
||||||
printBashOutputs(" ", " ", stdout, stderr, *tap)
|
|
||||||
if *tap {
|
|
||||||
fmt.Printf(" ...\n")
|
|
||||||
}
|
|
||||||
testResult.Fail++
|
|
||||||
}
|
|
||||||
results[name] = testResult
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func PrintResults(results ResultsByTest) bool {
|
|
||||||
failures := 0
|
|
||||||
|
|
||||||
passed := []string{}
|
|
||||||
flaky := []string{}
|
|
||||||
failed := []string{}
|
|
||||||
for test, result := range results {
|
|
||||||
if result.Pass > 0 && result.Fail == 0 {
|
|
||||||
passed = append(passed, test)
|
|
||||||
} else if result.Pass > 0 && result.Fail > 0 {
|
|
||||||
flaky = append(flaky, test)
|
|
||||||
failures += result.Fail
|
|
||||||
} else {
|
|
||||||
failed = append(failed, test)
|
|
||||||
failures += result.Fail
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(passed)
|
|
||||||
sort.Strings(flaky)
|
|
||||||
sort.Strings(failed)
|
|
||||||
printSubreport("Passed", passed, results)
|
|
||||||
printSubreport("Flaky", flaky, results)
|
|
||||||
printSubreport("Failed", failed, results)
|
|
||||||
if failures > 0 {
|
|
||||||
log.Printf("%v test(s) failed.", failures)
|
|
||||||
} else {
|
|
||||||
log.Printf("Success!")
|
|
||||||
}
|
|
||||||
|
|
||||||
return failures > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func printSubreport(title string, tests []string, results ResultsByTest) {
|
|
||||||
report := title + " tests:"
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
result := results[test]
|
|
||||||
report += fmt.Sprintf(" %v[%v/%v]", test, result.Pass, result.Pass+result.Fail)
|
|
||||||
}
|
|
||||||
log.Printf(report)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// All nonsense below is temporary until we have go versions of these things.
|
// All nonsense below is temporary until we have go versions of these things.
|
||||||
@ -451,10 +309,6 @@ func runBashUntil(stepName, bashFragment string) func() {
|
|||||||
cmd.Process.Signal(os.Interrupt)
|
cmd.Process.Signal(os.Interrupt)
|
||||||
headerprefix := stepName + " "
|
headerprefix := stepName + " "
|
||||||
lineprefix := " "
|
lineprefix := " "
|
||||||
if *tap {
|
|
||||||
headerprefix = "# " + headerprefix
|
|
||||||
lineprefix = "# " + lineprefix
|
|
||||||
}
|
|
||||||
printBashOutputs(headerprefix, lineprefix, string(stdout.Bytes()), string(stderr.Bytes()), false)
|
printBashOutputs(headerprefix, lineprefix, string(stdout.Bytes()), string(stderr.Bytes()), false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ set -o errexit
|
|||||||
set -o nounset
|
set -o nounset
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
||||||
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/../..
|
KUBE_ROOT=$(dirname "${BASH_SOURCE}")/..
|
||||||
|
|
||||||
: ${KUBE_VERSION_ROOT:=${KUBE_ROOT}}
|
: ${KUBE_VERSION_ROOT:=${KUBE_ROOT}}
|
||||||
: ${KUBECTL:="${KUBE_VERSION_ROOT}/cluster/kubectl.sh"}
|
: ${KUBECTL:="${KUBE_VERSION_ROOT}/cluster/kubectl.sh"}
|
||||||
@ -102,5 +102,6 @@ fi
|
|||||||
"${e2e}" "${auth_config[@]:+${auth_config[@]}}" \
|
"${e2e}" "${auth_config[@]:+${auth_config[@]}}" \
|
||||||
--host="https://${KUBE_MASTER_IP-}" \
|
--host="https://${KUBE_MASTER_IP-}" \
|
||||||
--provider="${KUBERNETES_PROVIDER}" \
|
--provider="${KUBERNETES_PROVIDER}" \
|
||||||
|
--ginkgo.v \
|
||||||
${E2E_REPORT_DIR+"--report_dir=${E2E_REPORT_DIR}"} \
|
${E2E_REPORT_DIR+"--report_dir=${E2E_REPORT_DIR}"} \
|
||||||
"${@}"
|
"${@}"
|
@ -77,11 +77,9 @@ if [[ ! -z ${E2E_SET_CLUSTER_API_VERSION:-} ]]; then
|
|||||||
export CLUSTER_API_VERSION=$(echo ${GITHASH} | cut -c 2-)
|
export CLUSTER_API_VERSION=$(echo ${GITHASH} | cut -c 2-)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Have cmd/e2e run by goe2e.sh generate JUnit report in ${WORKSPACE}/junit*.xml
|
export KUBE_CONFIG_FILE="config-test.sh"
|
||||||
export E2E_REPORT_DIR=${WORKSPACE}
|
cluster/kube-down.sh
|
||||||
|
cluster/kube-up.sh
|
||||||
go run ./hack/e2e.go ${E2E_OPT} -v --down
|
cluster/kubectl.sh version
|
||||||
go run ./hack/e2e.go ${E2E_OPT} -v --up
|
hack/ginkgo-e2e.sh --report_dir=${WORKSPACE}
|
||||||
go run ./hack/e2e.go -v --ctl="version --match-server-version=false"
|
cluster/kube-down.sh
|
||||||
go run ./hack/e2e.go ${E2E_OPT} --test --tap | tee ../e2e.${JOB_NAME}.${BUILD_NUMBER}.${GITHASH}.tap
|
|
||||||
go run ./hack/e2e.go ${E2E_OPT} -v --down
|
|
||||||
|
@ -55,6 +55,7 @@ readonly KUBE_TEST_PORTABLE=(
|
|||||||
contrib/for-tests/network-tester/service.json
|
contrib/for-tests/network-tester/service.json
|
||||||
hack/e2e.go
|
hack/e2e.go
|
||||||
hack/e2e-suite
|
hack/e2e-suite
|
||||||
|
hack/ginkgo-e2e.sh
|
||||||
)
|
)
|
||||||
|
|
||||||
# If we update this we need to also update the set of golang compilers we build
|
# If we update this we need to also update the set of golang compilers we build
|
||||||
|
71
test/e2e/shell.go
Normal file
71
test/e2e/shell.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package e2e
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
root = absOrDie(filepath.Clean(filepath.Join(path.Base(os.Args[0]), "..")))
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Shell", func() {
|
||||||
|
// Slurp up all the tests in hack/e2e-suite
|
||||||
|
bashE2ERoot := filepath.Join(root, "hack/e2e-suite")
|
||||||
|
files, err := ioutil.ReadDir(bashE2ERoot)
|
||||||
|
if err != nil {
|
||||||
|
Fail(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
fileName := file.Name() // Make a copy
|
||||||
|
It(fmt.Sprintf("tests that %v passes", fileName), func() {
|
||||||
|
runCmdTest(filepath.Join(bashE2ERoot, fileName))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
func absOrDie(path string) string {
|
||||||
|
out, err := filepath.Abs(path)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runs the given cmd test.
|
||||||
|
func runCmdTest(path string) {
|
||||||
|
By(fmt.Sprintf("Running %v", path))
|
||||||
|
cmd := exec.Command(path)
|
||||||
|
cmd.Stdout = bytes.NewBuffer(nil)
|
||||||
|
cmd.Stderr = cmd.Stdout
|
||||||
|
|
||||||
|
if err := cmd.Run(); err != nil {
|
||||||
|
Fail(fmt.Sprintf("Error running %v:\nCommand output:\n%v\n", cmd, cmd.Stdout))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user