github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/engine/test/e2e/e2e_test.go (about)

     1  // Copyright 2022 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package e2e_test
    15  
    16  import (
    17  	"context"
    18  	"encoding/json"
    19  	"fmt"
    20  	"os"
    21  	"sync"
    22  	"testing"
    23  	"time"
    24  
    25  	pb "github.com/pingcap/tiflow/engine/enginepb"
    26  	cvs "github.com/pingcap/tiflow/engine/jobmaster/cvsjob"
    27  	"github.com/pingcap/tiflow/engine/test/e2e"
    28  	"github.com/stretchr/testify/require"
    29  	"google.golang.org/grpc"
    30  )
    31  
    32  type Config struct {
    33  	DemoAddrs   []string `json:"demo_address"`
    34  	DemoHost    []string `json:"demo_host"`
    35  	MasterAddrs []string `json:"master_address_list"`
    36  	RecordNum   int64    `json:"demo_record_num"`
    37  	JobNum      int      `json:"job_num"`
    38  	DemoDataDir string   `json:"demo_data_dir"`
    39  	FileNum     int      `json:"file_num"`
    40  }
    41  
    42  func NewConfigFromFile(file string) (*Config, error) {
    43  	data, err := os.ReadFile(file)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	var config Config
    48  	err = json.Unmarshal(data, &config)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  	return &config, nil
    53  }
    54  
    55  type DemoClient struct {
    56  	conn   *grpc.ClientConn
    57  	client pb.DataRWServiceClient
    58  }
    59  
    60  func NewDemoClient(ctx context.Context, addr string) (*DemoClient, error) {
    61  	conn, err := grpc.DialContext(ctx, addr, grpc.WithInsecure(), grpc.WithBlock())
    62  	if err != nil {
    63  		return nil, err
    64  	}
    65  	return &DemoClient{
    66  		conn:   conn,
    67  		client: pb.NewDataRWServiceClient(conn),
    68  	}, err
    69  }
    70  
    71  func TestSubmitTest(t *testing.T) {
    72  	configPath := os.Getenv("CONFIG")
    73  	if configPath == "" {
    74  		configPath = "./docker.json"
    75  	}
    76  	config, err := NewConfigFromFile(configPath)
    77  	require.NoError(t, err)
    78  
    79  	for _, demoAddr := range config.DemoAddrs {
    80  		ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    81  		defer cancel()
    82  		democlient, err := NewDemoClient(ctx, demoAddr)
    83  		require.NoError(t, err)
    84  		fmt.Println("connect demo " + demoAddr)
    85  
    86  		resp, err := democlient.client.GenerateData(ctx, &pb.GenerateDataRequest{
    87  			FileNum:   int32(config.FileNum),
    88  			RecordNum: int32(config.RecordNum),
    89  		})
    90  		require.NoError(t, err)
    91  		require.Empty(t, resp.ErrMsg)
    92  	}
    93  
    94  	flowControl := make(chan struct{}, 50)
    95  	// avoid job swarming
    96  	go func() {
    97  		for i := 1; i <= config.JobNum; i++ {
    98  			if i%50 == 0 {
    99  				time.Sleep(100 * time.Millisecond)
   100  			}
   101  			flowControl <- struct{}{}
   102  		}
   103  	}()
   104  	var wg sync.WaitGroup
   105  	wg.Add(config.JobNum)
   106  	for i := 1; i <= config.JobNum; i++ {
   107  		demoAddr := config.DemoAddrs[i%len(config.DemoAddrs)]
   108  		demoHost := config.DemoHost[i%len(config.DemoHost)]
   109  		go func(idx int) {
   110  			defer wg.Done()
   111  			cfg := &cvs.Config{
   112  				DstDir:  fmt.Sprintf(config.DemoDataDir+"/data%d", idx),
   113  				SrcHost: demoHost,
   114  				DstHost: demoHost,
   115  				FileNum: config.FileNum,
   116  			}
   117  			testSubmitTest(t, cfg, config, demoAddr, flowControl)
   118  		}(i)
   119  	}
   120  	wg.Wait()
   121  }
   122  
   123  // run this test after docker-compose has been up
   124  func testSubmitTest(t *testing.T, cfg *cvs.Config, config *Config, demoAddr string, flowControl chan struct{}) {
   125  	var (
   126  		tenantID  = "e2e-test"
   127  		projectID = "project-basic-test"
   128  	)
   129  
   130  	ctx := context.Background()
   131  	fmt.Printf("connect demo\n")
   132  	democlient, err := NewDemoClient(ctx, demoAddr)
   133  	require.NoError(t, err)
   134  	fmt.Printf("connect clients\n")
   135  
   136  	for {
   137  		resp, err := democlient.client.IsReady(ctx, &pb.IsReadyRequest{})
   138  		require.NoError(t, err)
   139  		if resp.Ready {
   140  			break
   141  		}
   142  		time.Sleep(10 * time.Millisecond)
   143  	}
   144  
   145  	configBytes, err := json.Marshal(cfg)
   146  	require.NoError(t, err)
   147  
   148  	<-flowControl
   149  	fmt.Printf("test is ready\n")
   150  
   151  	jobID, err := e2e.CreateJobViaHTTP(ctx, config.MasterAddrs[0],
   152  		tenantID, projectID, pb.Job_CVSDemo, configBytes)
   153  	require.NoError(t, err)
   154  
   155  	fmt.Printf("job id %s\n", jobID)
   156  
   157  	// continue to query
   158  	for {
   159  		ctx1, cancel := context.WithTimeout(ctx, 3*time.Second)
   160  		job, err := e2e.QueryJobViaHTTP(ctx1, config.MasterAddrs[0],
   161  			tenantID, projectID, jobID,
   162  		)
   163  		require.NoError(t, err)
   164  		cancel()
   165  		require.Equal(t, pb.Job_CVSDemo, job.Type)
   166  		fmt.Printf("query id %s, status %d, time %s\n",
   167  			jobID, int(job.State), time.Now().Format("2006-01-02 15:04:05"))
   168  		if job.State == pb.Job_Finished {
   169  			break
   170  		}
   171  		time.Sleep(time.Second)
   172  	}
   173  	fmt.Printf("job id %s checking\n", jobID)
   174  	// check files
   175  	demoResp, err := democlient.client.CheckDir(ctx, &pb.CheckDirRequest{
   176  		Dir: cfg.DstDir,
   177  	})
   178  	require.NoError(t, err)
   179  	require.Empty(t, demoResp.ErrMsg, demoResp.ErrFileIdx)
   180  }