github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/tests/mq_protocol_tests/framework/docker_env.go (about)

     1  // Copyright 2020 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 framework
    15  
    16  import (
    17  	"context"
    18  	"database/sql"
    19  	"fmt"
    20  	"os/exec"
    21  
    22  	"github.com/pingcap/log"
    23  	cerrors "github.com/pingcap/tiflow/pkg/errors"
    24  	"github.com/pingcap/tiflow/pkg/retry"
    25  	"go.uber.org/zap"
    26  )
    27  
    28  const (
    29  	// UpstreamPD is upstream PD URI.
    30  	UpstreamPD = "http://upstream-pd:2379"
    31  	// UpstreamDSN is upstream database dsn
    32  	UpstreamDSN = "root@tcp(127.0.0.1:4000)/"
    33  	// DownstreamDSN is downstream database dsn
    34  	DownstreamDSN = "root@tcp(127.0.0.1:5000)/"
    35  	// DockerComposeFilePathPrefix is prefix of docker compose file path.
    36  	DockerComposeFilePathPrefix = "/deployments/ticdc/docker-compose/"
    37  	// ControllerContainerName is the ticdc controller container name.
    38  	ControllerContainerName = "ticdc_controller"
    39  )
    40  
    41  // DockerEnv represents the docker-compose service
    42  type DockerEnv struct {
    43  	DockerComposeOperator
    44  }
    45  
    46  // Reset implements Environment
    47  func (e *DockerEnv) Reset() {
    48  	stdout, err := e.ExecInController(`/cdc cli unsafe reset --no-confirm --pd="http://upstream-pd:2379"`)
    49  	if err != nil {
    50  		log.Fatal("ResetEnv: cannot reset the cdc cluster", zap.ByteString("stdout", stdout), zap.Error(err))
    51  	}
    52  	log.Info("ResetEnv: reset the cdc cluster", zap.ByteString("stdout", stdout))
    53  
    54  	upstream, err := sql.Open("mysql", UpstreamDSN)
    55  	if err != nil {
    56  		log.Fatal("ResetEnv: cannot connect to upstream database", zap.Error(err))
    57  	}
    58  	defer upstream.Close()
    59  	if err := dropAllSchemas(upstream); err != nil {
    60  		log.Fatal("ResetEnv: error found when dropping all schema", zap.Error(err))
    61  	}
    62  
    63  	downstream, err := sql.Open("mysql", DownstreamDSN)
    64  	if err != nil {
    65  		log.Fatal("ResetEnv: cannot connect to downstream database", zap.Error(err))
    66  	}
    67  	defer downstream.Close()
    68  	if err := dropAllSchemas(downstream); err != nil {
    69  		log.Fatal("ResetEnv: error found when dropping all schema", zap.Error(err))
    70  	}
    71  }
    72  
    73  // RunTest implements Environment
    74  func (e *DockerEnv) RunTest(task Task) {
    75  	cmdLine := "/cdc " + task.GetCDCProfile().String()
    76  	bytes, err := e.ExecInController(cmdLine)
    77  	if err != nil {
    78  		log.Fatal("RunTest failed: cannot setup changefeed",
    79  			zap.Error(err),
    80  			zap.ByteString("stdout", bytes),
    81  			zap.ByteString("stderr", err.(*exec.ExitError).Stderr))
    82  	}
    83  
    84  	upstream, err := sql.Open("mysql", UpstreamDSN)
    85  	if err != nil {
    86  		log.Fatal("RunTest: cannot connect to upstream database", zap.Error(err))
    87  	}
    88  
    89  	downstream, err := sql.Open("mysql", DownstreamDSN)
    90  	if err != nil {
    91  		log.Fatal("RunTest: cannot connect to downstream database", zap.Error(err))
    92  	}
    93  
    94  	taskCtx := &TaskContext{
    95  		Upstream:   upstream,
    96  		Downstream: downstream,
    97  		Env:        e,
    98  		WaitForReady: func() error {
    99  			return retry.Do(context.Background(), e.HealthChecker, retry.WithBackoffBaseDelay(1000), retry.WithMaxTries(120), retry.WithIsRetryableErr(cerrors.IsRetryableError))
   100  		},
   101  		Ctx: context.Background(),
   102  	}
   103  
   104  	err = task.Prepare(taskCtx)
   105  	if err != nil {
   106  		e.TearDown()
   107  		log.Fatal("RunTest: task preparation failed", zap.String("name", task.Name()), zap.Error(err))
   108  	}
   109  
   110  	log.Info("Start running task", zap.String("name", task.Name()))
   111  	err = task.Run(taskCtx)
   112  	if err != nil {
   113  		err1 := e.DumpStdout()
   114  		if err1 != nil {
   115  			log.Warn("Failed to dump container logs", zap.Error(err1))
   116  		}
   117  		e.TearDown()
   118  		log.Fatal("RunTest: task failed", zap.String("name", task.Name()), zap.Error(err))
   119  	}
   120  	log.Info("Finished running task", zap.String("name", task.Name()))
   121  }
   122  
   123  // SetListener implements Environment. Currently unfinished, will be used to monitor Kafka output
   124  func (e *DockerEnv) SetListener(states interface{}, listener MqListener) {
   125  	// TODO
   126  }
   127  
   128  var systemSchema = map[string]struct{}{
   129  	"INFORMATION_SCHEMA": {},
   130  	"METRICS_SCHEMA":     {},
   131  	"PERFORMANCE_SCHEMA": {},
   132  	"mysql":              {},
   133  }
   134  
   135  func dropAllSchemas(db *sql.DB) error {
   136  	result, err := db.Query("show databases;")
   137  	if err != nil {
   138  		return err
   139  	}
   140  	var schemaNames []string
   141  	var schema string
   142  	for result.Next() {
   143  		err := result.Scan(&schema)
   144  		if err != nil {
   145  			return err
   146  		}
   147  		schemaNames = append(schemaNames, schema)
   148  	}
   149  	for _, schema := range schemaNames {
   150  		if _, ok := systemSchema[schema]; ok {
   151  			continue
   152  		}
   153  		_, err := db.Exec(fmt.Sprintf("drop database %s;", schema))
   154  		if err != nil {
   155  			return err
   156  		}
   157  	}
   158  	return nil
   159  }