blob: 7399c967fd8da8415c8b80fba1a4f2c172b867ce [file] [log] [blame]
// Copyright Istio Authors
//
// 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 integration
import (
"fmt"
"sync"
"testing"
"time"
)
import (
"go.uber.org/atomic"
)
import (
"github.com/apache/dubbo-go-pixiu/pkg/test/framework"
)
func TestParallel(t *testing.T) {
var top, l1a, l1b, l2a, l2b, l2c, l2d *component
closeTimes := make(map[string]time.Time)
mutex := &sync.Mutex{}
closeHandler := func(c *component) {
mutex.Lock()
defer mutex.Unlock()
closeTimes[c.name] = time.Now()
// Sleep briefly to force time separation between close events.
time.Sleep(100 * time.Millisecond)
}
assertClosedBefore := func(t *testing.T, c1, c2 *component) {
t.Helper()
if !closeTimes[c1.name].Before(closeTimes[c2.name]) {
t.Fatalf("%s closed after %s", c1.name, c2.name)
}
}
framework.NewTest(t).
Run(func(ctx framework.TestContext) {
ctx.NewSubTest("top").
Run(func(ctx framework.TestContext) {
// NOTE: top can't be parallel for this test since it will exit before the children run,
// which means we won't be able to verify the results here.
top = newComponent(ctx, ctx.Name(), closeHandler)
ctx.NewSubTest("l1a").
RunParallel(func(ctx framework.TestContext) {
l1a = newComponent(ctx, ctx.Name(), closeHandler)
ctx.NewSubTest("l2a").
RunParallel(func(ctx framework.TestContext) {
l2a = newComponent(ctx, ctx.Name(), closeHandler)
})
ctx.NewSubTest("l2b").
RunParallel(func(ctx framework.TestContext) {
l2b = newComponent(ctx, ctx.Name(), closeHandler)
})
})
ctx.NewSubTest("l1b").
RunParallel(func(ctx framework.TestContext) {
l1b = newComponent(ctx, ctx.Name(), closeHandler)
ctx.NewSubTest("l2c").
RunParallel(func(ctx framework.TestContext) {
l2c = newComponent(ctx, ctx.Name(), closeHandler)
})
ctx.NewSubTest("l2d").
RunParallel(func(ctx framework.TestContext) {
l2d = newComponent(ctx, ctx.Name(), closeHandler)
})
})
})
})
assertClosedBefore(t, l2a, l1a)
assertClosedBefore(t, l2b, l1a)
assertClosedBefore(t, l2c, l1b)
assertClosedBefore(t, l2d, l1b)
assertClosedBefore(t, l1a, top)
assertClosedBefore(t, l1b, top)
}
// Validate that cleanup is done synchronously for asynchronous tests
func TestParallelWhenDone(t *testing.T) {
errors := make(chan error, 10)
framework.NewTest(t).Features("infrastructure.framework").
Run(func(ctx framework.TestContext) {
runCheck(ctx, errors, "root")
ctx.NewSubTest("nested-serial").Run(func(ctx framework.TestContext) {
runCheck(ctx, errors, "nested-serial")
})
ctx.NewSubTest("nested-parallel").RunParallel(func(ctx framework.TestContext) {
runCheck(ctx, errors, "nested-parallel")
})
})
for {
select {
case e := <-errors:
t.Error(e)
default:
return
}
}
}
func runCheck(ctx framework.TestContext, errors chan error, name string) {
currentTest := atomic.NewString("")
for _, c := range []string{"a", "b", "c"} {
c := c
ctx.NewSubTest(c).Run(func(ctx framework.TestContext) {
// Store the test name. We will check this in ConditionalCleanup to ensure we call finish cleanup before the next test runs
currentTest.Store(c)
ctx.ConditionalCleanup(func() {
time.Sleep(time.Millisecond * 100)
if ct := currentTest.Load(); ct != c {
errors <- fmt.Errorf("expected current test for %s to be %s but was %s", name, c, ct)
}
})
for _, st := range []string{"p1", "p2"} {
ctx.NewSubTest(st).
RunParallel(func(ctx framework.TestContext) {})
}
})
}
}