package webScene

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"net"
	"net/http"
	"strconv"
	"strings"
	"time"

	l4g "github.com/alecthomas/log4go"
	"github.com/gavv/httpexpect/v2"
	"github.com/shopspring/decimal"
	"github.com/stretchr/testify/assert"
	"github.com/tidbcloud/qa-PlatformAPIAuto/common"
	"github.com/tidbcloud/qa-PlatformAPIAuto/models"
	u "github.com/tidbcloud/qa-PlatformAPIAuto/util"
	"github.com/tidbcloud/qa-gourd/ProductModel"
	"github.com/tidbcloud/qa-gourd/ProductService"
	"github.com/tidbcloud/qa-gourd/util"
)

func (w *WebE2ECase) DeleteCIDRById(cidrId string, isActive bool) {
	orgId := w.WebRequestInfo.User.OrgId
	projectId := w.WebRequestInfo.User.ProjectId
	pathparam := map[string]string{"org_id": orgId, "project_id": projectId, "cidr_id": cidrId}
	deleteResp := w.WebRequestInfo.DoWebAPIRequestByUrlInfo(w.URLInfoMap["deleteCIDR"], nil, pathparam, nil)
	w.Reporter.StepReport(fmt.Sprintf("delete project cidr, pathparam:%s, Resp:%s", pathparam, deleteResp.JSON().Raw()), func() {
		deleteResp.Status(http.StatusOK)
		if isActive {
			deleteResp.JSON().Path("$.base_resp.err_code").IsEqual("49900001")
			deleteResp.JSON().Path("$.base_resp.err_msg").IsEqual("when CIDR is active, user can't update or delete it")
		} else {
			deleteResp.JSON().Path("$.base_resp.err_code").IsEqual("0")
		}
	})
}

func (w *WebE2ECase) CreateRegionCidr(cidr string) string {
	orgId := w.WebRequestInfo.User.OrgId
	projectId := w.WebRequestInfo.User.ProjectId
	provider := strings.ToUpper(w.WebRequestInfo.Cluster.Provider)
	region := w.WebRequestInfo.Cluster.Region
	pathparam := map[string]string{"org_id": orgId, "project_id": projectId}
	//query region cidr
	queryParam := map[string]string{"provider": provider}
	queryResp := w.WebRequestInfo.DoWebAPIRequestByUrlInfo(w.URLInfoMap["getRegionCIDR"], nil, pathparam, queryParam)
	w.Reporter.StepReport(fmt.Sprintf("query project cidr, pathparam:%s, Resp:%s", pathparam, queryResp.JSON().Raw()), func() {
		queryResp.Status(http.StatusOK)
		if queryResp.JSON().Path("$.total").Number().Raw() > 0 {
			//assert cidr is not set
			find := false
			for _, item := range queryResp.JSON().Path("$.items").Array().Iter() {
				if item.Path("$.region.name").String().Raw() == region {
					find = true
				}
			}
			assert.False(w.Reporter.T, find)
			if find {
				return
			}
		}
	})

	//validate cidr
	w.WebRequestInfo.CreateCIDR(cidr, true)

	//create cidr
	return w.WebRequestInfo.CreateCIDR(cidr, false)
}

func (w *WebE2ECase) CheckActualNodeInfo() {
	orgId := w.WebRequestInfo.User.OrgId
	projectId := w.WebRequestInfo.User.ProjectId
	cluster := w.WebRequestInfo.Cluster
	clusterId := cluster.ClusterId

	//查看集群的详细信息
	clusterPathParam := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId}

	//查看tidb的节点信息
	urlInfo := w.URLInfoMap["getTidbNodeInfo"]
	getTidbNodeInfoResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, clusterPathParam, nil)
	w.Reporter.StepReport(fmt.Sprintf("get cluster tidb node Info, Expect count:%d, "+
		"Actual count:%f", cluster.TiDBNodeCount, getTidbNodeInfoResp.JSON().Path("$.total").Raw()), func() {
		getTidbNodeInfoResp.JSON().Path("$.total").Equal(cluster.TiDBNodeCount)
	})

	//查看tikv的节点信息
	urlInfo = w.URLInfoMap["getTikvNodeInfo"]
	getTikvNodeInfoResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, clusterPathParam, nil)
	w.Reporter.StepReport(fmt.Sprintf("get cluster tikv node Info, Expect count:%d, "+
		"Actual count:%f", cluster.TiKVNodeCount, getTikvNodeInfoResp.JSON().Path("$.total").Raw()),
		func() {
			getTikvNodeInfoResp.JSON().Path("$.total").Equal(cluster.TiKVNodeCount)
		})

	//查看tiflash的节点信息
	urlInfo = w.URLInfoMap["getTiflashNodeInfo"]
	getTiflashNodeInfoResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, clusterPathParam, nil)
	w.Reporter.StepReport(fmt.Sprintf("get cluster tiflash node Info, Expect count:%d, "+
		"Actual count:%f", cluster.TiFlashNodeCount, getTiflashNodeInfoResp.JSON().Path("$.total").Raw()),
		func() {
			getTiflashNodeInfoResp.JSON().Path("$.total").Equal(cluster.TiFlashNodeCount)
		})
}

func (w *WebE2ECase) SetAuditLog() {
	orgId := w.WebRequestInfo.User.OrgId
	projectId := w.WebRequestInfo.User.ProjectId
	clusterId := w.WebRequestInfo.Cluster.ClusterId
	provider := w.WebRequestInfo.Cluster.Provider
	//add audit log auth in s3 and gcs
	w.addAuditAuth()
	//set audit access records
	postAccessRecordsParam := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId}
	access_items := common.NewRecords("root", "test", "testuser", []string{"CreateTable", "Insert", "Select"})
	// access_items := NewRecords(".*", ".*", ".*", []string{"AlterTable", "AnalyzeTable", "Begin", "Change", "Commit", "CreateDatabase", "CreateIndex", "CreateTable", "CreateView", "CreateUser", "Delete", "DropDatabase", "DropIndex",
	// 	"DropView", "DropTable", "DescTable", "ExplainAnalyzeSQL", "ExplainSQL", "Replace", "Insert", "LoadData", "RollBack", "Select", "Set", "Show", "TruncateTable", "Update", "Grant", "Revoke",
	// 	"Deallocate", "Execute", "Prepare", "Use", "CreateBinding", "IndexAdvise", "DropBinding", "Trace", "Shutdown", "other"})
	audit_log_access_records := common.NewAccessRecords(orgId, projectId, clusterId, access_items)
	l4g.Info("audit_log_access_records is : %s", audit_log_access_records)

	urlInfo := w.URLInfoMap["postAuditLogAccessRecords"]
	postAccessRecordsResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, audit_log_access_records, postAccessRecordsParam, nil)
	l4g.Info("postAccessRecordsResp is : %s, body is %v, param is %v", postAccessRecordsResp.JSON().Raw(), audit_log_access_records, postAccessRecordsParam)

	w.Reporter.StepReport(fmt.Sprintf("check post audit log access records, Expect res:%s, "+
		"Actual res:%s", "status 200 ok", postAccessRecordsResp.Raw().Status), func() {
		postAccessRecordsResp.Status(http.StatusOK)
	})

	//start audit log
	startAuditLogParam := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId}

	var start_audit_log_config *ProductModel.AuditLogConfig
	if provider == ProductModel.AWS {
		start_audit_log_config = w.WebRequestInfo.NewAuditLogConfig(1)
	} else {
		start_audit_log_config = w.WebRequestInfo.NewAuditLogConfig(2)
	}
	start_audit_log := w.WebRequestInfo.NewAuditLog(true, true, start_audit_log_config)
	urlInfo = w.URLInfoMap["putAuditLog"]
	startAuditLogResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, start_audit_log, startAuditLogParam, nil)
	l4g.Info("startAuditLogResp is : %s", startAuditLogResp)
	errCode := startAuditLogResp.JSON().Path("$.base_resp.err_code").String().Raw()
	// Rerun permission grant
	// "base_resp":{"err_code":"49900003","err_msg":"Bucket access verification failed. Please check the bucket URL and role ARN are correct, then try again."}}
	if errCode == "49900001" || errCode == "49900003" {
		for i := 0; i < 20; i++ {
			time.Sleep(30 * time.Second)
			startAuditLogResp = w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, start_audit_log, startAuditLogParam, nil)
			if startAuditLogResp.JSON().Path("$.base_resp.err_code").String().Raw() == "0" {
				break
			}
			w.addAuditAuth()
		}
	}

	w.Reporter.StepReport(fmt.Sprintf("check start audit log, Expect res:%s, "+
		"Actual res: enabled = %s", "enabled = true", startAuditLogResp.JSON().Raw()),
		func() {
			startAuditLogResp.JSON().Path("$.enabled").Boolean().True()
		},
	)
}

func (w *WebE2ECase) AuditLogSelectFromTidb() {
	w.WebRequestInfo.AddTrafficFilter("0.0.0.0/0", false)
	util.SecondTimeWait(6, 10, "Wait For Traffic Filter To Take Effect")

	cluster, _ := w.WebRequestInfo.GetClusterInfo()
	db, _ := w.WebRequestInfo.Cluster.ConnectTidbUseTLS(*cluster.Cluster.Endpoint.Address, int64(*cluster.Cluster.Endpoint.Port), w.WebRequestInfo.Cluster.Password, "test", "root")

	var createTable = "CREATE TABLE `testUser` (\n\t  `id` int(10) primary key,\n\t  `name` varchar(20));"
	util.CreateTable(db, createTable)
	var testUserSelect = "select * from testUser;"
	common.SelectData(db, testUserSelect, false, 1, "autotest")
	db.Close()
}

func (w *WebE2ECase) CheckAuditLog() {
	//去检查audit log的文件是否存入了s3/gcs
	if w.WebRequestInfo.Cluster.Provider == ProductModel.AWS {
		w.WebRequestInfo.CheckS3AuditLog()
	} else {
		w.WebRequestInfo.CheckGcsAuditLog()
	}
	//TODO:v2.0 要检查上传的日志文件里有没设置的语句，看看前面有没有写sql语句的，直接拿来用
}

func (w *WebE2ECase) CheckUpdatePassword() {
	//获取cluster信息
	cluster, _ := w.WebRequestInfo.GetClusterInfo()
	var user string
	if cluster.Cluster.IsDevTier {
		token := *cluster.Cluster.Endpoint.Token
		user = token + ".root"
	} else {
		user = "root"
	}
	oldPassword := w.WebRequestInfo.Cluster.Password
	password := u.ReverseString(oldPassword)
	w.WebRequestInfo.UpdatePassword(password)
	//连接tidb-用host port形式连接
	_, err := w.WebRequestInfo.Cluster.ConnectTidbUseTLS(*cluster.Cluster.Endpoint.Address, int64(*cluster.Cluster.Endpoint.Port), password, "test", user)
	result := false
	if err == nil {
		result = true
	}
	w.Reporter.StepReport(fmt.Sprintf("standard connect tidb result:%t, ConnectTidb failed reason:%s", result, err),
		func() {
			assert.True(w.Reporter.T, result)
		})
	time.Sleep(30 * time.Second)
	w.WebRequestInfo.UpdatePassword(oldPassword)
}

func (w *WebE2ECase) CheckPrivateLinkConnect() {
	orgId := w.WebRequestInfo.User.OrgId
	projectId := w.WebRequestInfo.User.ProjectId
	clusterId := w.WebRequestInfo.Cluster.ClusterId
	provider := w.WebRequestInfo.Cluster.Provider
	region := w.WebRequestInfo.Cluster.Region

	if !w.WebRequestInfo.GetVPCSupportRegion() {
		//其他region 不支持
		w.Reporter.StepReport(fmt.Sprintf("当前region: %s 不支持,请手工确认", region),
			func() {
				assert.True(w.Reporter.T, false)
			})
		return
	}

	//加载配置
	var gcpEndPointName string
	if provider == ProductModel.GCP {
		gcpEndPointName = "endpoint" + u.GenTempName()
		defer w.WebRequestInfo.StopGCPInstance()
		defer w.WebRequestInfo.DeleteVPCEndpoint(gcpEndPointName)
	}

	pathParam := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId}
	addEndpointServiceBody := common.NewPrivatelinkService(provider)
	urlInfo := w.URLInfoMap["addEndpointService"]
	addEndpointServiceResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, addEndpointServiceBody, pathParam, nil)
	l4g.Info("add endpointService, the body is %s, pathParam is %s, addEndpointServiceResp is %+v", addEndpointServiceBody,
		pathParam, addEndpointServiceResp.JSON().Raw())
	w.Reporter.StepReport(fmt.Sprintf("add endpointService, body:%v, pathParam:%s, addEndpointServiceResp:%s", nil, pathParam, addEndpointServiceResp.JSON().Raw()),
		func() {
			addEndpointServiceResp.Status(http.StatusOK)
			if addEndpointServiceResp.JSON().Path("$.base_resp.err_code").String().Raw() != "0" {
				addEndpointServiceResp.JSON().Path("$.base_resp.err_msg").IsEqual("private endpoint service has been created")
			} else {
				addEndpointServiceResp.JSON().Path("$.base_resp.err_code").IsEqual("0")
			}
		})

	if addEndpointServiceResp.JSON().Path("$.base_resp.err_code").String().Raw() != "0" &&
		addEndpointServiceResp.JSON().Path("$.base_resp.err_msg").String().Raw() != "private endpoint service has been created" {
		return
	}

	var getEndpointServiceResp, getPrivateLinksResp *httpexpect.Response
	urlInfo = w.URLInfoMap["getEndpointService"]
	for round := 0; round < 15; round++ {
		getEndpointServiceResp = w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, pathParam, nil)
		l4g.Info("get endpointService, the body is %s, pathParam is %s, getEndpointServiceResp is %+v", nil,
			pathParam, getEndpointServiceResp.JSON().Raw())
		if getEndpointServiceResp.Status(http.StatusOK).JSON().Path("$.privatelink_service.status").String().Raw() == "ACTIVE" {
			break
		}
		time.Sleep(time.Second * 60)
	}

	status := getEndpointServiceResp.Status(http.StatusOK).JSON().Path("$.privatelink_service.status").String().Raw()
	dns_name := getEndpointServiceResp.Status(http.StatusOK).JSON().Path("$.privatelink_service.dns_name").String().Raw()
	endpointService := getEndpointServiceResp.Status(http.StatusOK).JSON().Path("$.privatelink_service.name").String().Raw()

	w.Reporter.StepReport(fmt.Sprintf("get endpointService status, except:%s, actual:%s, getEndpointServiceResp:%s", "ACTIVE", status, addEndpointServiceResp.JSON().Raw()),
		func() {
			getEndpointServiceResp.Status(http.StatusOK).JSON().Path("$.privatelink_service.status").String().IsEqual("ACTIVE")
			assert.NotEmpty(w.Reporter.T, dns_name)
			assert.NotEmpty(w.Reporter.T, endpointService)
		})

	if status != "ACTIVE" || dns_name == "" || endpointService == "" {
		w.WebRequestInfo.Cluster.RemainFlag = true
		return
	}
	var endPoint string
	var err error
	if provider == ProductModel.AWS {
		endPoint, err = w.WebRequestInfo.CreateAWSVPCEndpoint(endpointService)
	} else if provider == ProductModel.GCP {
		endPoint, err = w.WebRequestInfo.CreateGCPVPCEndpoint(gcpEndPointName, endpointService)
	}

	w.Reporter.StepReport(fmt.Sprintf("createEndPoint, result is:%s, reason is:%s", endPoint, err),
		func() {
			assert.Nil(w.Reporter.T, err)
		})

	if err != nil {
		w.WebRequestInfo.Cluster.RemainFlag = true
		return
	}

	var createPrivateLinkBody map[string]string
	if provider == "gcp" {
		createPrivateLinkBody = map[string]string{
			"cloud_provider": provider,
			"endpoint_name":  endPoint}
	} else if provider == "aws" {
		createPrivateLinkBody = map[string]string{
			"cloud_provider": provider,
			"endpoint_id":    endPoint}
	}
	urlInfo = w.URLInfoMap["addPrivateLink"]
	createPrivateLinkResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, createPrivateLinkBody, pathParam, nil)
	l4g.Info("create private link, the body is %s, pathParam is %s, createPrivateLinkResp is %+v", createPrivateLinkBody,
		pathParam, createPrivateLinkResp.JSON().Raw())
	w.Reporter.StepReport(fmt.Sprintf("create private link, body:%v, pathParam:%s, createPrivateLinkResp:%s", createPrivateLinkBody, pathParam, addEndpointServiceResp.JSON().Raw()), func() {
		createPrivateLinkResp.Status(http.StatusOK)
		createPrivateLinkResp.JSON().Path("$.base_resp.err_code").Equal("0")
	})

	if createPrivateLinkResp.JSON().Path("$.base_resp.err_code").String().Raw() != "0" {
		w.WebRequestInfo.Cluster.RemainFlag = true
		return
	}

	//查询状态，直到 ACTIVE
	var index int
	var endpointStatus string
	projectPath := map[string]string{"org_id": orgId, "project_id": projectId}
	urlInfo = w.URLInfoMap["getPrivateLinks"]
	for round := 0; round < 15; round++ {
		getPrivateLinksResp = w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, projectPath, nil)
		l4g.Info("getPrivateLinksResp:%s", getPrivateLinksResp.JSON().Raw())
		var privateLinks = common.ListPrivateLinkEndpointsResp{}
		privateLinks, _ = util.UnmarshalResult(getPrivateLinksResp, privateLinks)
		for num, privatelink := range privateLinks.Endpoints {
			if privatelink.ClusterId == clusterId && privatelink.EndpointId == endPoint {
				endpointStatus = privatelink.Status
				index = num
				break
			}
		}
		if endpointStatus == "ACTIVE" {
			break
		}
		time.Sleep(time.Second * 60)
	}
	w.Reporter.StepReport(fmt.Sprintf("get private link status, except:%s, actual:%s, getEndpointServiceResp:%s", "ACTIVE", endpointStatus, getPrivateLinksResp.JSON().Raw()), func() {
		getPrivateLinksResp.Status(http.StatusOK).JSON().Path("$.endpoints[" + strconv.Itoa(index) + "].status").String().Equal("ACTIVE")
	})

	if endpointStatus == "" {
		w.WebRequestInfo.Cluster.RemainFlag = true
		return
	}

	var result bool
	if provider == ProductModel.GCP {
		endPointHost := gcpEndPointName + "." + dns_name
		result = w.WebRequestInfo.CheckConnectTiDBInVM(endPointHost, "root")
	} else if provider == ProductModel.AWS {
		w.WebRequestInfo.EnableAWSVPCEndpointDNS(endPoint)
		result = w.WebRequestInfo.CheckConnectTiDBInVM(dns_name, "root")
	}
	if result == false {
		w.WebRequestInfo.Cluster.RemainFlag = true
		return
	}

	deletePath := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId, "endpoint": endPoint}
	if provider == "gcp" {
		endPointId := getPrivateLinksResp.JSON().Path("$.endpoints[" + strconv.Itoa(index) + "].id").String().Raw()
		deletePath["endpoint"] = endPointId
	}
	urlInfo = w.URLInfoMap["deleteVpcLink"]
	delPrivateLinkResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, deletePath, nil)
	l4g.Info("delete private link, the body is %s, pathParam is %s, delPrivateLinkResp is %+v", nil,
		deletePath, delPrivateLinkResp.JSON().Raw())
	w.Reporter.StepReport(fmt.Sprintf("delete private link, body:%v, pathParam:%s, delPrivateLinkResp:%s", nil, deletePath, delPrivateLinkResp.JSON().Raw()), func() {
		delPrivateLinkResp.Status(http.StatusOK)
	})
}

func (w *WebE2ECase) CheckFilterAndConnectOperation() {
	orgId := w.WebRequestInfo.User.OrgId
	projectId := w.WebRequestInfo.User.ProjectId
	clusterId := w.WebRequestInfo.Cluster.ClusterId
	password := w.WebRequestInfo.Cluster.Password

	clusterPathParam := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId}

	if !w.WebRequestInfo.Cluster.IsServerless {
		//创建filter
		cidr := "0.0.0.0/0"
		w.WebRequestInfo.AddTrafficFilter(cidr, false)

		//查询filter列表
		urlInfo := w.URLInfoMap["getFilter"]
		getFilterResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, clusterPathParam, nil)
		w.Reporter.StepReport(fmt.Sprintf("getFilter, getFilterResp:%s", getFilterResp.JSON().Raw()), func() {
			getFilterResp.JSON().Path("$.traffic_filters.cidrs[0].cidr").String().Equal(cidr)
		})
	}

	cluster, _ := w.WebRequestInfo.GetClusterInfo()

	//获取cluster信息
	tidbAddress := *cluster.Cluster.Endpoint.Address
	tidbPort := int64(*cluster.Cluster.Endpoint.Port)
	var user string
	if w.WebRequestInfo.Cluster.IsServerless {
		token := *cluster.Cluster.Endpoint.Token
		user = token + ".root"
	} else {
		user = "root"
	}

	result := w.WebRequestInfo.CheckConnectTiDBByPublicEndpoint(user, tidbAddress)
	w.Reporter.StepReport(fmt.Sprintf("ConnectTidb, result is:%v", result), func() {
		assert.True(w.Reporter.T, result)
	})

	//连接tidb-webshell
	if !w.WebRequestInfo.Cluster.IsServerless {
		terminalPathparam := map[string]string{"cluster_id": clusterId, "org_id": orgId}
		param := map[string]string{"jwt": w.WebRequestInfo.GetToken(w.WebRequestInfo.User.TenantEmail)}
		var terminalResp *httpexpect.Response
		urlInfo := w.URLInfoMap["terminal"]
		for i := 0; i < 2; i++ {
			terminalResp = w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, terminalPathparam, param)
		}
		l4g.Info("web shell connect resp is:%s, pathparam is: %s, param is:%s", terminalResp.Raw(), terminalPathparam, param)
		w.Reporter.StepReport(fmt.Sprintf("web shell connect result:%d", terminalResp.Raw().StatusCode), func() {
			terminalResp.Status(http.StatusOK)
		})
	}

	//连接tidb-用host port形式连接
	_, err := w.WebRequestInfo.Cluster.ConnectTidbUseTLS(tidbAddress, tidbPort, password, "test", user)
	result = true
	if err != nil {
		result = false
	}
	//result, ierr := InsertDataToTest(db)
	w.Reporter.StepReport(fmt.Sprintf("standard connect tidb result:%t, ConnectTidb failed reason:%s, tidbAddress:%s", result, err, tidbAddress), func() {
		assert.True(w.Reporter.T, result)
	})
}

func (w *WebE2ECase) CheckVPCOperation(crossRegion bool) {
	if !crossRegion && !w.WebRequestInfo.GetVPCSupportRegion() {
		//其他region 不支持
		w.Reporter.StepReport(fmt.Sprintf("当前same region: %s Case不支持,请手工确认 or 测试cross region", w.WebRequestInfo.Cluster.Region),
			func() {
				assert.True(w.Reporter.T, false)
			})
		return
	}

	orgId := w.WebRequestInfo.User.OrgId
	projectId := w.WebRequestInfo.User.ProjectId
	pathparam := map[string]string{"org_id": orgId, "project_id": projectId}
	//创建VPC
	var total int
	var id string
	if w.WebRequestInfo.Cluster.Provider == ProductModel.AWS {
		total, id = w.createAWSVpcPeeringUntilActive(crossRegion)
	} else {
		defer w.WebRequestInfo.StopGCPInstance()
		total, id = w.createGCPVpcPeeringUntilActive()
	}
	if id == "" {
		return
	}
	//删除VPC
	w.deleteVpcPeering(id)

	//查询VPC列表
	urlInfo := w.URLInfoMap["getAwsVpcList"]
	if w.WebRequestInfo.Cluster.Provider == ProductModel.GCP {
		urlInfo = w.URLInfoMap["getGcpVpc"]
	}
	getVpcListResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, pathparam, nil)
	l4g.Info("get Aws Vpc list, getVpcListResp is: %s", getVpcListResp.JSON().Raw())
	w.Reporter.StepReport(fmt.Sprintf("check Vpc is deleted, ExpectNum:%d, ActualNum:%v",
		total-1, getVpcListResp.JSON().Path("$.total").Raw()), func() {
		getVpcListResp.JSON().Path("$.total").Equal(total - 1)
	})
}

func (w *WebE2ECase) Pause() {
	// record and send the cost before pause.
	w.WebRequestInfo.SendClusterCostQuantityAndPriceToCh("ClusterIntervalBeforePausing", decimal.NewFromFloat(float64(time.Since(common.LastBillsEventTime).Hours())))
	common.SetLastBillsEventTime()

	orgId := w.WebRequestInfo.User.OrgId
	projectId := w.WebRequestInfo.User.ProjectId
	clusterId := w.WebRequestInfo.Cluster.ClusterId

	pathParam := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId}
	urlInfo := w.URLInfoMap["pause"]
	pauseResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, pathParam, nil)
	l4g.Info("pause cluster, the body is %s, pathParam is %s, pauseResp is %+v", nil,
		pathParam, pauseResp.JSON().Raw())
	w.Reporter.StepReport(fmt.Sprintf("pause cluster, body:%v, pathParam:%s, pauseErrorCode:%s", nil, pathParam, pauseResp.JSON().Object().Path("$.base_resp.err_code").String().Raw()),
		func() {
			pauseResp.Status(http.StatusOK)
			pauseResp.JSON().Object().Path("$.base_resp.err_code").Equal("0")
		})

	if pauseResp.JSON().Object().Path("$.base_resp.err_code").String().Raw() != "0" {
		l4g.Error(pauseResp.JSON().Object().Path("$.base_resp.err_msg").String().Raw())
		return
	}
	w.Reporter.StepReport(fmt.Sprintf("get cluster status,"+
		"Expected value：%s, clusterId is:%s", "PAUSING", clusterId), func() {
		assert.True(w.Reporter.T, w.WebRequestInfo.CheckClusterStatus("PAUSING", 1))
	})

	var checkoutPaused bool
	for round := 0; round <= 30; round += 1 {
		time.Sleep(time.Second * 60)
		// get cluster info
		cluster, _ := w.WebRequestInfo.GetClusterInfo()
		l4g.Info("cluster status is: %s, round is: %d", cluster.Cluster.Status, round)
		if cluster.Cluster.Status == "PAUSED" {
			checkoutPaused = true
			break
		}

	}

	w.Reporter.StepReport(fmt.Sprintf("check pause stauts , pause success is : %v", checkoutPaused), func() {
		assert.True(w.Reporter.T, checkoutPaused)
	})
}

func (w *WebE2ECase) Resume() {
	orgId := w.WebRequestInfo.User.OrgId
	projectId := w.WebRequestInfo.User.ProjectId
	clusterId := w.WebRequestInfo.Cluster.ClusterId

	clusterPathParam := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId}
	urlInfo := w.URLInfoMap["resume"]
	resumeResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, clusterPathParam, nil)
	l4g.Info("resume cluster, the body is %s, pathParam is %s, resumeResp is %+v", nil,
		clusterPathParam, resumeResp.JSON().Raw())
	w.Reporter.StepReport(fmt.Sprintf("resume cluster, body:%v, pathParam:%s, resumeResp:%s", nil, clusterPathParam, resumeResp.JSON().Raw()),
		func() {
			resumeResp.Status(http.StatusOK)
		})

	w.Reporter.StepReport(fmt.Sprintf("get cluster status,"+
		"Expected value：%s, clusterId is:%s", "RESUMING", clusterId), func() {
		assert.True(w.Reporter.T, w.WebRequestInfo.CheckClusterStatus("RESUMING", 1))
	})
	w.Reporter.StepReport(fmt.Sprintf("get cluster status,"+
		"Expected value：%s, clusterId is:%s", "NORMAL", clusterId), func() {
		assert.True(w.Reporter.T, w.WebRequestInfo.CheckClusterStatus("NORMAL", 20))
	})
	cluster, _ := w.WebRequestInfo.GetClusterInfo()
	if cluster.Cluster.Status != "NORMAL" {
		w.WebRequestInfo.Cluster.RemainFlag = true
	}

	// after cluster's status -> NORMAL, the cluster start to meter full cost.
	w.WebRequestInfo.SendClusterCostQuantityAndPriceToCh(ProductService.ClusterPausedEvent, decimal.NewFromFloat(float64(time.Since(common.LastBillsEventTime).Hours())), true)
	common.SetLastBillsEventTime()
}

func (w *WebE2ECase) CheckScaleCluster() {
	tidb_count := w.WebRequestInfo.Cluster.TiDBNodeCount
	tikv_count := w.WebRequestInfo.Cluster.TiKVNodeCount
	tiflash_count := w.WebRequestInfo.Cluster.TiFlashNodeCount

	cluster, _ := w.WebRequestInfo.GetClusterInfo()
	tikvStorage := int(*cluster.Cluster.ClusterComponents.Tikv.NodeProfile.StorageGi)
	_, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId, _, tidbScaleProfileId, tikvScaleProfileId, tiflashScaleProfileId := w.WebRequestInfo.GetProfileIds()
	if tiflash_count != 0 {
		tiflashStorage = int(*cluster.Cluster.ClusterComponents.Tiflash.NodeProfile.StorageGi)
	} else {
		tiflashScaleProfileId = tiflashProfileId
	}
	//扩容
	l4g.Info("begin to scale cluster!")
	//tidb node scale
	tidb_count += 1
	startTime := strconv.FormatInt(time.Now().Unix(), 10)
	w.scaleCluster(tidb_count, tikv_count, tiflash_count, tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId)
	common.CheckPodUptime(w.Reporter.T, w.WebRequestInfo.Cluster.Provider, w.WebRequestInfo.Cluster.ClusterId, common.TiKVType, startTime)

	if w.WebRequestInfo.Cluster.CPU != 2 && w.WebRequestInfo.Cluster.CPU != 4 {
		//tikv node scale
		tikv_count += 3
		startTime = strconv.FormatInt(time.Now().Unix(), 10)
		w.scaleCluster(tidb_count, tikv_count, tiflash_count, tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId)
		common.CheckPodUptime(w.Reporter.T, w.WebRequestInfo.Cluster.Provider, w.WebRequestInfo.Cluster.ClusterId, common.TiDBType, startTime)
		if tiflash_count != 0 {
			common.CheckPodUptime(w.Reporter.T, w.WebRequestInfo.Cluster.Provider, w.WebRequestInfo.Cluster.ClusterId, common.TiFlashType, "")
		}
	}

	//complex scale
	tikvStorage += 10
	tiflashStorage += 10
	if w.WebRequestInfo.Cluster.CPU == 4 {
		tikv_count += 3
		tiflash_count += 1
	} else if w.WebRequestInfo.Cluster.CPU != 2 {
		tiflash_count += 1
	}
	if tidbScaleProfileId != "" {
		w.scaleCluster(tidb_count, tikv_count, tiflash_count, tikvStorage, tiflashStorage, tidbScaleProfileId, tikvScaleProfileId, tiflashScaleProfileId)
	} else {
		//当集群的cpu为当前环境支持的最大cpu时，scaleProfileId 为空，无法再往上升级
		w.scaleCluster(tidb_count, tikv_count, tiflash_count, tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId)
	}

	//缩容
	tidb_count -= 1
	if w.WebRequestInfo.Cluster.CPU != 2 {
		tikv_count -= 3
		tiflash_count -= 1
		//	tikvStorage -= 10
	}
	if tidbScaleProfileId != "" && w.WebRequestInfo.Cluster.Provider == ProductModel.AWS {
		w.scaleCluster(tidb_count, tikv_count, tiflash_count, tikvStorage, tiflashStorage, tidbScaleProfileId, tikvScaleProfileId, tiflashScaleProfileId)
	} else {
		w.scaleCluster(tidb_count, tikv_count, tiflash_count, tikvStorage, tiflashStorage, tidbProfileId, tikvProfileId, tiflashProfileId)
	}

	cluster, _ = w.WebRequestInfo.GetClusterInfo()
	if cluster.Cluster.Status != "NORMAL" {
		w.WebRequestInfo.Cluster.RemainFlag = true
	}
}

func (w *WebE2ECase) CheckEnableAndDisablePublicIp() {
	//获取cluster信息
	cluster, _ := w.WebRequestInfo.GetClusterInfo()
	tidbAddress := *cluster.Cluster.Endpoint.Address
	connectResult := false
	w.Reporter.StepReport("current connect check", func() {
		w.WebRequestInfo.AddTrafficFilter("0.0.0.0/0", false)
		connectResult = w.WebRequestInfo.CheckConnectTiDBByPublicEndpoint("root", tidbAddress)
		assert.True(w.Reporter.T, connectResult)
	})

	if !connectResult {
		w.WebRequestInfo.Cluster.RemainFlag = true
		return
	}

	//disable
	w.WebRequestInfo.AddTrafficFilter("0.0.0.0/0", true)
	for i := 0; i < 10; i++ {
		cluster, _ = w.WebRequestInfo.GetClusterInfo()
		if *cluster.Cluster.Endpoint.Address == "" {
			connectResult = w.WebRequestInfo.CheckConnectTiDBByPublicEndpoint("root", tidbAddress)
			if !connectResult {
				break
			}
		}
		time.Sleep(time.Second * 30)
	}
	//连接tidb-用host port形式连接
	w.Reporter.StepReport("disable connect check", func() {
		assert.False(w.Reporter.T, connectResult)
	})

	if connectResult {
		w.WebRequestInfo.Cluster.RemainFlag = true
		return
	}

	//enable
	w.WebRequestInfo.AddTrafficFilter("0.0.0.0/0", false)
	for i := 0; i < 20; i++ {
		cluster, _ = w.WebRequestInfo.GetClusterInfo()
		tidbAddress = *cluster.Cluster.Endpoint.Address
		if tidbAddress != "" {
			break
		}
		time.Sleep(time.Second * 30)
	}

	//连接tidb-用host port形式连接
	w.Reporter.StepReport("enable connect check", func() {
		connectResult = w.WebRequestInfo.CheckConnectTiDBByPublicEndpoint("root", tidbAddress)
		assert.True(w.Reporter.T, connectResult)
	})

	if !connectResult {
		w.WebRequestInfo.Cluster.RemainFlag = true
		return
	}
}

func (w *WebE2ECase) checkSpecNodeStatus(clusterPathParam map[string]string, tidb_count, tikv_count, tiflash_count int) {
	var err_msg string
	var NormalFlag bool
	var tidbCount, tikvCount, tiflashCount int
	for round := 0; round <= 10; round += 1 {
		time.Sleep(time.Second * 30)
		urlInfo := w.URLInfoMap["getTidbNodeInfo"]
		getTidbNodeInfoResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, clusterPathParam, nil)

		urlInfo = w.URLInfoMap["getTikvNodeInfo"]
		getTikvNodeInfoResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, clusterPathParam, nil)

		urlInfo = w.URLInfoMap["getTiflashNodeInfo"]
		getTiflashNodeInfoResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, clusterPathParam, nil)
		NormalFlag, err_msg, tidbCount, tikvCount, tiflashCount = checkNodeCountAndStatus(getTidbNodeInfoResp, getTikvNodeInfoResp, getTiflashNodeInfoResp)
		if NormalFlag == true {
			break
		}
	}
	if tidb_count != tidbCount || tikv_count != tikvCount || tiflash_count != tiflashCount {
		NormalFlag = false
	}

	w.Reporter.StepReport(fmt.Sprintf("check node count and status , error message is %s, "+
		"expect tidbCount:%d, actual tidbCount:%d, expect tikvCount:%d, actual tikvCount:%d, "+
		"expect tiflashCount:%d, actual tiflashCount:%d", err_msg, tidb_count, tidbCount, tikv_count, tikvCount, tiflash_count, tiflashCount),
		func() {
			assert.True(w.Reporter.T, NormalFlag)
		})
}

func checkNodeCountAndStatus(tidbresp, tikvresp, tiflashresp *httpexpect.Response) (bool, string, int, int, int) {
	//遍历，查看所有节点的状态是否是 normal
	tidbdata := tidbresp.JSON().Raw()
	tikvdata := tikvresp.JSON().Raw()
	tiflashdata := tiflashresp.JSON().Raw()

	var tidbnodes = models.CentralTiDBNodes{}
	var tikvnodes = models.CentralTiKVNodes{}
	var tiflashnodes = models.CentralTiFlashNodes{}
	var tidbCount, tikvCount, tiflashCount int

	tidbresByre, tidbresByteErr := json.Marshal(tidbdata)
	if tidbresByteErr == nil {
		jsonRes := json.Unmarshal(tidbresByre, &tidbnodes)
		if jsonRes == nil {
			for _, tidbnode := range tidbnodes.Items {
				tidbCount++
				if *&tidbnode.Status != "AVAILABLE" {
					return false, fmt.Sprintf("tidb node is %s", tidbnode.Status), tidbCount, tikvCount, tiflashCount
				}
			}
		} else {
			l4g.Error("ChecktidbNodeStatus Unmarshal error: %s", jsonRes)
		}

	} else {
		l4g.Error("ChecktidbNodeStatus Marshal error: %s", tidbresByteErr)
	}

	tikvresByre, tikvresByteErr := json.Marshal(tikvdata)
	if tikvresByteErr == nil {
		jsonRes := json.Unmarshal(tikvresByre, &tikvnodes)
		if jsonRes == nil {
			for _, tikvnode := range tikvnodes.Items {
				tikvCount++
				if *&tikvnode.Status != "AVAILABLE" {
					return false, fmt.Sprintf("tikv node is %s", tikvnode.Status), tidbCount, tikvCount, tiflashCount
				}
			}
		} else {
			l4g.Error("ChecktikvNodeStatus Unmarshal error: %s", jsonRes)
		}

	} else {
		l4g.Error("ChecktikvNodeStatus Marshal error: %s", tikvresByteErr)
	}

	tiflashresByre, tiflashresByteErr := json.Marshal(tiflashdata)
	if tiflashresByteErr == nil {
		jsonRes := json.Unmarshal(tiflashresByre, &tiflashnodes)
		if jsonRes == nil {
			if *tiflashnodes.Total == 0 {
				return true, "", tidbCount, tikvCount, tiflashCount
			}
			for _, tiflashnode := range tiflashnodes.Items {
				tiflashCount++
				if *&tiflashnode.Status != "AVAILABLE" {
					return false, fmt.Sprintf("tiflash node is %s", tiflashnode.Status), tidbCount, tikvCount, tiflashCount
				}
			}
		} else {
			l4g.Error("ChecktiflashNodeStatus Unmarshal error: %s", jsonRes)
		}

	} else {
		l4g.Error("ChecktiflashNodeStatus Marshal error: %s", tiflashresByteErr)
	}
	return true, "", tidbCount, tikvCount, tiflashCount
}

func (w *WebE2ECase) scaleCluster(tidb_count, tikv_count, tiflash_count, tikvStorage, tiflashStorage int, tidbScaleProfileId, tikvScaleProfileId, tiflashScaleProfileId string) bool {
	orgId := w.WebRequestInfo.User.OrgId
	projectId := w.WebRequestInfo.User.ProjectId
	clusterId := w.WebRequestInfo.Cluster.ClusterId

	clusterPathParam := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId}

	l4g.Info("begin to scale cluster!")
	scale := common.NewScale(tidb_count, tikv_count, tiflash_count, tikvStorage, tiflashStorage, tidbScaleProfileId, tikvScaleProfileId, tiflashScaleProfileId)

	urlInfo := w.URLInfoMap["scale"]
	scaleResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, scale, clusterPathParam, nil)
	l4g.Info("do the scale, body is: %+v, pathParam is: %s, scaleResp is %s", scale, clusterPathParam, scaleResp.JSON().Raw())
	w.Reporter.StepReport(fmt.Sprintf("do scale, body is: %+v, pathParam is: %s, resp is: %+v", scale, clusterPathParam, scaleResp.JSON().Raw()),
		func() {
			scaleResp.Status(http.StatusOK)
			scaleResp.JSON().Path("$.base_resp.err_code").String().IsEqual("0")
		})
	if scaleResp.JSON().Path("$.base_resp.err_code").String().Raw() == "0" {
		//查看集群的详细信息
		cluster, _ := w.WebRequestInfo.GetClusterInfo()
		w.Reporter.StepReport(fmt.Sprintf("get cluster node Info, Expect tidb.node_profile.name:%s, "+
			"Actual tidb.node_profile.name:%s",
			tidbScaleProfileId, *cluster.Cluster.ClusterComponents.Tidb.NodeProfile.Name),
			func() {
				assert.Equal(w.Reporter.T, *cluster.Cluster.ClusterComponents.Tidb.NodeProfile.Name, tidbScaleProfileId)
			})

		w.Reporter.StepReport(fmt.Sprintf("get cluster node Info, Expect tikv.node_profile.name:%s, Actual tikv.node_profile.name:%s, "+
			"Expect tikv.storage_gi:%d, Actual tikv.storage_gi:%d",
			tikvScaleProfileId, *cluster.Cluster.ClusterComponents.Tikv.NodeProfile.Name,
			tikvStorage, *cluster.Cluster.ClusterComponents.Tikv.NodeProfile.StorageGi),
			func() {
				assert.Equal(w.Reporter.T, *cluster.Cluster.ClusterComponents.Tikv.NodeProfile.Name, tikvScaleProfileId)
				assert.Equal(w.Reporter.T, int(*cluster.Cluster.ClusterComponents.Tikv.NodeProfile.StorageGi), tikvStorage)
			})

		if tiflash_count != 0 {
			w.Reporter.StepReport(fmt.Sprintf("get cluster node Info, Expect tiflash.node_profile.name:%s, Actual tiflash.node_profile.name:%s, "+
				"Expect tiflash.storage_gi:%d, Actual tiflash.storage_gi:%d",
				tiflashScaleProfileId, *cluster.Cluster.ClusterComponents.Tiflash.NodeProfile.Name,
				tiflashStorage, *cluster.Cluster.ClusterComponents.Tiflash.NodeProfile.StorageGi),
				func() {
					if tiflash_count != 0 {
						assert.Equal(w.Reporter.T, *cluster.Cluster.ClusterComponents.Tiflash.NodeProfile.Name, tiflashScaleProfileId)
						assert.Equal(w.Reporter.T, int(*cluster.Cluster.ClusterComponents.Tiflash.NodeProfile.StorageGi), tiflashStorage)
					}
				})
		}

		w.Reporter.StepReport(fmt.Sprintf("get cluster status, "+
			"Expected value：%s, clusterId is:%s", "SCALING", clusterId), func() {
			assert.True(w.Reporter.T, w.WebRequestInfo.CheckClusterStatus("SCALING", 1))
		})
		w.Reporter.StepReport(fmt.Sprintf("get cluster status, "+
			"Expected value：%s, clusterId is:%s", "NORMAL", clusterId), func() {
			assert.True(w.Reporter.T, w.WebRequestInfo.CheckClusterStatus("NORMAL", 60))
		})

		w.checkSpecNodeStatus(clusterPathParam, tidb_count, tikv_count, tiflash_count)
		return true
	}
	return false
}

func (w *WebE2ECase) createAWSVpcPeeringUntilActive(crossRegion bool) (int, string) {
	orgId := w.WebRequestInfo.User.OrgId
	projectId := w.WebRequestInfo.User.ProjectId

	pathparam := map[string]string{"org_id": orgId, "project_id": projectId}
	//创建VPC

	newVPC := w.WebRequestInfo.NewAWSVPCWithRegion(crossRegion)
	urlInfo := w.URLInfoMap["addAwsVpc"]
	addAwsVpcResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, newVPC, pathparam, nil)
	l4g.Info("add Aws Vpc, addAwsVpcResp is: %s", addAwsVpcResp.JSON().Raw())
	w.Reporter.StepReport(fmt.Sprintf("add Aws Vpc, body:%v, pathParam:%s, addAwsVpcResp:%s", newVPC, pathparam, addAwsVpcResp.JSON().Raw()), func() {
		addAwsVpcResp.Status(http.StatusOK).JSON().Object().Keys().Contains("vpc_peering_id")
		addAwsVpcResp.JSON().Path("$.base_resp.err_code").IsEqual("0")
	})

	if addAwsVpcResp.JSON().Path("$.base_resp.err_code").String().Raw() != "0" {
		return 0, ""
	}

	id := addAwsVpcResp.JSON().Path("$.id").String().Raw()

	var getAwsVpcResp *httpexpect.Response
	var vpcPeeringId, vpcCidr string
	vpcPathParam := map[string]string{"org_id": orgId, "project_id": projectId, "id": id}
	urlInfo = w.URLInfoMap["getAwsVpcInfo"]
	for round := 0; round <= 10; round += 1 {
		time.Sleep(time.Second * 60)
		getAwsVpcResp = w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, vpcPathParam, nil)
		vpcPeeringId = getAwsVpcResp.JSON().Path("$.vpc_peering_id").String().Raw()
		vpcCidr = getAwsVpcResp.JSON().Path("$.vpc_cidr").String().Raw()
		if vpcPeeringId != "" && vpcCidr != "" {
			break
		}
	}
	w.Reporter.StepReport(fmt.Sprintf("check vpc_peering_id, expect vpc_peering_id is %s,getAwsVpcResp:%s", vpcPeeringId, getAwsVpcResp.JSON().Raw()), func() {
		getAwsVpcResp.JSON().Path("$.vpc_peering_id").String().NotEmpty()
		if addAwsVpcResp.JSON().Path("$.vpc_peering_id").String().Raw() != "" {
			addAwsVpcResp.JSON().Path("$.vpc_peering_id").String().IsEqual(vpcPeeringId)
		}
	})

	if vpcPeeringId == "" {
		w.WebRequestInfo.Cluster.RemainFlag = true
		return 1, id
	}

	l4g.Info("begin accept vpc peering, vpcPeeringId is %s, vpcCidr is %s", vpcPeeringId, vpcCidr)
	w.WebRequestInfo.AcceptAWSVpcPeeringWithRegion(vpcPeeringId, newVPC.TenantRegion)

	//查询VPC
	vpcPathParam = map[string]string{"org_id": orgId, "project_id": projectId, "id": id}
	urlInfo = w.URLInfoMap["getAwsVpcInfo"]
	for round := 0; round <= 25; round += 1 {
		time.Sleep(time.Second * 60)
		getAwsVpcResp = w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, vpcPathParam, nil)
		if getAwsVpcResp.JSON().Path("$.status").String().Raw() == "active" {
			break
		}

	}
	w.Reporter.StepReport(fmt.Sprintf("check vpc status, status is %s, getAwsVpcResp:%s",
		getAwsVpcResp.JSON().Path("$.status").String().Raw(), getAwsVpcResp.JSON().Raw()),
		func() {
			getAwsVpcResp.JSON().Path("$.status").String().Equal("active")
		})

	if getAwsVpcResp.JSON().Path("$.status").String().Raw() != "active" {
		w.WebRequestInfo.Cluster.RemainFlag = true
		return 1, id
	}

	l4g.Info("begin delete route")
	w.WebRequestInfo.DelAWSVPCRouteWithRegion(vpcCidr, newVPC.TenantRegion)
	l4g.Info("begin add route")
	w.WebRequestInfo.AddAWSVPCRouteWithRegion(vpcPeeringId, vpcCidr, newVPC.TenantRegion)

	time.Sleep(time.Second * 60)
	urlInfo = w.URLInfoMap["getAwsVpcList"]

	getAwsVpcListResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, pathparam, nil)
	w.Reporter.StepReport(fmt.Sprintf("get Aws Vpc list and check vpc status is active?, getAwsVpcListResp:%s",
		getAwsVpcListResp.JSON().Raw()), func() {
		l4g.Info("get Aws Vpc list, getAwsVpcListResp is: %s", getAwsVpcListResp.JSON().Raw())
		w.WebRequestInfo.CheckAwsVPCWithRegion(getAwsVpcListResp, newVPC.TenantRegion)
	})

	total, _ := getAwsVpcListResp.JSON().Path("$.total").Raw().(float64)
	rel := w.checkVpcConnect(newVPC.TenantRegion)
	w.Reporter.StepReport(fmt.Sprintf("vpc connect result: %t", rel), func() {
		assert.True(w.Reporter.T, rel)
	})
	return int(total), id
}

func (w *WebE2ECase) createGCPVpcPeeringUntilActive() (int, string) {
	orgId := w.WebRequestInfo.User.OrgId
	projectId := w.WebRequestInfo.User.ProjectId

	pathparam := map[string]string{"org_id": orgId, "project_id": projectId}
	l4g.Info("begin delete vpcPeering")
	peerName := "zm-peering-test"
	w.WebRequestInfo.DelGCPVpcPeering(peerName)

	//创建VPC
	newVPC := w.WebRequestInfo.NewGCPVPC()
	urlInfo := w.URLInfoMap["addGcpVpc"]
	addGpcVpcResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, newVPC, pathparam, nil)
	l4g.Info("add gcp Vpc, addGpcVpcResp is: %s", addGpcVpcResp.JSON().Raw())
	tidbProjectId := addGpcVpcResp.JSON().Path("$.project_id").String().Raw()
	id := addGpcVpcResp.JSON().Path("$.id").String().Raw()
	w.Reporter.StepReport(fmt.Sprintf("add gcp Vpc, body:%v, pathParam:%s, addGpcVpcResp:%s", newVPC, pathparam, addGpcVpcResp.JSON().Raw()),
		func() {
			addGpcVpcResp.Status(http.StatusOK).JSON().Object().Keys().Contains("project_id")
			addGpcVpcResp.JSON().Path("$.base_resp.err_code").IsEqual("0")
		})

	if addGpcVpcResp.JSON().Path("$.base_resp.err_code").String().Raw() != "0" {
		return 1, ""
	}

	peerNetwork := addGpcVpcResp.JSON().Path("$.network_name").String().Raw()

	l4g.Info("begin add vpcPeering")
	w.WebRequestInfo.CeateGCPVpcPeering(peerName, tidbProjectId, peerNetwork)

	//查询VPC
	vpcPathParam := map[string]string{"org_id": orgId, "project_id": projectId, "id": id}
	var getGcpVpcResp *httpexpect.Response
	urlInfo = w.URLInfoMap["getGcpVpcInfo"]
	for round := 0; round <= 10; round += 1 {
		time.Sleep(time.Second * 60)
		getGcpVpcResp = w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, vpcPathParam, nil)
		if getGcpVpcResp.JSON().Path("$.status").String().Raw() == "active" {
			break
		}

	}

	//查询VPC列表
	time.Sleep(time.Second * 60)
	urlInfo = w.URLInfoMap["getGcpVpc"]

	getGcpVpcListResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, pathparam, nil)
	w.Reporter.StepReport(fmt.Sprintf("get gcp Vpc list and check vpc status is active?, "+
		"getGcpVpcListResp:%s", getGcpVpcListResp.JSON().Raw()),
		func() {
			w.WebRequestInfo.CheckGcpVPC(getGcpVpcListResp)
		})

	l4g.Info("get gcp Vpc list, getGcpVpcListResp is: %s", getGcpVpcListResp.JSON().Raw())
	total, _ := getGcpVpcListResp.JSON().Path("$.total").Raw().(float64)

	//获取endpoint
	rel := w.checkVpcConnect("")
	w.Reporter.StepReport(fmt.Sprintf("vpc connect result: %t", rel), func() {
		assert.True(w.Reporter.T, rel)
	})
	return int(total), id
}

func (w *WebE2ECase) checkVpcConnect(tenantRegion string) bool {
	orgId := w.WebRequestInfo.User.OrgId
	projectId := w.WebRequestInfo.User.ProjectId
	clusterId := w.WebRequestInfo.Cluster.ClusterId
	//获取endpoint
	var getConnectionResp *httpexpect.Response
	connectionPathParam := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId}
	/*connectionResp := dbassRequestInfo.DbassRequest(t, "connection", nil, connectionPathParam, nil, nil)
	l4g.Info("get privte endpoint, body is: %+v, pathParam is: %s, getClusterInfoResp is %s", nil, connectionPathParam, connectionResp.JSON().Raw())
	allure.Step(allure.Description(fmt.Sprintf("get privte endpoint, pathParam is: %s, getClusterInfoResp is %s", connectionPathParam, connectionResp.JSON().Raw())),
		allure.Action(func() {
			connectionResp.Status(StatusOK)
		}))*/

	urlInfo := w.URLInfoMap["getConnection"]
	for round := 0; round <= 5; round += 1 {
		time.Sleep(time.Second * 60)
		getConnectionResp = w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, connectionPathParam, nil)
		l4g.Info("getConnectionResp, body is: %+v, pathParam is: %s, getClusterInfoResp is %s", nil, connectionPathParam, getConnectionResp.JSON().Raw())
		if getConnectionResp.JSON().Path("$.status").String().Raw() == "NORMAL" {
			break
		}

	}
	vpcEndpoint := getConnectionResp.JSON().Path("$.domain").String().Raw()

	w.Reporter.StepReport(fmt.Sprintf("check vpcEndpoint, vpcEndpoint is %s, getConnectionResp:%s", vpcEndpoint, getConnectionResp.JSON().Raw()),
		func() {
			getConnectionResp.JSON().Path("$.domain").String().NotEmpty()
		})
	if vpcEndpoint == "" {
		return false
	}
	result := w.WebRequestInfo.CheckConnectTiDBInVMWithRegion(vpcEndpoint, "root", tenantRegion)
	return result

}

func (w *WebE2ECase) deleteVpcPeering(id string) {
	orgId := w.WebRequestInfo.User.OrgId
	projectId := w.WebRequestInfo.User.ProjectId

	delPathParam := map[string]string{"org_id": orgId, "project_id": projectId, "id": id}
	urlInfo := w.URLInfoMap["delAwsVpc"]
	if w.WebRequestInfo.Cluster.Provider == ProductModel.GCP {
		urlInfo = w.URLInfoMap["delGcpVpc"]
	}
	delVpcResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, delPathParam, nil)
	l4g.Info("del Vpc list, delVpcResp is: %s", delVpcResp.JSON().Raw())
	w.Reporter.StepReport(fmt.Sprintf("del Vpc list, delAwsVpcResp:%s", delVpcResp.JSON().Raw()), func() {
		delVpcResp.Status(http.StatusOK)
	})
}

func (w *WebE2ECase) addAuditAuth() {
	orgId := w.WebRequestInfo.User.OrgId
	projectId := w.WebRequestInfo.User.ProjectId
	clusterId := w.WebRequestInfo.Cluster.ClusterId
	provider := w.WebRequestInfo.Cluster.Provider

	clusterPathParam := map[string]string{"org_id": orgId, "project_id": projectId, "cluster_id": clusterId}
	//查询cluster的role_arn
	urlInfo := w.URLInfoMap["getDataIngestionProfile"]
	res := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, nil, clusterPathParam, nil)
	l4g.Info("add audit auth res  is : %s", res.JSON().Raw())
	if provider == "aws" {
		//获取aws的externalId
		accountId := res.JSON().Path("$.aws_account_id").String().Raw()
		externalId := res.JSON().Path("$.aws_external_id").String().Raw()
		w.WebRequestInfo.UpdateAuditLogS3Policy(accountId, externalId)

	} else {
		//获取gcp的account id，加入gcsBucketUrl的权限中
		accountId := res.JSON().Path("$.gcp_account_id").String().Raw()
		w.WebRequestInfo.PutGcpAuditLogBucketPolicy(accountId)
	}
}

func (w *WebE2ECase) CheckDedicatedDashboard() {
	orgId := w.WebRequestInfo.User.OrgId
	clusterId := w.WebRequestInfo.Cluster.ClusterId
	//slow query
	endTime := time.Now().Unix()
	startTime := endTime - 30*60
	clusterPathParam := map[string]string{"org_id": orgId, "cluster_id": clusterId}
	queryParam := map[string]string{
		"begin_time": strconv.FormatInt(startTime, 10),
		"end_time":   strconv.FormatInt(endTime, 10),
		"desc":       "true",
		"fields":     "query,timestamp,query_time,memory_max,process_keys,user,db",
		"limit":      "100",
		"orderBy":    "query_time"}
	urlInfo := w.URLInfoMap["getSlowQuery"]
	slowQueryResp := w.WebRequestInfo.DoWebAPIRequest(urlInfo.UrlPath, urlInfo.UrlMethod, queryParam, clusterPathParam, nil)
	w.Reporter.StepReport(fmt.Sprintf("get slow query param is %s, status code is %d", queryParam, slowQueryResp.Raw().StatusCode),
		func() {
			slowQueryResp.Status(http.StatusOK)
		})

	//sql statement
	w.CheckClusterStatement()

	//Key Visualizer
	w.CheckClusterKeyVisual()
}

func (w *WebE2ECase) GetAllProjects(orgId string) *models.CentralProjects {
	// get project name
	type queryParam struct {
		Page     int `url:"page"`
		Per_page int `url:"per_page"`
	}
	param := queryParam{1, 100}
	projectPathparam := map[string]string{"org_id": orgId}
	getProjectNameResp := w.WebRequestInfo.DoWebAPIRequestByUrlInfo(w.URLInfoMap["listProjects"], nil, projectPathparam, param)
	data := getProjectNameResp.JSON().Raw()
	var projects = &models.CentralProjects{}
	//var index = 0
	resByre, resByteErr := json.Marshal(data)
	if resByteErr == nil {
		jsonRes := json.Unmarshal(resByre, &projects)
		if jsonRes == nil {
			return projects
		} else {
			l4g.Error("GetProjectName Unmarshal error: %s", jsonRes)
		}
	}
	return nil
}

func getCIDRArray(provider string) []string {
	prefixes := []string{"/19", "/20"}
	ranges := []string{"10.250.0.0/16", "172.16.0.0/16", "172.31.0.0/16"}
	if provider == ProductModel.AWS {
		prefixes = append(prefixes, "/16", "/17", "/18", "/21", "/22", "/23")
		ranges = append(ranges, "192.168.0.0/16")
	}
	rangeIndex := rand.Intn(len(ranges))
	_, ipnet, _ := net.ParseCIDR(ranges[rangeIndex])
	cidrArray := make([]string, len(prefixes))
	for index, prefix := range prefixes {
		cidrArray[index] = ipnet.IP.String() + prefix
	}
	return cidrArray
}

func generateRandomCidr() string {
	prefixes := []string{"/16", "/17", "/18", "/19", "/20"}
	ranges := []string{"10.250.0.0/16", "172.16.0.0/12", "192.168.0.0/16"}

	rangeIndex := rand.Intn(len(ranges))
	_, ipnet, _ := net.ParseCIDR(ranges[rangeIndex])
	prefixIndex := rand.Intn(len(prefixes))
	prefix := prefixes[prefixIndex]
	return ipnet.IP.String() + prefix
}

func getAllCIDRTest() []string {
	start := 16
	len := 5
	cidrList := make([]string, 0, len) // 创建长度为 0、容量为 len 的切片
	for i := start; i < start+len; i++ {
		cidr := fmt.Sprintf("172.%d.0.0/16", i)
		cidrList = append(cidrList, cidr)
	}
	return cidrList
}
