Once again, use native Ginkgo test runner instead of cmd/e2e.

This commit deletes cmd/e2e and updates hack/ginkgo-e2e.sh to use the
'ginkgo' command instead. All logic from cmd/e2e/e2e.go and
test/e2e/driver.go have been combined into the new file
test/e2e/e2e_test.go.

The test tarball now includes a built version of the test/e2e test
binary, which includes all tests under test/e2e. This was accomplished
by updating the build scripts to use 'go test -c' when a target name
ended with '.test', and adding a dependency on test/e2e/e2e.test.

This prebuilt test binary is passed to the Ginkgo runner in
hack/ginkgo-e2e.sh. In a future change, we can add support to run
Ginkgo against the source tree if it is available.

This change is generally intended to have no externally visible changes,
aside from the following caveats:
 - The -t/--tests flag has been removed
 - Calling cmd/e2e/e2e directly obviously won't work, but that was never
   intended to be supported anyway
 - If the GINKGO_PARALLEL environment variable is set to y, then ginkgo
   will run test specs in parallel. (Currently defaults to n, since some
   tests are broken in this mode.)

Additionally, several tests which made poor assumptions about cwd or
used testContext before it had been set have been fixed.
This commit is contained in:
Jeff Grafton
2015-05-01 14:18:50 -07:00
parent 1ee33ac481
commit 86b023fdd6
9 changed files with 202 additions and 294 deletions

View File

@@ -1,98 +0,0 @@
/*
Copyright 2014 The Kubernetes Authors 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 (
"fmt"
"path"
"regexp"
"strings"
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/golang/glog"
"github.com/onsi/ginkgo"
"github.com/onsi/ginkgo/config"
"github.com/onsi/ginkgo/reporters"
"github.com/onsi/gomega"
)
type testResult bool
type CloudConfig struct {
ProjectID string
Zone string
MasterName string
Provider cloudprovider.Interface
}
func init() {
// Turn on verbose by default to get spec names
config.DefaultReporterConfig.Verbose = true
// Turn on EmitSpecProgress to get spec progress (especially on interrupt)
config.GinkgoConfig.EmitSpecProgress = true
// Randomize specs as well as suites
config.GinkgoConfig.RandomizeAllSpecs = true
}
func (t *testResult) Fail() { *t = false }
// Run each Go end-to-end-test. This function assumes the
// creation of a test cluster.
func RunE2ETests(context *TestContextType, orderseed int64, times int, reportDir string, testList []string) {
testContext = *context
util.ReallyCrash = true
util.InitLogs()
defer util.FlushLogs()
if len(testList) != 0 {
if config.GinkgoConfig.FocusString != "" || config.GinkgoConfig.SkipString != "" {
glog.Fatal("Either specify --test/-t or --ginkgo.focus/--ginkgo.skip but not both.")
}
var testRegexps []string
for _, t := range testList {
testRegexps = append(testRegexps, regexp.QuoteMeta(t))
}
config.GinkgoConfig.FocusString = `\b(` + strings.Join(testRegexps, "|") + `)\b`
}
// Disable density test unless it's explicitly requested.
if config.GinkgoConfig.FocusString == "" && config.GinkgoConfig.SkipString == "" {
config.GinkgoConfig.SkipString = "Skipped"
}
// TODO: Make orderseed work again.
var passed testResult = true
gomega.RegisterFailHandler(ginkgo.Fail)
// Run the existing tests with output to console + JUnit for Jenkins
for i := 0; i < times && passed; i++ {
var r []ginkgo.Reporter
if reportDir != "" {
r = append(r, reporters.NewJUnitReporter(path.Join(reportDir, fmt.Sprintf("junit_%d.xml", i+1))))
}
ginkgo.RunSpecsWithDefaultAndCustomReporters(&passed, fmt.Sprintf("Kubernetes e2e Suite run %d of %d", i+1, times), r)
}
if !passed {
glog.Fatalf("At least one test failed")
} else {
glog.Infof("All tests pass")
}
}

111
test/e2e/e2e_test.go Normal file
View File

@@ -0,0 +1,111 @@
/*
Copyright 2015 The Kubernetes Authors 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 (
"flag"
"fmt"
"os"
"path"
goruntime "runtime"
"strings"
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
"github.com/golang/glog"
"github.com/onsi/ginkgo"
"github.com/onsi/ginkgo/config"
"github.com/onsi/ginkgo/reporters"
"github.com/onsi/gomega"
)
var (
cloudConfig = &testContext.CloudConfig
reportDir = flag.String("report-dir", "", "Path to the directory where the JUnit XML reports should be saved. Default is empty, which doesn't generate these reports.")
)
func init() {
// Turn on verbose by default to get spec names
config.DefaultReporterConfig.Verbose = true
// Turn on EmitSpecProgress to get spec progress (especially on interrupt)
config.GinkgoConfig.EmitSpecProgress = true
// Randomize specs as well as suites
config.GinkgoConfig.RandomizeAllSpecs = true
flag.StringVar(&testContext.KubeConfig, clientcmd.RecommendedConfigPathFlag, "", "Path to kubeconfig containing embeded authinfo.")
flag.StringVar(&testContext.KubeContext, clientcmd.FlagContext, "", "kubeconfig context to use/override. If unset, will use value from 'current-context'")
flag.StringVar(&testContext.CertDir, "cert-dir", "", "Path to the directory containing the certs. Default is empty, which doesn't use certs.")
flag.StringVar(&testContext.Host, "host", "", "The host, or apiserver, to connect to")
flag.StringVar(&testContext.RepoRoot, "repo-root", "../../", "Root directory of kubernetes repository, for finding test files.")
flag.StringVar(&testContext.Provider, "provider", "", "The name of the Kubernetes provider (gce, gke, local, vagrant, etc.)")
// TODO: Flags per provider? Rename gce-project/gce-zone?
flag.StringVar(&cloudConfig.MasterName, "kube-master", "", "Name of the kubernetes master. Only required if provider is gce or gke")
flag.StringVar(&cloudConfig.ProjectID, "gce-project", "", "The GCE project being used, if applicable")
flag.StringVar(&cloudConfig.Zone, "gce-zone", "", "GCE zone being used, if applicable")
}
func TestE2E(t *testing.T) {
defer util.FlushLogs()
// Disable density test unless it's explicitly requested.
if config.GinkgoConfig.FocusString == "" && config.GinkgoConfig.SkipString == "" {
config.GinkgoConfig.SkipString = "Skipped"
}
gomega.RegisterFailHandler(ginkgo.Fail)
// Run tests through the Ginkgo runner with output to console + JUnit for Jenkins
var r []ginkgo.Reporter
if *reportDir != "" {
r = append(r, reporters.NewJUnitReporter(path.Join(*reportDir, fmt.Sprintf("junit_%02d.xml", config.GinkgoConfig.ParallelNode))))
}
ginkgo.RunSpecsWithDefaultAndCustomReporters(t, "Kubernetes e2e suite", r)
}
func TestMain(m *testing.M) {
flag.Parse()
util.ReallyCrash = true
util.InitLogs()
goruntime.GOMAXPROCS(goruntime.NumCPU())
// TODO: possibly clean up or refactor this functionality.
if testContext.Provider == "" {
glog.Info("The --provider flag is not set. Treating as a conformance test. Some tests may not be run.")
os.Exit(1)
}
if testContext.Provider == "aws" {
awsConfig := "[Global]\n"
if cloudConfig.Zone == "" {
glog.Fatal("gce-zone must be specified for AWS")
}
awsConfig += fmt.Sprintf("Zone=%s\n", cloudConfig.Zone)
var err error
cloudConfig.Provider, err = cloudprovider.GetCloudProvider(testContext.Provider, strings.NewReader(awsConfig))
if err != nil {
glog.Fatal("Error building AWS provider: ", err)
}
}
os.Exit(m.Run())
}

View File

@@ -45,6 +45,7 @@ const (
)
var _ = Describe("kubectl", func() {
defer GinkgoRecover()
var c *client.Client
var ns string
var testingNs *api.Namespace
@@ -65,11 +66,12 @@ var _ = Describe("kubectl", func() {
})
Describe("update-demo", func() {
var (
var updateDemoRoot, nautilusPath, kittenPath string
BeforeEach(func() {
updateDemoRoot = filepath.Join(testContext.RepoRoot, "examples/update-demo")
nautilusPath = filepath.Join(updateDemoRoot, "nautilus-rc.yaml")
kittenPath = filepath.Join(updateDemoRoot, "kitten-rc.yaml")
)
nautilusPath = filepath.Join(updateDemoRoot, "nautilus-rc.yaml")
kittenPath = filepath.Join(updateDemoRoot, "kitten-rc.yaml")
})
It("should create and stop a replication controller", func() {
defer cleanup(nautilusPath, ns, updateDemoSelector)
@@ -105,7 +107,10 @@ var _ = Describe("kubectl", func() {
})
Describe("guestbook", func() {
var guestbookPath = filepath.Join(testContext.RepoRoot, "examples/guestbook")
var guestbookPath string
BeforeEach(func() {
guestbookPath = filepath.Join(testContext.RepoRoot, "examples/guestbook")
})
It("should create and stop a working application", func() {
if !providerIs("gce", "gke") {

View File

@@ -19,7 +19,6 @@ package e2e
import (
"bytes"
"fmt"
"io/ioutil"
"os/exec"
"path/filepath"
@@ -27,36 +26,19 @@ import (
)
var _ = Describe("Shell", func() {
bashE2ERoot := filepath.Join(testContext.RepoRoot, "hack/e2e-suite")
defer GinkgoRecover()
// Slurp up all the tests in hack/e2e-suite
files, err := ioutil.ReadDir(bashE2ERoot)
if err != nil {
Fail(fmt.Sprintf("Error reading test suites from %v %v", bashE2ERoot, err.Error()))
}
for _, file := range files {
fileName := file.Name() // Make a copy
It(fmt.Sprintf("tests that %v passes", fileName), func() {
// A number of scripts only work on gce
if !providerIs("gce", "gke") {
By(fmt.Sprintf("Skipping Shell test %s, which is only supported for provider gce and gke (not %s)",
fileName, testContext.Provider))
return
}
runCmdTest(filepath.Join(bashE2ERoot, fileName))
})
}
It(fmt.Sprintf("tests that services.sh passes"), func() {
// The services script only works on gce/gke
if !providerIs("gce", "gke") {
By(fmt.Sprintf("Skipping Shell test services.sh, which is only supported for provider gce and gke (not %s)",
testContext.Provider))
return
}
runCmdTest(filepath.Join(testContext.RepoRoot, "hack/e2e-suite/services.sh"))
})
})
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))

View File

@@ -34,6 +34,7 @@ import (
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client"
"github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd"
"github.com/GoogleCloudPlatform/kubernetes/pkg/cloudprovider"
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
"github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl"
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
@@ -54,6 +55,14 @@ const (
nonExist = "NonExist"
)
type CloudConfig struct {
ProjectID string
Zone string
MasterName string
Provider cloudprovider.Interface
}
type TestContextType struct {
KubeConfig string
KubeContext string
@@ -294,7 +303,7 @@ func validateController(c *client.Client, containerImage string, replicas int, c
Failf("Timed out after %v seconds waiting for %s pods to reach valid state", podStartTimeout.Seconds(), testname)
}
// kubectlCmd runs the kubectl executable.
// kubectlCmd runs the kubectl executable through the wrapper script.
func kubectlCmd(args ...string) *exec.Cmd {
defaultArgs := []string{}
@@ -321,7 +330,7 @@ func kubectlCmd(args ...string) *exec.Cmd {
kubectlArgs := append(defaultArgs, args...)
//TODO: the "kubectl" path string might be worth externalizing into an (optional) ginko arg.
cmd := exec.Command("kubectl", kubectlArgs...)
cmd := exec.Command(filepath.Join(testContext.RepoRoot, "cluster/kubectl.sh"), kubectlArgs...)
Logf("Running '%s %s'", cmd.Path, strings.Join(cmd.Args, " "))
return cmd
}