Skip to content

Commit

Permalink
Rent Boskos project only once per test run.
Browse files Browse the repository at this point in the history
The old implementation rents Boskos project for each Ginkgo node.
  • Loading branch information
Xuewei Zhang committed Jan 3, 2020
1 parent 0d0bba9 commit 4db575d
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 36 deletions.
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -125,7 +125,7 @@ test: vet fmt
GO111MODULE=on go test -mod vendor -timeout=1m -v -race -short -tags "$(BUILD_TAGS)" ./...

e2e-test: vet fmt build-tar
GO111MODULE=on ginkgo -nodes=$(PARALLEL) -mod vendor -timeout=10m -v -tags "$(BUILD_TAGS)" \
GO111MODULE=on ginkgo -nodes=$(PARALLEL) -mod vendor -timeout=10m -v -tags "$(BUILD_TAGS)" -stream \
./test/e2e/metriconly/... -- \
-project=$(PROJECT) -zone=$(ZONE) \
-image=$(VM_IMAGE) -image-family=$(IMAGE_FAMILY) -image-project=$(IMAGE_PROJECT) \
Expand Down
99 changes: 64 additions & 35 deletions test/e2e/metriconly/e2e_npd_test.go
Expand Up @@ -53,65 +53,94 @@ var boskosWaitDuration = flag.Duration("boskos-wait-duration", 2*time.Minute,
"Duration to wait before quitting getting Boskos resource.")

var computeService *compute.Service

func TestNPD(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
// boskosClient helps renting project from Boskos, and is only initialized on Ginkgo node 1.
var boskosClient *client.Client

// rentBoskosProjectIfNeededOnNode1 rents a GCP project from Boskos if no GCP project is specified.
//
// rentBoskosProjectIfNeededOnNode1 returns a byte slice containing the project name.
// rentBoskosProjectIfNeededOnNode1 also initializes boskosClient if necessary.
// When the tests run in parallel mode in Ginkgo, this rentBoskosProjectIfNeededOnNode1 runs only on
// Ginkgo node 1. The output should be shared with all other Gingko nodes so that they all use the same
// GCP project.
func rentBoskosProjectIfNeededOnNode1() []byte {
if *project != "" {
return []byte{}
}

var err error
computeService, err = gce.GetComputeClient()
if err != nil {
panic(fmt.Sprintf("Unable to create gcloud compute service using defaults. Make sure you are authenticated. %v", err))
}

if *project == "" {
boskosClient := client.NewClient(*jobName, *boskosServerURL)
*project = acquireProjectOrDie(boskosClient)

defer releaseProjectOrDie(boskosClient)
}

if *artifactsDir != "" {
_, err := os.Stat(*artifactsDir)
if err != nil && os.IsNotExist(err) {
os.MkdirAll(*artifactsDir, os.ModeDir|0755)
}
}

// The junit formatted result output is for showing test results on testgrid.
junitReporter := reporters.NewJUnitReporter(path.Join(*artifactsDir, fmt.Sprintf("junit-%02d.xml", config.GinkgoConfig.ParallelNode)))
ginkgo.RunSpecsWithDefaultAndCustomReporters(t, "NPD Metric-only Suite", []ginkgo.Reporter{junitReporter})
}

func acquireProjectOrDie(boskosClient *client.Client) string {
fmt.Printf("Renting project from Boskos\n")
boskosClient = client.NewClient(*jobName, *boskosServerURL)
ctx, cancel := context.WithTimeout(context.Background(), *boskosWaitDuration)
defer cancel()
p, err := boskosClient.AcquireWait(ctx, *boskosProjectType, "free", "busy")
Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("Unable to rent project from Boskos: %v\n", err))

fmt.Printf("Rented project %s from Boskos", p.Name)
fmt.Printf("Rented project %q from Boskos\n", p.Name)

go func(boskosClient *client.Client, projectName string) {
for range time.Tick(5 * time.Minute) {
fmt.Printf("Renewing boskosProject %q\n", projectName)
if err := boskosClient.UpdateOne(projectName, "busy", nil); err != nil {
fmt.Printf("Failed to update status for project %s with Boskos: %v\n", projectName, err)
fmt.Printf("Failed to update status for project %q with Boskos: %v\n", projectName, err)
}
}
}(boskosClient, p.Name)

return p.Name
return []byte(p.Name)
}

func releaseProjectOrDie(boskosClient *client.Client) {
// acceptBoskosProjectIfNeededFromNode1 accepts a GCP project rented from Boskos by Ginkgo node 1.
//
// acceptBoskosProjectIfNeededFromNode1 takes the output of rentBoskosProjectIfNeededOnNode1.
// When the tests run in parallel mode in Ginkgo, this function runs on all Ginkgo nodes.
func acceptBoskosProjectIfNeededFromNode1(data []byte) {
if *project != "" {
return
}

boskosProject := string(data)
fmt.Printf("Received Boskos project %q from Ginkgo node 1.\n", boskosProject)
*project = boskosProject
}

// releaseBoskosResourcesOnNode1 releases all rented Boskos resources if there is any.
func releaseBoskosResourcesOnNode1() {
if boskosClient == nil {
return
}
if !boskosClient.HasResource() {
return
}
fmt.Printf("Releasing all Boskos resources.\n")
err := boskosClient.ReleaseAll("dirty")
Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("Failed to release project to Boskos: %v", err))
}

var _ = ginkgo.SynchronizedBeforeSuite(rentBoskosProjectIfNeededOnNode1, acceptBoskosProjectIfNeededFromNode1)
var _ = ginkgo.SynchronizedAfterSuite(func() {}, releaseBoskosResourcesOnNode1)

func TestNPD(t *testing.T) {
if testing.Short() {
t.Skip("skipping test in short mode.")
}

var err error
computeService, err = gce.GetComputeClient()
if err != nil {
panic(fmt.Sprintf("Unable to create gcloud compute service using defaults. Make sure you are authenticated. %v", err))
}

if *artifactsDir != "" {
_, err := os.Stat(*artifactsDir)
if err != nil && os.IsNotExist(err) {
os.MkdirAll(*artifactsDir, os.ModeDir|0755)
}
}

// The junit formatted result output is for showing test results on testgrid.
junitReporter := reporters.NewJUnitReporter(path.Join(*artifactsDir, fmt.Sprintf("junit-%02d.xml", config.GinkgoConfig.ParallelNode)))
ginkgo.RunSpecsWithDefaultAndCustomReporters(t, "NPD Metric-only Suite", []ginkgo.Reporter{junitReporter})
}

func TestMain(m *testing.M) {
RegisterFailHandler(ginkgo.Fail)
flag.Parse()
Expand Down

0 comments on commit 4db575d

Please sign in to comment.