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 }