From d4483c3f377394ab7dade6b5d33bd3f21a3cfbce Mon Sep 17 00:00:00 2001 From: husharp Date: Fri, 28 Jun 2024 08:03:35 +0800 Subject: [PATCH] accelarate build Signed-off-by: husharp --- .github/workflows/pd-tests.yaml | 23 ++- .gitignore | 1 + Makefile | 2 +- pkg/core/region_test.go | 2 +- scripts/ci-subtask.sh | 35 +++-- server/api/region_test.go | 2 +- tests/integrations/client/client_test.go | 2 +- .../mcs/tso/keyspace_group_manager_test.go | 2 +- tests/integrations/mcs/tso/server_test.go | 72 +++++---- tests/integrations/tso/client_test.go | 4 +- tests/integrations/tso/consistency_test.go | 4 +- tests/server/api/scheduler_test.go | 16 +- tests/testutil.go | 50 +++--- tools/pd-ut/ut.go | 145 ++++++++++++------ 14 files changed, 233 insertions(+), 127 deletions(-) diff --git a/.github/workflows/pd-tests.yaml b/.github/workflows/pd-tests.yaml index 223187737e0d..928ef9d26631 100644 --- a/.github/workflows/pd-tests.yaml +++ b/.github/workflows/pd-tests.yaml @@ -27,19 +27,25 @@ jobs: matrix: include: - worker_id: 1 - name: 'Unit Test(1)' + name: 'Unit Test(core)' - worker_id: 2 - name: 'Unit Test(2)' + name: 'Unit Test(others)' - worker_id: 3 - name: 'Tools Test' + name: 'Tests(core)' - worker_id: 4 - name: 'Client Integration Test' + name: 'Tests(others)' - worker_id: 5 - name: 'TSO Integration Test' + name: 'Tools Test' - worker_id: 6 - name: 'MicroService Integration Test' + name: 'Client Integration Test' + - worker_id: 7 + name: 'TSO Integration Test' + - worker_id: 8 + name: 'MicroService Integration(Core)' + - worker_id: 9 + name: 'MicroService Integration(TSO)' outputs: - job-total: 6 + job-total: 9 steps: - name: Checkout code uses: actions/checkout@v4 @@ -52,6 +58,9 @@ jobs: run: | make ci-test-job JOB_INDEX=$WORKER_ID mv covprofile covprofile_$WORKER_ID + if [ -f junitfile ]; then + cat junitfile + fi - name: Upload coverage result ${{ matrix.worker_id }} uses: actions/upload-artifact@v4 with: diff --git a/.gitignore b/.gitignore index fb9f0424418f..dc2efa5004f8 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ docs/swagger/* *.before covprofile coverage.tmp +junitfile package.list report.xml coverage.xml diff --git a/Makefile b/Makefile index 5f5ac871f18b..25628a13736c 100644 --- a/Makefile +++ b/Makefile @@ -228,7 +228,7 @@ failpoint-disable: install-tools ut: pd-ut @$(FAILPOINT_ENABLE) # only run unit tests - ./bin/pd-ut run --ignore tests --race + ./bin/pd-ut run --ignore tests --race --junitfile ./junitfile @$(CLEAN_UT_BINARY) @$(FAILPOINT_DISABLE) diff --git a/pkg/core/region_test.go b/pkg/core/region_test.go index ce59c0075d09..816bba4efaed 100644 --- a/pkg/core/region_test.go +++ b/pkg/core/region_test.go @@ -731,7 +731,7 @@ func BenchmarkRandomSetRegion(b *testing.B) { func TestGetRegionSizeByRange(t *testing.T) { regions := NewRegionsInfo() - nums := 1000010 + nums := 100001 for i := 0; i < nums; i++ { peer := &metapb.Peer{StoreId: 1, Id: uint64(i + 1)} endKey := []byte(fmt.Sprintf("%20d", i+1)) diff --git a/scripts/ci-subtask.sh b/scripts/ci-subtask.sh index 9bdce420d4a7..16f491ef0cc5 100755 --- a/scripts/ci-subtask.sh +++ b/scripts/ci-subtask.sh @@ -3,34 +3,47 @@ # ./ci-subtask.sh ROOT_PATH_COV=$(pwd)/covprofile +ROOT_PATH_JUNITFILE=$(pwd)/junitfile # Currently, we only have 3 integration tests, so we can hardcode the task index. integrations_dir=$(pwd)/tests/integrations case $1 in 1) - # unit tests ignore `tests` - ./bin/pd-ut run --race --ignore tests --coverprofile $ROOT_PATH_COV || exit 1 + # unit tests ignore `tests`, `server`, `schedule` and `encryption` + ./bin/pd-ut run --ignore tests,server,pkg/schedule,pkg/encryption --race --coverprofile $ROOT_PATH_COV --junitfile $ROOT_PATH_JUNITFILE || exit 1 ;; 2) - # unit tests only in `tests` - ./bin/pd-ut run tests --race --coverprofile $ROOT_PATH_COV || exit 1 + # unit tests only in `server`, `schedule` and `encryption` without `tests` + ./bin/pd-ut run server,schedule,encryption --ignore tests --race --coverprofile $ROOT_PATH_COV --junitfile $ROOT_PATH_JUNITFILE || exit 1 ;; 3) + # tests only in `tests` without `server/api, server/cluster and `server/config` + ./bin/pd-ut run tests --ignore tests/server/api,tests/server/cluster,tests/server/config --race --coverprofile $ROOT_PATH_COV --junitfile $ROOT_PATH_JUNITFILE || exit 1 + ;; + 4) + # tests only in `server/api, server/cluster and `server/config` in `tests` + ./bin/pd-ut run tests/server/api,tests/server/cluster,tests/server/config --race --coverprofile $ROOT_PATH_COV --junitfile $ROOT_PATH_JUNITFILE || exit 1 + ;; + 5) # tools tests cd ./tools && make ci-test-job && cat covprofile >> $ROOT_PATH_COV || exit 1 ;; - 4) + 6) # integration test client - ./bin/pd-ut it run client --race --coverprofile $ROOT_PATH_COV || exit 1 + ./bin/pd-ut it run client --race --coverprofile $ROOT_PATH_COV --junitfile $ROOT_PATH_JUNITFILE || exit 1 # client tests cd ./client && make ci-test-job && cat covprofile >> $ROOT_PATH_COV || exit 1 ;; - 5) + 7) # integration test tso - ./bin/pd-ut it run tso --race --coverprofile $ROOT_PATH_COV || exit 1 + ./bin/pd-ut it run tso --race --ignore mcs/tso --coverprofile $ROOT_PATH_COV --junitfile $ROOT_PATH_JUNITFILE || exit 1 ;; - 6) - # integration test mcs - ./bin/pd-ut it run mcs --race --coverprofile $ROOT_PATH_COV || exit 1 + 8) + # integration test mcs without mcs/tso + ./bin/pd-ut it run mcs --race --ignore mcs/tso --coverprofile $ROOT_PATH_COV --junitfile $ROOT_PATH_JUNITFILE || exit 1 + ;; + 9) + # integration test mcs/tso + ./bin/pd-ut it run mcs/tso --race --coverprofile $ROOT_PATH_COV --junitfile $ROOT_PATH_JUNITFILE || exit 1 ;; esac diff --git a/server/api/region_test.go b/server/api/region_test.go index 886322321751..fb32496c16a1 100644 --- a/server/api/region_test.go +++ b/server/api/region_test.go @@ -333,7 +333,7 @@ func TestRegionsWithKillRequest(t *testing.T) { url := fmt.Sprintf("%s%s/api/v1/regions", addr, apiPrefix) mustBootstrapCluster(re, svr) - regionCount := 100000 + regionCount := 10000 tu.GenerateTestDataConcurrently(regionCount, func(i int) { r := core.NewTestRegionInfo(uint64(i+2), 1, []byte(fmt.Sprintf("%09d", i)), diff --git a/tests/integrations/client/client_test.go b/tests/integrations/client/client_test.go index e2d34f2c96fa..07824c5483a8 100644 --- a/tests/integrations/client/client_test.go +++ b/tests/integrations/client/client_test.go @@ -217,7 +217,7 @@ func TestLeaderTransferAndMoveCluster(t *testing.T) { }() // Transfer leader. - for i := 0; i < 5; i++ { + for i := 0; i < 3; i++ { oldLeaderName := cluster.WaitLeader() err := cluster.GetServer(oldLeaderName).ResignLeader() re.NoError(err) diff --git a/tests/integrations/mcs/tso/keyspace_group_manager_test.go b/tests/integrations/mcs/tso/keyspace_group_manager_test.go index 6d861962d9b6..31aa5ee704ed 100644 --- a/tests/integrations/mcs/tso/keyspace_group_manager_test.go +++ b/tests/integrations/mcs/tso/keyspace_group_manager_test.go @@ -67,7 +67,7 @@ func (suite *tsoKeyspaceGroupManagerTestSuite) allocID() uint32 { return uint32(id) } -func TestTSOKeyspaceGroupManager(t *testing.T) { +func TestTSOKeyspaceGroupManagerSuite(t *testing.T) { suite.Run(t, &tsoKeyspaceGroupManagerTestSuite{}) } diff --git a/tests/integrations/mcs/tso/server_test.go b/tests/integrations/mcs/tso/server_test.go index 260395e42096..29d396b3d2ea 100644 --- a/tests/integrations/mcs/tso/server_test.go +++ b/tests/integrations/mcs/tso/server_test.go @@ -260,8 +260,8 @@ func TestWaitAPIServiceReady(t *testing.T) { } } -type APIServerForwardTestSuite struct { - suite.Suite +type APIServerForward struct { + re *require.Assertions ctx context.Context cancel context.CancelFunc cluster *tests.TestCluster @@ -270,13 +270,11 @@ type APIServerForwardTestSuite struct { pdClient pd.Client } -func TestAPIServerForwardTestSuite(t *testing.T) { - suite.Run(t, new(APIServerForwardTestSuite)) -} - -func (suite *APIServerForwardTestSuite) SetupTest() { +func NewAPIServerForward(re *require.Assertions) APIServerForward { + suite := APIServerForward{ + re: re, + } var err error - re := suite.Require() suite.ctx, suite.cancel = context.WithCancel(context.Background()) suite.cluster, err = tests.NewTestAPICluster(suite.ctx, 3) re.NoError(err) @@ -294,11 +292,12 @@ func (suite *APIServerForwardTestSuite) SetupTest() { suite.pdClient, err = pd.NewClientWithContext(context.Background(), []string{suite.backendEndpoints}, pd.SecurityOption{}, pd.WithMaxErrorRetry(1)) re.NoError(err) + return suite } -func (suite *APIServerForwardTestSuite) TearDownTest() { - re := suite.Require() +func (suite *APIServerForward) ShutDown() { suite.pdClient.Close() + re := suite.re etcdClient := suite.pdLeader.GetEtcdClient() clusterID := strconv.FormatUint(suite.pdLeader.GetClusterID(), 10) @@ -314,8 +313,10 @@ func (suite *APIServerForwardTestSuite) TearDownTest() { re.NoError(failpoint.Disable("github.com/tikv/pd/client/usePDServiceMode")) } -func (suite *APIServerForwardTestSuite) TestForwardTSORelated() { - re := suite.Require() +func TestForwardTSORelated(t *testing.T) { + re := require.New(t) + suite := NewAPIServerForward(re) + defer suite.ShutDown() // Unable to use the tso-related interface without tso server suite.checkUnavailableTSO(re) tc, err := tests.NewTestTSOCluster(suite.ctx, 1, suite.backendEndpoints) @@ -325,8 +326,10 @@ func (suite *APIServerForwardTestSuite) TestForwardTSORelated() { suite.checkAvailableTSO(re) } -func (suite *APIServerForwardTestSuite) TestForwardTSOWhenPrimaryChanged() { - re := suite.Require() +func TestForwardTSOWhenPrimaryChanged(t *testing.T) { + re := require.New(t) + suite := NewAPIServerForward(re) + defer suite.ShutDown() tc, err := tests.NewTestTSOCluster(suite.ctx, 2, suite.backendEndpoints) re.NoError(err) @@ -363,10 +366,11 @@ func (suite *APIServerForwardTestSuite) TestForwardTSOWhenPrimaryChanged() { suite.checkAvailableTSO(re) } -func (suite *APIServerForwardTestSuite) TestResignTSOPrimaryForward() { +func TestResignTSOPrimaryForward(t *testing.T) { + re := require.New(t) + suite := NewAPIServerForward(re) + defer suite.ShutDown() // TODO: test random kill primary with 3 nodes - re := suite.Require() - tc, err := tests.NewTestTSOCluster(suite.ctx, 2, suite.backendEndpoints) re.NoError(err) defer tc.Destroy() @@ -388,8 +392,10 @@ func (suite *APIServerForwardTestSuite) TestResignTSOPrimaryForward() { } } -func (suite *APIServerForwardTestSuite) TestResignAPIPrimaryForward() { - re := suite.Require() +func TestResignAPIPrimaryForward(t *testing.T) { + re := require.New(t) + suite := NewAPIServerForward(re) + defer suite.ShutDown() tc, err := tests.NewTestTSOCluster(suite.ctx, 2, suite.backendEndpoints) re.NoError(err) @@ -410,8 +416,10 @@ func (suite *APIServerForwardTestSuite) TestResignAPIPrimaryForward() { } } -func (suite *APIServerForwardTestSuite) TestForwardTSOUnexpectedToFollower1() { - re := suite.Require() +func TestForwardTSOUnexpectedToFollower1(t *testing.T) { + re := require.New(t) + suite := NewAPIServerForward(re) + defer suite.ShutDown() suite.checkForwardTSOUnexpectedToFollower(func() { // unary call will retry internally // try to update gc safe point @@ -421,8 +429,10 @@ func (suite *APIServerForwardTestSuite) TestForwardTSOUnexpectedToFollower1() { }) } -func (suite *APIServerForwardTestSuite) TestForwardTSOUnexpectedToFollower2() { - re := suite.Require() +func TestForwardTSOUnexpectedToFollower2(t *testing.T) { + re := require.New(t) + suite := NewAPIServerForward(re) + defer suite.ShutDown() suite.checkForwardTSOUnexpectedToFollower(func() { // unary call will retry internally // try to set external ts @@ -433,16 +443,18 @@ func (suite *APIServerForwardTestSuite) TestForwardTSOUnexpectedToFollower2() { }) } -func (suite *APIServerForwardTestSuite) TestForwardTSOUnexpectedToFollower3() { - re := suite.Require() +func TestForwardTSOUnexpectedToFollower3(t *testing.T) { + re := require.New(t) + suite := NewAPIServerForward(re) + defer suite.ShutDown() suite.checkForwardTSOUnexpectedToFollower(func() { _, _, err := suite.pdClient.GetTS(suite.ctx) re.Error(err) }) } -func (suite *APIServerForwardTestSuite) checkForwardTSOUnexpectedToFollower(checkTSO func()) { - re := suite.Require() +func (suite *APIServerForward) checkForwardTSOUnexpectedToFollower(checkTSO func()) { + re := suite.re tc, err := tests.NewTestTSOCluster(suite.ctx, 2, suite.backendEndpoints) re.NoError(err) tc.WaitForDefaultPrimaryServing(re) @@ -477,7 +489,7 @@ func (suite *APIServerForwardTestSuite) checkForwardTSOUnexpectedToFollower(chec tc.Destroy() } -func (suite *APIServerForwardTestSuite) addRegions() { +func (suite *APIServerForward) addRegions() { leader := suite.cluster.GetServer(suite.cluster.WaitLeader()) rc := leader.GetServer().GetRaftCluster() for i := 0; i < 3; i++ { @@ -491,7 +503,7 @@ func (suite *APIServerForwardTestSuite) addRegions() { } } -func (suite *APIServerForwardTestSuite) checkUnavailableTSO(re *require.Assertions) { +func (suite *APIServerForward) checkUnavailableTSO(re *require.Assertions) { _, _, err := suite.pdClient.GetTS(suite.ctx) re.Error(err) // try to update gc safe point @@ -502,7 +514,7 @@ func (suite *APIServerForwardTestSuite) checkUnavailableTSO(re *require.Assertio re.Error(err) } -func (suite *APIServerForwardTestSuite) checkAvailableTSO(re *require.Assertions) { +func (suite *APIServerForward) checkAvailableTSO(re *require.Assertions) { mcs.WaitForTSOServiceAvailable(suite.ctx, re, suite.pdClient) // try to get ts _, _, err := suite.pdClient.GetTS(suite.ctx) diff --git a/tests/integrations/tso/client_test.go b/tests/integrations/tso/client_test.go index d4f484087cfe..f229c4782bbe 100644 --- a/tests/integrations/tso/client_test.go +++ b/tests/integrations/tso/client_test.go @@ -71,13 +71,13 @@ func (suite *tsoClientTestSuite) getBackendEndpoints() []string { return strings.Split(suite.backendEndpoints, ",") } -func TestLegacyTSOClient(t *testing.T) { +func TestLegacyTSOClientSuite(t *testing.T) { suite.Run(t, &tsoClientTestSuite{ legacy: true, }) } -func TestMicroserviceTSOClient(t *testing.T) { +func TestMicroserviceTSOClientSuite(t *testing.T) { suite.Run(t, &tsoClientTestSuite{ legacy: false, }) diff --git a/tests/integrations/tso/consistency_test.go b/tests/integrations/tso/consistency_test.go index 4d05c47225a3..37c1441bc805 100644 --- a/tests/integrations/tso/consistency_test.go +++ b/tests/integrations/tso/consistency_test.go @@ -53,13 +53,13 @@ type tsoConsistencyTestSuite struct { tsoClient tsopb.TSOClient } -func TestLegacyTSOConsistency(t *testing.T) { +func TestLegacyTSOConsistencySuite(t *testing.T) { suite.Run(t, &tsoConsistencyTestSuite{ legacy: true, }) } -func TestMicroserviceTSOConsistency(t *testing.T) { +func TestMicroserviceTSOConsistencySuite(t *testing.T) { suite.Run(t, &tsoConsistencyTestSuite{ legacy: false, }) diff --git a/tests/server/api/scheduler_test.go b/tests/server/api/scheduler_test.go index 10631dab158a..3c108706fcdd 100644 --- a/tests/server/api/scheduler_test.go +++ b/tests/server/api/scheduler_test.go @@ -40,11 +40,20 @@ const apiPrefix = "/pd" type scheduleTestSuite struct { suite.Suite - env *tests.SchedulingTestEnvironment + env *tests.SchedulingTestEnvironment + runMode tests.SchedulerMode } -func TestScheduleTestSuite(t *testing.T) { - suite.Run(t, new(scheduleTestSuite)) +func TestPDSchedulingTestSuite(t *testing.T) { + suite.Run(t, &scheduleTestSuite{ + runMode: tests.PDMode, + }) +} + +func TestAPISchedulingTestSuite(t *testing.T) { + suite.Run(t, &scheduleTestSuite{ + runMode: tests.APIMode, + }) } func (suite *scheduleTestSuite) SetupSuite() { @@ -52,6 +61,7 @@ func (suite *scheduleTestSuite) SetupSuite() { re.NoError(failpoint.Enable("github.com/tikv/pd/pkg/schedule/changeCoordinatorTicker", `return(true)`)) re.NoError(failpoint.Enable("github.com/tikv/pd/server/cluster/skipStoreConfigSync", `return(true)`)) suite.env = tests.NewSchedulingTestEnvironment(suite.T()) + suite.env.RunMode = suite.runMode } func (suite *scheduleTestSuite) TearDownSuite() { diff --git a/tests/testutil.go b/tests/testutil.go index ea52bce310ed..4d5c0573b725 100644 --- a/tests/testutil.go +++ b/tests/testutil.go @@ -283,19 +283,21 @@ func MustReportBuckets(re *require.Assertions, cluster *TestCluster, regionID ui return buckets } -type mode int +type SchedulerMode int const ( - pdMode mode = iota - apiMode + Both SchedulerMode = iota + PDMode + APIMode ) // SchedulingTestEnvironment is used for test purpose. type SchedulingTestEnvironment struct { t *testing.T opts []ConfigOption - clusters map[mode]*TestCluster + clusters map[SchedulerMode]*TestCluster cancels []context.CancelFunc + RunMode SchedulerMode } // NewSchedulingTestEnvironment is to create a new SchedulingTestEnvironment. @@ -303,24 +305,30 @@ func NewSchedulingTestEnvironment(t *testing.T, opts ...ConfigOption) *Schedulin return &SchedulingTestEnvironment{ t: t, opts: opts, - clusters: make(map[mode]*TestCluster), + clusters: make(map[SchedulerMode]*TestCluster), cancels: make([]context.CancelFunc, 0), } } -// RunTestInTwoModes is to run test in two modes. func (s *SchedulingTestEnvironment) RunTestInTwoModes(test func(*TestCluster)) { - s.RunTestInPDMode(test) - s.RunTestInAPIMode(test) + switch s.RunMode { + case PDMode: + s.RunTestInPDMode(test) + case APIMode: + s.RunTestInAPIMode(test) + default: + s.RunTestInPDMode(test) + s.RunTestInAPIMode(test) + } } // RunTestInPDMode is to run test in pd mode. func (s *SchedulingTestEnvironment) RunTestInPDMode(test func(*TestCluster)) { s.t.Logf("start test %s in pd mode", getTestName()) - if _, ok := s.clusters[pdMode]; !ok { - s.startCluster(pdMode) + if _, ok := s.clusters[PDMode]; !ok { + s.startCluster(PDMode) } - test(s.clusters[pdMode]) + test(s.clusters[PDMode]) } func getTestName() string { @@ -347,18 +355,18 @@ func (s *SchedulingTestEnvironment) RunTestInAPIMode(test func(*TestCluster)) { re.NoError(failpoint.Disable("github.com/tikv/pd/server/cluster/highFrequencyClusterJobs")) }() s.t.Logf("start test %s in api mode", getTestName()) - if _, ok := s.clusters[apiMode]; !ok { - s.startCluster(apiMode) + if _, ok := s.clusters[APIMode]; !ok { + s.startCluster(APIMode) } - test(s.clusters[apiMode]) + test(s.clusters[APIMode]) } // RunFuncInTwoModes is to run func in two modes. func (s *SchedulingTestEnvironment) RunFuncInTwoModes(f func(*TestCluster)) { - if c, ok := s.clusters[pdMode]; ok { + if c, ok := s.clusters[PDMode]; ok { f(c) } - if c, ok := s.clusters[apiMode]; ok { + if c, ok := s.clusters[PDMode]; ok { f(c) } } @@ -373,12 +381,12 @@ func (s *SchedulingTestEnvironment) Cleanup() { } } -func (s *SchedulingTestEnvironment) startCluster(m mode) { +func (s *SchedulingTestEnvironment) startCluster(m SchedulerMode) { re := require.New(s.t) ctx, cancel := context.WithCancel(context.Background()) s.cancels = append(s.cancels, cancel) switch m { - case pdMode: + case PDMode: cluster, err := NewTestCluster(ctx, 1, s.opts...) re.NoError(err) err = cluster.RunInitialServers() @@ -386,8 +394,8 @@ func (s *SchedulingTestEnvironment) startCluster(m mode) { re.NotEmpty(cluster.WaitLeader()) leaderServer := cluster.GetServer(cluster.GetLeader()) re.NoError(leaderServer.BootstrapCluster()) - s.clusters[pdMode] = cluster - case apiMode: + s.clusters[PDMode] = cluster + case APIMode: cluster, err := NewTestAPICluster(ctx, 1, s.opts...) re.NoError(err) err = cluster.RunInitialServers() @@ -406,7 +414,7 @@ func (s *SchedulingTestEnvironment) startCluster(m mode) { testutil.Eventually(re, func() bool { return cluster.GetLeaderServer().GetServer().GetRaftCluster().IsServiceIndependent(utils.SchedulingServiceName) }) - s.clusters[apiMode] = cluster + s.clusters[APIMode] = cluster } } diff --git a/tools/pd-ut/ut.go b/tools/pd-ut/ut.go index fbf2a6406515..76b57e5125c2 100644 --- a/tools/pd-ut/ut.go +++ b/tools/pd-ut/ut.go @@ -62,6 +62,9 @@ pd-ut run // run test all cases of a single package pd-ut run $package +// run test all cases of a set of packages +pd-ut run $package1,$package2,... + // run test cases of a single package pd-ut run $package $test @@ -102,7 +105,8 @@ var ( race bool junitFile string coverProfile string - ignoreDir string + ignoreDirs string + cache bool ) func main() { @@ -110,7 +114,8 @@ func main() { parallelStr := stripFlag("--parallel") junitFile = stripFlag("--junitfile") coverProfile = stripFlag("--coverprofile") - ignoreDir = stripFlag("--ignore") + ignoreDirs = stripFlag("--ignore") + cache = handleFlag("--cache") if coverProfile != "" { var err error @@ -171,6 +176,8 @@ func main() { switch os.Args[2] { case "run": isSucceed = cmdRun(os.Args[3:]...) + case "list": + isSucceed = cmdList(os.Args[3:]...) default: isSucceed = usage() } @@ -249,7 +256,7 @@ func cmdBuild(args ...string) bool { // build all packages if len(args) == 0 { - err := buildTestBinaryMulti(pkgs) + _, err := buildTestBinaryMulti(pkgs) if err != nil { fmt.Println("build package error", pkgs, err) return false @@ -266,7 +273,7 @@ func cmdBuild(args ...string) bool { } } - err := buildTestBinaryMulti(dirPkgs) + _, err := buildTestBinaryMulti(dirPkgs) if err != nil { log.Println("build package error", dirPkgs, err) return false @@ -286,55 +293,30 @@ func cmdRun(args ...string) bool { start := time.Now() // run all tests if len(args) == 0 { - err := buildTestBinaryMulti(pkgs) + tasks, err = runExistingTestCases(pkgs) if err != nil { - fmt.Println("build package error", pkgs, err) + fmt.Println("run existing test cases error", err) return false } - - for _, pkg := range pkgs { - exist, err := testBinaryExist(pkg) - if err != nil { - fmt.Println("check test binary existence error", err) - return false - } - if !exist { - fmt.Println("no test case in ", pkg) - continue - } - - tasks = listTestCases(pkg, tasks) - } } // run tests for a single package if len(args) == 1 { + dirs := strings.Split(args[0], ",") var dirPkgs []string for _, pkg := range pkgs { - if strings.Contains(pkg, args[0]) { - dirPkgs = append(dirPkgs, pkg) + for _, dir := range dirs { + if strings.Contains(pkg, dir) { + dirPkgs = append(dirPkgs, pkg) + } } } - err := buildTestBinaryMulti(dirPkgs) + tasks, err = runExistingTestCases(dirPkgs) if err != nil { - log.Println("build package error", dirPkgs, err) + fmt.Println("run existing test cases error", err) return false } - - for _, pkg := range dirPkgs { - exist, err := testBinaryExist(pkg) - if err != nil { - fmt.Println("check test binary existence error", err) - return false - } - if !exist { - fmt.Println("no test case in ", pkg) - continue - } - - tasks = listTestCases(pkg, tasks) - } } // run a single test @@ -408,6 +390,48 @@ func cmdRun(args ...string) bool { return true } +func runExistingTestCases(pkgs []string) (tasks []task, err error) { + // run tests for a single package + content, err := buildTestBinaryMulti(pkgs) + if err != nil { + fmt.Println("build package error", pkgs, err) + return nil, err + } + + // read content + existPkgs := make(map[string]struct{}) + for _, line := range strings.Split(string(content), "\n") { + if len(line) == 0 || strings.Contains(line, "no test files") { + continue + } + // format is + // ? github.com/tikv/pd/server/apiv2/middlewares [no test files] + // ok github.com/tikv/pd/server/api 0.173s + existPkgs[strings.Split(line, "\t")[1]] = struct{}{} + fmt.Println(line) + } + + wg := &sync.WaitGroup{} + tasksChannel := make(chan []task, len(pkgs)) + for _, pkg := range pkgs { + _, ok := existPkgs[fmt.Sprintf("%s/%s", modulePath, pkg)] + if !ok { + fmt.Println("no test case in ", pkg) + continue + } + + wg.Add(1) + go listTestCasesConcurrent(wg, pkg, tasksChannel) + } + + wg.Wait() + close(tasksChannel) + for t := range tasksChannel { + tasks = append(tasks, t...) + } + return tasks, nil +} + // stripFlag strip the '--flag xxx' from the command line os.Args // Example of the os.Args changes // Before: ut run pkg TestXXX --coverprofile xxx --junitfile yyy --parallel 16 @@ -470,6 +494,16 @@ func listTestCases(pkg string, tasks []task) []task { return tasks } +func listTestCasesConcurrent(wg *sync.WaitGroup, pkg string, tasksChannel chan<- []task) { + defer wg.Done() + newCases := listNewTestCases(pkg) + var tasks []task + for _, c := range newCases { + tasks = append(tasks, task{pkg, c}) + } + tasksChannel <- tasks +} + func filterTestCases(tasks []task, arg1 string) ([]task, error) { if strings.HasPrefix(arg1, "r:") { r, err := regexp.Compile(arg1[2:]) @@ -665,8 +699,9 @@ func (*numa) testCommand(pkg string, fn string) *exec.Cmd { func skipDIR(pkg string) bool { skipDir := []string{"bin", "cmd", "realcluster"} - if ignoreDir != "" { - skipDir = append(skipDir, ignoreDir) + if ignoreDirs != "" { + dirs := strings.Split(ignoreDirs, ",") + skipDir = append(skipDir, dirs...) } for _, ignore := range skipDir { if strings.HasPrefix(pkg, ignore) { @@ -677,6 +712,10 @@ func skipDIR(pkg string) bool { } func generateBuildCache() error { + if !cache { + fmt.Println("skip generate build cache") + return nil + } // cd cmd/pd-server && go test -tags=tso_function_test,deadlock -exec-=true -vet=off -toolexec=go-compile-without-link cmd := exec.Command("go", "test", "-exec=true", "-vet", "off", "--tags=tso_function_test,deadlock") goCompileWithoutLink := fmt.Sprintf("-toolexec=%s/tools/pd-ut/go-compile-without-link.sh", workDir) @@ -687,7 +726,6 @@ func generateBuildCache() error { workDir[:strings.LastIndex(workDir, integrationsTestPath)]) } cmd.Args = append(cmd.Args, goCompileWithoutLink) - cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { @@ -697,11 +735,11 @@ func generateBuildCache() error { } // buildTestBinaryMulti is much faster than build the test packages one by one. -func buildTestBinaryMulti(pkgs []string) error { +func buildTestBinaryMulti(pkgs []string) ([]byte, error) { // staged build, generate the build cache for all the tests first, then generate the test binary. // This way is faster than generating test binaries directly, because the cache can be used. if err := generateBuildCache(); err != nil { - return withTrace(err) + return nil, withTrace(err) } // go test --exec=xprog --tags=tso_function_test,deadlock -vet=off --count=0 $(pkgs) @@ -726,13 +764,28 @@ func buildTestBinaryMulti(pkgs []string) error { cmd.Args = append(cmd.Args, "-cover", fmt.Sprintf("-coverpkg=%s", coverpkg)) } cmd.Args = append(cmd.Args, packages...) + if race { + cmd.Args = append(cmd.Args, "-race") + } cmd.Dir = workDir - cmd.Stdout = os.Stdout + outputFile, err := os.CreateTemp("", "test_pd_ut*.out") + if err != nil { + return nil, err + } + cmd.Stdout = outputFile cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { - return withTrace(err) + return nil, withTrace(err) } - return nil + + // return content + content, err := os.ReadFile(outputFile.Name()) + if err != nil { + return nil, err + } + defer outputFile.Close() + + return content, nil } func buildTestBinary(pkg string) error {