package tests

import (
	"fmt"
	"sort"
	"strings"
	"testing"
	"time"

	"github.com/pingcap/dbaas/billing2/utils/tests/datainit"

	"github.com/dlclark/regexp2"
	"github.com/pingcap/dbaas/billing2/config"
	"github.com/pingcap/dbaas/billing2/constant"
	"github.com/pingcap/dbaas/billing2/db"
	"github.com/pingcap/dbaas/billing2/db/entity"
	"github.com/pingcap/dbaas/billing2/forms"
	"github.com/pingcap/dbaas/billing2/handler/infrahandler"
	"github.com/pingcap/dbaas/billing2/model/billing"
	"github.com/pingcap/dbaas/billing2/model/marketing"
	"github.com/pingcap/dbaas/billing2/model/marketing/unit_filter"
	"github.com/pingcap/dbaas/billing2/model/migrate"
	"github.com/pingcap/dbaas/billing2/model/payment/spend_limit"
	"github.com/pingcap/dbaas/billing2/utils/tests"
	"github.com/pingcap/dbaas/billing2/utils/timeutils"
	"github.com/pingcap/dbaas/billing2/utils/transformer"
	"github.com/shopspring/decimal"
	"github.com/stretchr/testify/mock"
	"github.com/stretchr/testify/suite"
	"gorm.io/gorm/clause"
)

type MigrateTestSuite struct {
	tests.BillingTestSuite
}

func TestMigrateSuite(t *testing.T) {
	suite.Run(t, new(MigrateTestSuite))
}
func (suite *MigrateTestSuite) TestCreateNewPackages() {
	assert := suite.Assert()
	migrateModel := &migrate.MigrateModel{}
	assert.NoError(migrateModel.CreateNewPackages())
	packages, err := (&billing.PackageModel{}).GetAllPackages()
	assert.NoError(err)
	assert.Len(packages, 3)
	assert.Equal(packages[0].Description, "POC Package")
	assert.Equal(packages[1].Description, "OnDemand Package")
	assert.Equal(packages[2].Description, "DevTier Package")
}

func (suite *MigrateTestSuite) TestUpdateDataTransferCategory() {
	assert := suite.Assert()
	migrateModel := &migrate.MigrateModel{}

	assert.NoError(migrateModel.CreateSystemSKU())
	assert.NoError(migrateModel.UpdateDataTransferCategory())
	unitModel := &billing.UnitModel{}
	info, err := unitModel.GetUnit("network-traffic:all")
	assert.NoError(err)
	assert.Equal(info.Category, "Data Transfer Cost - Load Balancing")
}

func (suite *MigrateTestSuite) TestNewSpendLimitAlertThreshold() {
	assert := suite.Assert()
	var err error
	err = (&migrate.MigrateModel{}).NewSpendLimitAlertThreshold(db.GetDB())
	assert.NoError(err)
	var entities []entity.SpendLimitAlertThreshold
	err = entity.NewSpendLimitAlertThresholdQuerySet(db.GetDB()).BizTypeEq(entity.SpendLimitBizType_ServerlessCluster).All(&entities)
	assert.NoError(err)
	target := []string{"0.75", "0.9", "1"}
	sort.Slice(entities, func(i, j int) bool { return entities[i].Proportion.Cmp(entities[j].Proportion) < 0 })
	for i, ent := range entities {
		assert.Equal(decimal.RequireFromString(target[i]), ent.Proportion)
	}
}

func (suite *MigrateTestSuite) TestSetupAllCategoryItem() {
	assert := suite.Assert()
	var err error
	err = (&migrate.MigrateModel{}).SetupAllCategoryItem()
	assert.NoError(err)
	var entities []entity.CategoryItemShow
	err = entity.NewCategoryItemShowQuerySet(db.GetDB()).All(&entities)
	assert.NoError(err)
	//pp.Print(entities)
}

func (suite *MigrateTestSuite) TestServerlessSKUMigrate() {
	assert := suite.Assert()
	var err error
	migrateModel := migrate.MigrateModel{}
	err = migrateModel.MigrateServerlessUnitFilter()
	assert.Error(err)
	ufModel := &unit_filter.Model{}
	generalUnitFilter, err := (&unit_filter.Model{}).CreateUnitFilter(&forms.UnitFilter{
		UnitFilterSlim: forms.UnitFilterSlim{Name: "General", Description: "General"},
		General:        true,
	})
	assert.NoError(err)
	config.Get().Set(config.GeneralCreditTypeID, generalUnitFilter.FilterID)
	pattern := `serverless-\b(request-unit|row-storage|column-storage)\b:[\w\-]+:[\w\-]+$`
	name := constant.ServerlessTierTypeName
	_, err = ufModel.CreateUnitFilter(&forms.UnitFilter{
		UnitFilterSlim: forms.UnitFilterSlim{Name: name, Description: name, ParentID: config.Get().GetUint(config.GeneralCreditTypeID)},
		General:        false, UnitKeyPattern: pattern,
	})
	assert.NoError(err)
	err = migrateModel.MigrateServerlessUnitFilter()
	assert.NoError(err)
	err = migrateModel.MigrateUnitFilterPriority()
	assert.NoError(err)
	err = migrateModel.MigrateServerlessUnitFilter20250606()
	assert.NoError(err)

	ruSKU := "serverless-request-unit:aws:ap-southeast-1"
	rsSKU := "serverless-row-storage:aws:us-west-2"
	csSKU := "serverless-column-storage:aws:ap-northeast-1"
	//
	ruStarterSKU := "serverless-request-unit:aws:ap-southeast-1:starter"
	rsStarterSKU := "serverless-row-storage:aws:us-west-2:starter"
	csStarterSKU := "serverless-column-storage:aws:ap-northeast-1:starter"
	drsStarterSKU := "serverless-row-storage-dual-encryption:aws:us-west-2:starter"
	dcsStarterSKU := "serverless-column-storage-dual-encryption:aws:ap-northeast-1:starter"

	ruEssentialSKU := "serverless-request-capacity-unit:aws:ap-southeast-1:essential"
	rsEssentialSKU := "serverless-row-storage:aws:us-west-2:essential"
	csEssentialSKU := "serverless-column-storage:aws:ap-northeast-1:essential"
	drsEssentialSKU := "serverless-row-storage-dual-encryption:aws:us-west-2:essential"
	dcsEssentialSKU := "serverless-column-storage-dual-encryption:aws:ap-northeast-1:essential"

	var ru, rs, cs entity.UnitFilter
	var matched bool

	re := regexp2.MustCompile(pattern, regexp2.RE2)
	matched, err = re.MatchString(ruSKU)
	assert.NoError(err)
	assert.True(matched)
	matched, err = re.MatchString(ruStarterSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(csEssentialSKU)
	assert.NoError(err)
	assert.False(matched)

	err = entity.NewUnitFilterQuerySet(db.GetDB()).UniqueKeyEq(constant.ServerlessRUTypeName).One(&ru)
	assert.NoError(err)
	assert.Equal(constant.ServerlessRUPriority, ru.Priority)
	re = regexp2.MustCompile(ru.UnitKeyPattern, regexp2.RE2)
	matched, err = re.MatchString(ruSKU)
	assert.NoError(err)
	assert.True(matched)
	matched, err = re.MatchString(rsSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(csSKU)
	assert.NoError(err)
	assert.False(matched)

	err = entity.NewUnitFilterQuerySet(db.GetDB()).UniqueKeyEq(constant.ServerlessRowStorageTypeName).One(&rs)
	assert.Equal(constant.ServerlessRowStoragePriority, rs.Priority)
	assert.NoError(err)
	re = regexp2.MustCompile(rs.UnitKeyPattern, regexp2.RE2)
	matched, err = re.MatchString(ruSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(rsSKU)
	assert.NoError(err)
	assert.True(matched)
	matched, err = re.MatchString(csSKU)
	assert.NoError(err)
	assert.False(matched)

	err = entity.NewUnitFilterQuerySet(db.GetDB()).UniqueKeyEq(constant.ServerlessColStorageTypeName).One(&cs)
	assert.NoError(err)
	assert.Equal(constant.ServerlessColStoragePriority, cs.Priority)
	re = regexp2.MustCompile(cs.UnitKeyPattern, regexp2.RE2)
	matched, err = re.MatchString(ruSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(rsSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(csSKU)
	assert.NoError(err)
	assert.True(matched)

	var ruStarter, rsStarter, csStarter entity.UnitFilter

	err = entity.NewUnitFilterQuerySet(db.GetDB()).UniqueKeyEq(constant.ServerlessStarterRUTypeName).One(&ruStarter)
	assert.NoError(err)
	assert.Equal(constant.ServerlessStarterRUPriority, ruStarter.Priority)
	re = regexp2.MustCompile(ruStarter.UnitKeyPattern, regexp2.RE2)
	matched, err = re.MatchString(ruStarterSKU)
	assert.NoError(err)
	assert.True(matched)
	//false
	matched, err = re.MatchString(rsStarterSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(csStarterSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(ruSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(ruSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(ruEssentialSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(drsStarterSKU)
	assert.NoError(err)
	assert.False(matched)

	err = entity.NewUnitFilterQuerySet(db.GetDB()).UniqueKeyEq(constant.ServerlessStarterRowStorageTypeName).One(&rsStarter)
	assert.Equal(constant.ServerlessStarterRowStoragePriority, rsStarter.Priority)
	assert.NoError(err)
	re = regexp2.MustCompile(rsStarter.UnitKeyPattern, regexp2.RE2)
	matched, err = re.MatchString(ruStarterSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(rsStarterSKU)
	assert.NoError(err)
	assert.True(matched)
	matched, err = re.MatchString(drsStarterSKU)
	assert.NoError(err)
	assert.True(matched)
	//false
	matched, err = re.MatchString(csStarterSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(rsSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(rsEssentialSKU)
	assert.NoError(err)
	assert.False(matched)

	err = entity.NewUnitFilterQuerySet(db.GetDB()).UniqueKeyEq(constant.ServerlessStarterColStorageTypeName).One(&csStarter)
	assert.NoError(err)
	assert.Equal(constant.ServerlessStarterColStoragePriority, csStarter.Priority)
	re = regexp2.MustCompile(csStarter.UnitKeyPattern, regexp2.RE2)
	matched, err = re.MatchString(ruStarterSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(rsStarterSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(csStarterSKU)
	assert.NoError(err)
	assert.True(matched)
	matched, err = re.MatchString(dcsStarterSKU)
	assert.NoError(err)
	assert.True(matched)

	matched, err = re.MatchString(csSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(csEssentialSKU)
	assert.NoError(err)
	assert.False(matched)

	// Essential
	var ruEssential, rsEssential, csEssential entity.UnitFilter

	err = entity.NewUnitFilterQuerySet(db.GetDB()).UniqueKeyEq(constant.ServerlessEssentialRCUTypeName).One(&ruEssential)
	assert.NoError(err)
	assert.Equal(constant.ServerlessEssentialRCUPriority, ruEssential.Priority)
	re = regexp2.MustCompile(ruEssential.UnitKeyPattern, regexp2.RE2)
	matched, err = re.MatchString(ruEssentialSKU)
	assert.NoError(err)
	assert.True(matched)
	matched, err = re.MatchString(rsEssentialSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(csEssentialSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(ruStarterSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(ruSKU)
	assert.NoError(err)
	assert.False(matched)

	err = entity.NewUnitFilterQuerySet(db.GetDB()).UniqueKeyEq(constant.ServerlessEssentialRowStorageTypeName).One(&rsEssential)
	assert.Equal(constant.ServerlessEssentialRowStoragePriority, rsEssential.Priority)
	assert.NoError(err)
	re = regexp2.MustCompile(rsEssential.UnitKeyPattern, regexp2.RE2)
	matched, err = re.MatchString(ruEssentialSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(rsEssentialSKU)
	assert.NoError(err)
	assert.True(matched)
	matched, err = re.MatchString(drsEssentialSKU)
	assert.NoError(err)
	assert.True(matched)
	matched, err = re.MatchString(csEssentialSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(rsStarterSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(rsSKU)
	assert.NoError(err)
	assert.False(matched)

	err = entity.NewUnitFilterQuerySet(db.GetDB()).UniqueKeyEq(constant.ServerlessEssentialColStorageTypeName).One(&csEssential)
	assert.NoError(err)
	assert.Equal(constant.ServerlessEssentialColStoragePriority, csEssential.Priority)
	re = regexp2.MustCompile(csEssential.UnitKeyPattern, regexp2.RE2)
	matched, err = re.MatchString(ruEssentialSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(rsEssentialSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(csEssentialSKU)
	assert.NoError(err)
	assert.True(matched)
	matched, err = re.MatchString(dcsEssentialSKU)
	assert.NoError(err)
	assert.True(matched)
	matched, err = re.MatchString(csStarterSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(csSKU)
	assert.NoError(err)
	assert.False(matched)

	var tStarter, tEssential entity.UnitFilter
	err = entity.NewUnitFilterQuerySet(db.GetDB()).UniqueKeyEq(constant.ServerlessStarterTypeName).One(&tStarter)
	assert.NoError(err)
	assert.Equal(constant.ServerlessStarterTierPriority, tStarter.Priority)
	assert.Equal(ruStarter.ParentID, tStarter.ID)
	assert.Equal(rsStarter.ParentID, tStarter.ID)
	assert.Equal(csStarter.ParentID, tStarter.ID)
	re = regexp2.MustCompile(tStarter.UnitKeyPattern, regexp2.RE2)
	matched, err = re.MatchString(ruEssentialSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(ruSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(ruStarterSKU)
	assert.NoError(err)
	assert.True(matched)
	matched, err = re.MatchString(csStarterSKU)
	assert.NoError(err)
	assert.True(matched)
	matched, err = re.MatchString(rsStarterSKU)
	assert.NoError(err)
	assert.True(matched)

	err = entity.NewUnitFilterQuerySet(db.GetDB()).UniqueKeyEq(constant.ServerlessEssentialTypeName).One(&tEssential)
	assert.NoError(err)
	assert.Equal(constant.ServerlessEssentialPriority, tEssential.Priority)
	assert.Equal(ruEssential.ParentID, tEssential.ID)
	assert.Equal(rsEssential.ParentID, tEssential.ID)
	assert.Equal(csEssential.ParentID, tEssential.ID)

	re = regexp2.MustCompile(tEssential.UnitKeyPattern, regexp2.RE2)
	matched, err = re.MatchString(ruStarterSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(ruSKU)
	assert.NoError(err)
	assert.False(matched)
	matched, err = re.MatchString(ruEssentialSKU)
	assert.NoError(err)
	assert.True(matched)
	matched, err = re.MatchString(csEssentialSKU)
	assert.NoError(err)
	assert.True(matched)
	matched, err = re.MatchString(rsEssentialSKU)
	assert.NoError(err)
	assert.True(matched)

}

func (suite *MigrateTestSuite) TestMigrateRechargePlanUnitFilter() {
	var err error
	assert := suite.Assert()
	generalUnitFilter, err := (&unit_filter.Model{}).CreateUnitFilter(&forms.UnitFilter{
		UnitFilterSlim: forms.UnitFilterSlim{Name: "General", Description: "General"},
		General:        true,
	})
	assert.NoError(err)
	tenantID := uint(1)
	targets := 10
	for i := 0; i != targets; i++ {
		unitFilterReq := &forms.UnitFilter{
			UnitFilterSlim: forms.UnitFilterSlim{
				Name:     fmt.Sprintf("test-%d", i),
				Internal: true,
				ParentID: generalUnitFilter.FilterID,
			},
			General:        false,
			Region:         forms.UnitFilterALL,
			Provider:       forms.UnitFilterALL,
			Category:       forms.UnitFilterALL,
			UnitKeyPattern: ".*",
			Labels:         map[string]string{constant.ClusterLabelKey: fmt.Sprint(i + 1)},
		}
		uf, err := (&unit_filter.Model{}).CreateUnitFilter(unitFilterReq)
		assert.NoError(err)
		mainPlan := entity.RechargeCreditsPlan{
			Value:       decimal.NewFromInt(2),
			UnitFilters: transformer.UnitFiltersEntitiesFromUnitFilterSlimForm([]*forms.UnitFilterSlim{&uf.UnitFilterSlim}),
			Duration:    99 * 366 * 24 * time.Hour,
			StartDate:   timeutils.GetNow(),
			ExpiredDate: time.Date(2099, 12, 31, 0, 0, 0, 0, time.UTC),
		}
		err = mainPlan.Create(db.GetDB())
		assert.NoError(err)
		tenantPlan := entity.TenantRechargeCreditsPlan{
			TenantID:           tenantID,
			MainPlanID:         mainPlan.ID,
			StartDate:          timeutils.GetNow(),
			ExpiredDate:        time.Date(2099, 12, 31, 0, 0, 0, 0, time.UTC),
			NextCycleStartTime: timeutils.GetNow().Add(time.Hour * 24 * 31),
		}
		err = tenantPlan.Create(db.GetDB())
		assert.NoError(err)
		tp, err := (&marketing.RechargeCreditsModel{}).GetTenantRechargePlan(tenantPlan.ID)
		assert.NoError(err)
		assert.Len(tp.UnitFilters, 0)
	}
	err = (&migrate.MigrateModel{}).MigrateRechargePlanUnitFilter()
	assert.NoError(err)
	var tenantPlans []entity.TenantRechargeCreditsPlan
	err = entity.NewTenantRechargeCreditsPlanQuerySet(db.GetDB().Preload(clause.Associations)).All(&tenantPlans)
	assert.NoError(err)
	assert.Len(tenantPlans, targets)
	for _, tenantPlan := range tenantPlans {
		assert.Len(tenantPlan.UnitFilters, 1)
		mainPlan, err := (&marketing.RechargeCreditsModel{}).GetRechargePlan(tenantPlan.MainPlanID)
		assert.NoError(err)
		assert.Len(mainPlan.UnitFilters, 1)
		assert.Equal(mainPlan.UnitFilters[0].FilterID, tenantPlan.UnitFilters[0].ID)
	}
	err = (&migrate.MigrateModel{}).MigrateRechargePlanUnitFilter()
	assert.NoError(err)
}

type MockPOCInfraHandlerImpl struct {
	infrahandler.InfraHandler
	mock.Mock
}

func (*MockPOCInfraHandlerImpl) GetCluster(tenantID, clusterID uint) (ret *forms.Cluster, err error) {
	return &forms.Cluster{
		ID:         clusterID,
		Name:       constant.UnknownClusterName,
		TenantID:   tenantID,
		RegionName: "us-east-1",
	}, nil
}

func (suite *MigrateTestSuite) TestMigrateSpendLimitRechargePlanID() {
	var err error
	assert := suite.Assert()
	var rechargeModel = &marketing.RechargeCreditsModel{}
	rechargePlan, err := rechargeModel.CreateRechargePlan(&forms.RechargeCreditsPlan{
		Value: decimal.NewFromInt(5),
		Cycle: entity.RechargePlanCycle_Month,
		Rule: forms.RechargeCreditsPlanRule{
			FirstCycleStartedAt:   forms.FirstCycleStartedAt_RightNow,
			FirstCycleFinishedAt:  forms.FirstCycleFinishedAt_EndOfNaturalCycle,
			FirstCreditsConvertor: forms.FirstCreditsConvertor_Full,
		},
		StartDate:   timeutils.GetNow(),
		ExpiredDate: timeutils.GetNow().Add(time.Hour * 24),
		Internal:    true,
		Source:      entity.RechargeCreditsPlanSource_Web,
	})
	assert.NoError(err)
	spendLimitModel := &spend_limit.SpendLimitModel{}
	q1 := forms.SpendLimitSetting{
		Interval:  entity.SpendLimitInterval_Monthly,
		CostType:  entity.SpendLimitCostType_Total,
		Limit:     decimal.RequireFromString("0.5"),
		RangeType: entity.SpendLimitRangeType_Cluster,
		RangeID:   1,
		BizType:   entity.SpendLimitBizType_ServerlessCluster,
		BizData:   fmt.Sprintf("{\"invoice_limit\": \"0\", \"recharge_plan_id\": %d}", rechargePlan.PlanID),
	}
	datainit.CreateBillingConfig(uint(1), entity.BillingConfigType_DirectCustomer)
	s1, err := spendLimitModel.CreateSpendLimitSetting(1, &q1)
	assert.NoError(err)
	err = db.GetDB().Exec("INSERT INTO `recharge_credits_plans` (`id`, `created_at`, `updated_at`, `deleted_at`, `value`, `usage`, `note`, `rule`, `cycle`, `trigger`, `duration`, `start_date`, `expired_date`, `closed_at`, `internal`, `source`) VALUES" +
		"(500000, '2023-10-23 00:00:00.000', '2023-10-23 00:00:00.000', NULL, 6.000000000000000,  X'6D61726B6574696E67', X'75732D656173742D31', '{\"first_cycle_started_at\": \"right_now\", \"first_credits_convertor\": \"full\", \"first_cycle_finished_at\": \"end_of_natural_cycle\"}', X'6D6F6E7468', NULL, 0, '2023-01-01 00:00:00.000', '2099-12-31 23:59:59.000', NULL, 1, X'776562'),		  " +
		"(500001, '2023-10-23 00:00:00.000', '2023-10-23 00:00:00.000', NULL, 6.000000000000000,  X'6D61726B6574696E67', X'75732D776573742D32', '{\"first_cycle_started_at\": \"right_now\", \"first_credits_convertor\": \"full\", \"first_cycle_finished_at\": \"end_of_natural_cycle\"}', X'6D6F6E7468', NULL, 0, '2023-01-01 00:00:00.000', '2099-12-31 23:59:59.000', NULL, 1, X'776562'),		  " +
		"(500002, '2023-10-23 00:00:00.000', '2023-10-23 00:00:00.000', NULL, 7.200000000000000,  X'6D61726B6574696E67', X'65752D63656E7472616C2D31', '{\"first_cycle_started_at\": \"right_now\", \"first_credits_convertor\": \"full\", \"first_cycle_finished_at\": \"end_of_natural_cycle\"}', X'6D6F6E7468', NULL, 0, '2023-01-01 00:00:00.000', '2099-12-31 23:59:59.000', NULL, 1, X'776562'),	  " +
		"(500003, '2023-10-23 00:00:00.000', '2023-10-23 00:00:00.000', NULL, 7.200000000000000,  X'6D61726B6574696E67', X'61702D736F757468656173742D31', '{\"first_cycle_started_at\": \"right_now\", \"first_credits_convertor\": \"full\", \"first_cycle_finished_at\": \"end_of_natural_cycle\"}', X'6D6F6E7468', NULL, 0, '2023-01-01 00:00:00.000', '2099-12-31 23:59:59.000', NULL, 1, X'776562')," +
		"(500004, '2023-10-23 00:00:00.000', '2023-10-23 00:00:00.000', NULL, 7.200000000000000,  X'6D61726B6574696E67', X'61702D6E6F727468656173742D31', '{\"first_cycle_started_at\": \"right_now\", \"first_credits_convertor\": \"full\", \"first_cycle_finished_at\": \"end_of_natural_cycle\"}', X'6D6F6E7468', NULL, 0, '2023-01-01 00:00:00.000', '2099-12-31 23:59:59.000', NULL, 1, X'776562');",
	).Error
	assert.NoError(err)
	q2 := forms.SpendLimitSetting{
		Interval:  entity.SpendLimitInterval_Monthly,
		CostType:  entity.SpendLimitCostType_Total,
		Limit:     decimal.RequireFromString("0.5"),
		RangeType: entity.SpendLimitRangeType_Cluster,
		RangeID:   2,
		BizType:   entity.SpendLimitBizType_ServerlessCluster,
		BizData:   fmt.Sprintf("{\"invoice_limit\": \"0\", \"recharge_plan_id\": %d}", 500001),
	}
	s2, err := spendLimitModel.CreateSpendLimitSetting(1, &q2)
	assert.NoError(err)
	bizData, err := spendLimitModel.UnmarshallServerlessBizData(s2.BizData)
	assert.NoError(err)
	assert.Equal(uint(500001), bizData.RechargePlanID)
	q3 := forms.SpendLimitSetting{
		Interval:  entity.SpendLimitInterval_Monthly,
		CostType:  entity.SpendLimitCostType_Total,
		Limit:     decimal.RequireFromString("0.5"),
		RangeType: entity.SpendLimitRangeType_Cluster,
		RangeID:   3,
		BizType:   entity.SpendLimitBizType_ServerlessCluster,
		BizData:   fmt.Sprintf("{\"invoice_limit\": \"1\", \"recharge_plan_id\": %d}", 0),
	}
	s3, err := spendLimitModel.CreateSpendLimitSetting(1, &q3)
	assert.NoError(err)
	mockInfra := &MockPOCInfraHandlerImpl{}
	infrahandler.Set(mockInfra)
	err = (&migrate.MigrateModel{}).MigrateSpendLimitRechargePlanID()
	assert.NoError(err)
	s1New, err := spendLimitModel.GetSpendLimitInfo(1, s1.SpendLimitSettingID)
	assert.NoError(err)
	bizData, err = spendLimitModel.UnmarshallServerlessBizData(s1New.BizData)
	assert.NoError(err)
	assert.Equal(uint(500000), bizData.RechargePlanID)
	tenantRechargePlan, err := rechargeModel.GetTenantRechargePlan(bizData.TenantRechargePlanID)
	assert.NoError(err)
	assert.Equal(uint(500000), tenantRechargePlan.MainPlanID)

	s2New, err := spendLimitModel.GetSpendLimitInfo(1, s2.SpendLimitSettingID)
	assert.NoError(err)
	bizData, err = spendLimitModel.UnmarshallServerlessBizData(s2New.BizData)
	assert.NoError(err)
	assert.Equal(uint(500001), bizData.RechargePlanID)
	tenantRechargePlan, err = rechargeModel.GetTenantRechargePlan(bizData.TenantRechargePlanID)
	assert.NoError(err)
	assert.Equal(uint(500001), tenantRechargePlan.MainPlanID)

	s3New, err := spendLimitModel.GetSpendLimitInfo(1, s3.SpendLimitSettingID)
	assert.NoError(err)
	bizData, err = spendLimitModel.UnmarshallServerlessBizData(s3New.BizData)
	assert.NoError(err)
	assert.Equal(uint(0), bizData.RechargePlanID)
	assert.Equal(uint(0), bizData.TenantRechargePlanID)
}

func (suite *MigrateTestSuite) TestMigrateDataTrafficUnitFilters() {
	assert := suite.Assert()
	sql := "INSERT INTO `credit_types` (`id`, `created_at`, `updated_at`, `deleted_at`, `name`, `description`, `general`, `provider`, `region`, `category`, `unit_key_pattern`, `labels`, `parent_id`, `internal`, `unique_key`, `priority`)\nVALUES\n\t(1, NULL, '2023-09-01 10:17:30.990', NULL, X'47656E6572616C2050726F64756374', X'47656E6572616C2050726F64756374', 0, X'616C6C', X'616C6C', X'616C6C', X'5E283F21737570706F72742D706C616E292E2A24', NULL, NULL, 0, X'47656E6572616C', 100000),\n\t(23, '2023-01-03 05:50:33.005', '2023-04-18 01:58:19.749', NULL, X'44617461205472616E73666572', X'44617461205472616E73666572', 0, X'616C6C', X'616C6C', X'616C6C', X'5E5C62286E6574776F726B5C2D74726166666963295C622E2A', 'null', 1, 1, X'44617461205472616E73666572', NULL),\n\t(24, '2023-01-03 05:50:33.011', '2023-04-18 01:58:19.749', NULL, X'44617461205472616E73666572202843726F737320526567696F6E29', X'44617461205472616E73666572202843726F737320526567696F6E29', 0, X'616C6C', X'616C6C', X'616C6C', X'6E6574776F726B5C2D747261666669633A5B5C775C2D5D2B3A63726F73735F726567696F6E24', 'null', 23, 1, X'44617461205472616E73666572202843726F737320526567696F6E29', NULL),\n\t(25, '2023-01-03 05:50:33.017', '2023-04-18 01:58:19.749', NULL, X'44617461205472616E73666572202853616D6520526567696F6E29', X'44617461205472616E73666572202853616D6520526567696F6E29', 0, X'616C6C', X'616C6C', X'616C6C', X'6E6574776F726B5C2D747261666669633A5B5C775C2D5D2B3A63726F73735F617A24', 'null', 23, 1, X'44617461205472616E73666572202853616D6520526567696F6E29', NULL),\n\t(26, '2023-01-03 05:50:33.023', '2023-04-18 01:58:19.749', NULL, X'44617461205472616E736665722028496E7465726E657429', X'44617461205472616E736665722028496E7465726E657429', 0, X'616C6C', X'616C6C', X'616C6C', X'6E6574776F726B5C2D747261666669633A5B5C775C2D5D2B3A696E7465726E657424', 'null', 23, 1, X'44617461205472616E736665722028496E7465726E657429', NULL),\n\t(27, '2023-01-03 05:50:33.029', '2023-04-18 01:58:19.749', NULL, X'44617461205472616E7366657220284C6F61642042616C616E63696E6729', X'44617461205472616E7366657220284C6F61642042616C616E636529', 0, X'616C6C', X'616C6C', X'616C6C', X'6E6574776F726B5C2D747261666669633A5B5C775C2D5D2B3A6C6224', 'null', 23, 1, X'44617461205472616E7366657220284C6F61642042616C616E63696E6729', NULL);\n"
	assert.NoError(db.GetDB().Exec(sql).Error)
	units := strings.Split("backup-dual-region-replication:aws:ap-northeast-1\tData Transfer Cost - AWS Cross Region\nbackup-dual-region-replication:aws:ap-northeast-3\tData Transfer Cost - AWS Cross Region\nbackup-dual-region-replication:aws:ap-southeast-1\tData Transfer Cost - AWS Cross Region\nbackup-dual-region-replication:aws:ap-southeast-2\tData Transfer Cost - AWS Cross Region\nbackup-dual-region-replication:aws:eu-central-1\tData Transfer Cost - AWS Cross Region\nbackup-dual-region-replication:aws:us-east-1\tData Transfer Cost - AWS Cross Region\nbackup-dual-region-replication:aws:us-west-2\tData Transfer Cost - AWS Cross Region\nbackup-dual-region-replication:gcp:asia-east1\tData Transfer Cost - GCP Cross Region\nbackup-dual-region-replication:gcp:asia-northeast1\tData Transfer Cost - GCP Cross Region\nbackup-dual-region-replication:gcp:asia-northeast2\tData Transfer Cost - GCP Cross Region\nbackup-dual-region-replication:gcp:asia-southeast1\tData Transfer Cost - GCP Cross Region\nbackup-dual-region-replication:gcp:us-central1\tData Transfer Cost - GCP Cross Region\nbackup-dual-region-replication:gcp:us-west1\tData Transfer Cost - GCP Cross Region\ndm-internet:aws:all\tData Transfer Cost - AWS Internet\ndm-internet:gcp:all\tData Transfer Cost - GCP Internet\ndm-nat:aws:ap-northeast-1\tData Transfer Cost - AWS DM NAT Gateway Cost\ndm-nat:aws:ap-northeast-2\tData Transfer Cost - AWS DM NAT Gateway Cost\ndm-nat:aws:ap-south-1\tData Transfer Cost - AWS DM NAT Gateway Cost\ndm-nat:aws:ap-southeast-1\tData Transfer Cost - AWS DM NAT Gateway Cost\ndm-nat:aws:eu-central-1\tData Transfer Cost - AWS DM NAT Gateway Cost\ndm-nat:aws:us-east-1\tData Transfer Cost - AWS DM NAT Gateway Cost\ndm-nat:aws:us-west-2\tData Transfer Cost - AWS DM NAT Gateway Cost\ndm-nat:gcp:all\tData Transfer Cost - GCP DM NAT Gateway Cost\ndm-network:aws\tData Transfer Cost - AWS Same Region\ndm-network:gcp\tData Transfer Cost - GCP Same Region\nnetwork-traffic:all\tData Transfer Cost - Load Balancing\nnetwork-traffic:aws:cross_az\tData Transfer Cost - AWS Same Region\nnetwork-traffic:aws:s-east-1:cross_region\tData Transfer Cost - AWS Cross Region\nnetwork-traffic:aws:internet\tData Transfer Cost - AWS Internet\nnetwork-traffic:aws:s-east-1:lb\tData Transfer Cost - AWS Load Balancing\nnetwork-traffic:gcp:asia-southeast1:cross_az\tData Transfer Cost - GCP Same Region\nnetwork-traffic:gcp:asia-southeast1:cross_region\tData Transfer Cost - GCP Cross Region\nnetwork-traffic:gcp:asia-southeast1:internet\tData Transfer Cost - GCP Internet\nnetwork-traffic:gcp:lb\tData Transfer Cost - GCP Load Balancing\npl-network:aws\tData Transfer Cost - AWS Same Region\nvpcpeering:aws:CrossAZ\tData Transfer Cost - AWS Same Region\nvpcpeering:aws:CrossRegion\tData Transfer Cost - AWS Cross Region", "\n")
	unitCatMap := make(map[string]string, len(units))
	for _, uc := range units {
		ucSlice := strings.Split(uc, "\t")
		unit := ucSlice[0]
		cat := ucSlice[1]
		unitCatMap[unit] = cat
	}
	invalidUnits := strings.Split("ApiAuto-QA-unit-wrong\nLegacyBackupUsage\nLegacyDataTransferUsage\nLegacyNodeUsage\nbackup-dual-region-storage:aws:ap-northeast-1\nbackup-dual-region-storage:aws:ap-northeast-3\nbackup-dual-region-storage:aws:ap-southeast-1\nbackup-dual-region-storage:aws:ap-southeast-2\nbackup-dual-region-storage:aws:eu-central-1\nbackup-dual-region-storage:aws:us-east-1\nbackup-dual-region-storage:aws:us-west-2\nbackup-dual-region-storage:gcp:asia-east1\nbackup-dual-region-storage:gcp:asia-northeast1\nbackup-dual-region-storage:gcp:asia-northeast2\nbackup-dual-region-storage:gcp:asia-southeast1\nbackup-dual-region-storage:gcp:us-central1\nbackup-dual-region-storage:gcp:us-west1\nbackup-replication:gcp:asia-northeast1\nbackup-replication:gcp:asia-northeast2\nbackup-replication:gcp:us-central1\nbackup-replication:gcp:us-west1\nbackup-storage:all\nbackup-storage:aws:ap-northeast-1\nbackup-storage:aws:ap-south-1\nbackup-storage:aws:ap-southeast-1\nbackup-storage:aws:ap-southeast-3\nbackup-storage:aws:eu-central-1\nbackup-storage:aws:us-east-1\nbackup-storage:aws:us-west-2\nbackup-storage:gcp:asia-east1\nbackup-storage:gcp:asia-northeast1\nbackup-storage:gcp:asia-northeast2\nbackup-storage:gcp:asia-southeast1\nbackup-storage:gcp:us-central1\nbackup-storage:gcp:us-west1\nbackup-volume-snapshot-storage:aws:ap-northeast-1\nbackup-volume-snapshot-storage:aws:ap-northeast-2\nbackup-volume-snapshot-storage:aws:ap-south-1\nbackup-volume-snapshot-storage:aws:ap-southeast-1\nbackup-volume-snapshot-storage:aws:eu-central-1\nbackup-volume-snapshot-storage:aws:us-east-1\nbackup-volume-snapshot-storage:aws:us-west-2\ndisk-iops:aws:ap-northeast-1:gp3\ndisk-iops:aws:ap-northeast-2:gp3\ndisk-iops:aws:ap-south-1:gp3\ndisk-iops:aws:ap-southeast-1:gp3\ndisk-iops:aws:eu-central-1:gp3\ndisk-iops:aws:us-east-1:gp3\ndisk-iops:aws:us-east-1:io2\ndisk-iops:aws:us-west-2:gp3\ndisk-iops:aws:us-west-2:io2\ndisk-storage:aws:ap-northeast-1:gp3\ndisk-storage:aws:ap-northeast-1:local-storage\ndisk-storage:aws:ap-northeast-2:gp2\ndisk-storage:aws:ap-northeast-2:gp3\ndisk-storage:aws:ap-northeast-2:local-storage\ndisk-storage:aws:ap-south-1:gp3\ndisk-storage:aws:ap-south-1:local-storage\ndisk-storage:aws:ap-southeast-1:gp3\ndisk-storage:aws:ap-southeast-1:local-storage\ndisk-storage:aws:eu-central-1:gp3\ndisk-storage:aws:eu-central-1:local-storage\ndisk-storage:aws:us-east-1:gp2\ndisk-storage:aws:us-east-1:gp3\ndisk-storage:aws:us-east-1:io2\ndisk-storage:aws:us-east-1:local-storage\ndisk-storage:aws:us-west-2:gp2\ndisk-storage:aws:us-west-2:gp3\ndisk-storage:aws:us-west-2:io2\ndisk-storage:aws:us-west-2:local-storage\ndisk-storage:gcp:asia-east1:local-storage\ndisk-storage:gcp:asia-east1:pd-ssd\ndisk-storage:gcp:asia-northeast1:local-storage\ndisk-storage:gcp:asia-northeast1:pd-ssd\ndisk-storage:gcp:asia-northeast2:local-storage\ndisk-storage:gcp:asia-northeast2:pd-ssd\ndisk-storage:gcp:asia-southeast1:local-storage\ndisk-storage:gcp:asia-southeast1:pd-ssd\ndisk-storage:gcp:us-central1:local-storage\ndisk-storage:gcp:us-central1:pd-ssd\ndisk-storage:gcp:us-west1:local-storage\ndisk-storage:gcp:us-west1:pd-ssd\ndisk-throughput:aws:ap-northeast-1:gp3\ndisk-throughput:aws:ap-northeast-2:gp3\ndisk-throughput:aws:ap-south-1:gp3\ndisk-throughput:aws:ap-southeast-1:gp3\ndisk-throughput:aws:eu-central-1:gp3\ndisk-throughput:aws:us-east-1:gp3\ndisk-throughput:aws:us-east-1:io2\ndisk-throughput:aws:us-west-2:gp3\ndisk-throughput:aws:us-west-2:io2\ndm-rcu:aws:ap-northeast-1\ndm-rcu:aws:ap-south-1\ndm-rcu:aws:ap-southeast-1\ndm-rcu:aws:eu-central-1\ndm-rcu:aws:us-east-1\ndm-rcu:aws:us-west-2\ndm-rcu:gcp:asia-east1\ndm-rcu:gcp:asia-northeast1\ndm-rcu:gcp:asia-northeast2\ndm-rcu:gcp:asia-southeast1\ndm-rcu:gcp:us-central1\ndm-rcu:gcp:us-east4\ndm-rcu:gcp:us-west1\ndm-rcu:gcp:us-west2\neda-network-bytes:aws:us-west-2\neda-requests:aws:us-west-2\neda-tokens:aws:us-west-2\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:c5.2xlarge\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:c5.4xlarge\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:c5.xlarge\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:c6g.2xlarge\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:c6g.4xlarge\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:c6g.xlarge\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:m5.2xlarge\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:m5.4xlarge\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:m5.large\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:m5.xlarge\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:m6g.2xlarge\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:m6g.4xlarge\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:m6g.large\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:m6g.xlarge\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:r5.2xlarge\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:r5.4xlarge\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:r6g.2xlarge\nnode:aws:ap-northeast-1:DEPLOY_TYPE_DEDICATED:r6g.4xlarge\nnode:aws:ap-northeast-1:DEPLOY_TYPE_SHARED:aws_freetier_10\nnode:aws:ap-northeast-2:DEPLOY_TYPE_DEDICATED:c5.2xlarge\nnode:aws:ap-northeast-2:DEPLOY_TYPE_DEDICATED:c5.4xlarge\nnode:aws:ap-northeast-2:DEPLOY_TYPE_DEDICATED:c5.xlarge\nnode:aws:ap-northeast-2:DEPLOY_TYPE_DEDICATED:c6g.2xlarge\nnode:aws:ap-northeast-2:DEPLOY_TYPE_DEDICATED:c6g.4xlarge\nnode:aws:ap-northeast-2:DEPLOY_TYPE_DEDICATED:c6g.xlarge\nnode:aws:ap-northeast-2:DEPLOY_TYPE_DEDICATED:i3.2xlarge\nnode:aws:ap-northeast-2:DEPLOY_TYPE_DEDICATED:i3.4xlarge\nnode:aws:ap-northeast-2:DEPLOY_TYPE_DEDICATED:m5.2xlarge\nnode:aws:ap-northeast-2:DEPLOY_TYPE_DEDICATED:m6g.2xlarge\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:c5.2xlarge\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:c5.4xlarge\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:c5.xlarge\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:c6g.2xlarge\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:c6g.4xlarge\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:c6g.xlarge\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:m5.2xlarge\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:m5.4xlarge\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:m5.large\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:m5.xlarge\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:m6g.2xlarge\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:m6g.4xlarge\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:m6g.large\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:m6g.xlarge\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:r5.2xlarge\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:r5.4xlarge\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:r6g.2xlarge\nnode:aws:ap-south-1:DEPLOY_TYPE_DEDICATED:r6g.4xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:c5.2xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:c5.4xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:c5.xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:c6g.2xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:c6g.4xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:c6g.xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:m5.2xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:m5.4xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:m5.large\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:m5.xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:m6g.2xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:m6g.4xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:m6g.large\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:m6g.xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:r5.2xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:r5.4xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:r6g.2xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_DEDICATED:r6g.4xlarge\nnode:aws:ap-southeast-1:DEPLOY_TYPE_SHARED:aws_freetier_10\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:c5.2xlarge\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:c5.4xlarge\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:c5.xlarge\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:c6g.2xlarge\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:c6g.4xlarge\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:c6g.xlarge\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:m5.2xlarge\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:m5.4xlarge\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:m5.large\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:m5.xlarge\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:m6g.2xlarge\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:m6g.4xlarge\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:m6g.large\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:m6g.xlarge\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:r5.2xlarge\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:r5.4xlarge\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:r6g.2xlarge\nnode:aws:eu-central-1:DEPLOY_TYPE_DEDICATED:r6g.4xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:c5.2xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:c5.4xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:c5.xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:c6g.2xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:c6g.4xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:c6g.8xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:c6g.xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:i3.2xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:i3.4xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:m5.2xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:m5.4xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:m5.large\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:m5.xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:m6g.2xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:m6g.4xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:m6g.8xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:m6g.large\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:m6g.xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:r5.2xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:r5.4xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:r6g.2xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:r6g.4xlarge\nnode:aws:us-east-1:DEPLOY_TYPE_DEDICATED:t3.medium\nnode:aws:us-east-1:DEPLOY_TYPE_SHARED:aws_freetier_10\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:c5.2xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:c5.4xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:c5.xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:c6g.2xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:c6g.4xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:c6g.8xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:c6g.xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:c6i.8xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:i3.2xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:i3.4xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.2xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.4xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.large\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m5.xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6g.2xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6g.4xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6g.8xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6g.large\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6g.xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:m6i.8xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:r5.2xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:r5.4xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:r6g.2xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:r6g.4xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:r6g.8xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_DEDICATED:r6i.8xlarge\nnode:aws:us-west-2:DEPLOY_TYPE_SHARED:aws_freetier_10\nnode:gcp:asia-east1:DEPLOY_TYPE_DEDICATED:n1-standard-2\nnode:gcp:asia-east1:DEPLOY_TYPE_DEDICATED:n1-standard-4\nnode:gcp:asia-east1:DEPLOY_TYPE_DEDICATED:n2-custom-16-32768\nnode:gcp:asia-east1:DEPLOY_TYPE_DEDICATED:n2-highmem-16\nnode:gcp:asia-east1:DEPLOY_TYPE_DEDICATED:n2-highmem-8\nnode:gcp:asia-east1:DEPLOY_TYPE_DEDICATED:n2-standard-16\nnode:gcp:asia-east1:DEPLOY_TYPE_DEDICATED:n2-standard-2\nnode:gcp:asia-east1:DEPLOY_TYPE_DEDICATED:n2-standard-4\nnode:gcp:asia-east1:DEPLOY_TYPE_DEDICATED:n2-standard-8\nnode:gcp:asia-east1:DEPLOY_TYPE_DEDICATED:t2d-standard-16\nnode:gcp:asia-northeast1:DEPLOY_TYPE_DEDICATED:n1-standard-1\nnode:gcp:asia-northeast1:DEPLOY_TYPE_DEDICATED:n1-standard-2\nnode:gcp:asia-northeast1:DEPLOY_TYPE_DEDICATED:n1-standard-4\nnode:gcp:asia-northeast1:DEPLOY_TYPE_DEDICATED:n2-custom-16-32768\nnode:gcp:asia-northeast1:DEPLOY_TYPE_DEDICATED:n2-custom-8-16384\nnode:gcp:asia-northeast1:DEPLOY_TYPE_DEDICATED:n2-highmem-16\nnode:gcp:asia-northeast1:DEPLOY_TYPE_DEDICATED:n2-highmem-8\nnode:gcp:asia-northeast1:DEPLOY_TYPE_DEDICATED:n2-standard-16\nnode:gcp:asia-northeast1:DEPLOY_TYPE_DEDICATED:n2-standard-2\nnode:gcp:asia-northeast1:DEPLOY_TYPE_DEDICATED:n2-standard-4\nnode:gcp:asia-northeast1:DEPLOY_TYPE_DEDICATED:n2-standard-8\nnode:gcp:asia-northeast1:DEPLOY_TYPE_DEDICATED:t2d-standard-16\nnode:gcp:asia-northeast2:DEPLOY_TYPE_DEDICATED:n1-standard-2\nnode:gcp:asia-northeast2:DEPLOY_TYPE_DEDICATED:n1-standard-4\nnode:gcp:asia-northeast2:DEPLOY_TYPE_DEDICATED:n2-custom-16-32768\nnode:gcp:asia-northeast2:DEPLOY_TYPE_DEDICATED:n2-highmem-16\nnode:gcp:asia-northeast2:DEPLOY_TYPE_DEDICATED:n2-highmem-8\nnode:gcp:asia-northeast2:DEPLOY_TYPE_DEDICATED:n2-standard-16\nnode:gcp:asia-northeast2:DEPLOY_TYPE_DEDICATED:n2-standard-2\nnode:gcp:asia-northeast2:DEPLOY_TYPE_DEDICATED:n2-standard-4\nnode:gcp:asia-northeast2:DEPLOY_TYPE_DEDICATED:n2-standard-8\nnode:gcp:asia-northeast2:DEPLOY_TYPE_DEDICATED:t2d-standard-16\nnode:gcp:asia-southeast1:DEPLOY_TYPE_DEDICATED:n1-standard-2\nnode:gcp:asia-southeast1:DEPLOY_TYPE_DEDICATED:n1-standard-4\nnode:gcp:asia-southeast1:DEPLOY_TYPE_DEDICATED:n2-custom-16-32768\nnode:gcp:asia-southeast1:DEPLOY_TYPE_DEDICATED:n2-custom-8-16384\nnode:gcp:asia-southeast1:DEPLOY_TYPE_DEDICATED:n2-highmem-16\nnode:gcp:asia-southeast1:DEPLOY_TYPE_DEDICATED:n2-highmem-8\nnode:gcp:asia-southeast1:DEPLOY_TYPE_DEDICATED:n2-standard-16\nnode:gcp:asia-southeast1:DEPLOY_TYPE_DEDICATED:n2-standard-2\nnode:gcp:asia-southeast1:DEPLOY_TYPE_DEDICATED:n2-standard-4\nnode:gcp:asia-southeast1:DEPLOY_TYPE_DEDICATED:n2-standard-8\nnode:gcp:asia-southeast1:DEPLOY_TYPE_DEDICATED:t2d-standard-16\nnode:gcp:us-central1:DEPLOY_TYPE_DEDICATED:n1-standard-1\nnode:gcp:us-central1:DEPLOY_TYPE_DEDICATED:n1-standard-2\nnode:gcp:us-central1:DEPLOY_TYPE_DEDICATED:n1-standard-4\nnode:gcp:us-central1:DEPLOY_TYPE_DEDICATED:n2-custom-16-32768\nnode:gcp:us-central1:DEPLOY_TYPE_DEDICATED:n2-custom-8-16384\nnode:gcp:us-central1:DEPLOY_TYPE_DEDICATED:n2-highmem-16\nnode:gcp:us-central1:DEPLOY_TYPE_DEDICATED:n2-highmem-8\nnode:gcp:us-central1:DEPLOY_TYPE_DEDICATED:n2-standard-16\nnode:gcp:us-central1:DEPLOY_TYPE_DEDICATED:n2-standard-2\nnode:gcp:us-central1:DEPLOY_TYPE_DEDICATED:n2-standard-4\nnode:gcp:us-central1:DEPLOY_TYPE_DEDICATED:n2-standard-8\nnode:gcp:us-central1:DEPLOY_TYPE_DEDICATED:t2d-standard-16\nnode:gcp:us-west1:DEPLOY_TYPE_DEDICATED:n1-standard-1\nnode:gcp:us-west1:DEPLOY_TYPE_DEDICATED:n1-standard-2\nnode:gcp:us-west1:DEPLOY_TYPE_DEDICATED:n1-standard-4\nnode:gcp:us-west1:DEPLOY_TYPE_DEDICATED:n2-custom-16-32768\nnode:gcp:us-west1:DEPLOY_TYPE_DEDICATED:n2-custom-8-16384\nnode:gcp:us-west1:DEPLOY_TYPE_DEDICATED:n2-highmem-16\nnode:gcp:us-west1:DEPLOY_TYPE_DEDICATED:n2-highmem-8\nnode:gcp:us-west1:DEPLOY_TYPE_DEDICATED:n2-standard-16\nnode:gcp:us-west1:DEPLOY_TYPE_DEDICATED:n2-standard-2\nnode:gcp:us-west1:DEPLOY_TYPE_DEDICATED:n2-standard-4\nnode:gcp:us-west1:DEPLOY_TYPE_DEDICATED:n2-standard-8\nnode:gcp:us-west1:DEPLOY_TYPE_DEDICATED:t2d-standard-16\npl-endpoint:aws\nserverless-column-storage:aws:ap-northeast-1\nserverless-column-storage:aws:ap-southeast-1\nserverless-column-storage:aws:eu-central-1\nserverless-column-storage:aws:us-east-1\nserverless-column-storage:aws:us-west-2\nserverless-request-unit:aws:ap-northeast-1\nserverless-request-unit:aws:ap-southeast-1\nserverless-request-unit:aws:eu-central-1\nserverless-request-unit:aws:us-east-1\nserverless-request-unit:aws:us-west-2\nserverless-row-storage:aws:ap-northeast-1\nserverless-row-storage:aws:ap-southeast-1\nserverless-row-storage:aws:eu-central-1\nserverless-row-storage:aws:us-east-1\nserverless-row-storage:aws:us-west-2\nsupport-plan:commitment\nsupport-plan:commitment_price\nsupport-plan:fixed\nsupport-plan:fixed_price\nsupport-plan:percentage\nsupport-plan:percentage_price\ntcds-request-network:aws:ap-northeast-1\ntcds-request-network:aws:ap-northeast-2\ntcds-request-network:aws:ap-southeast-1\ntcds-request-network:aws:eu-central-1\ntcds-request-network:aws:us-east-1\ntcds-request-network:aws:us-west-2\ntcds-request-unit:aws:ap-northeast-1\ntcds-request-unit:aws:ap-northeast-2\ntcds-request-unit:aws:ap-southeast-1\ntcds-request-unit:aws:eu-central-1\ntcds-request-unit:aws:us-east-1\ntcds-request-unit:aws:us-west-2\nticdc-tcu:aws:ap-northeast-1\nticdc-tcu:aws:ap-south-1\nticdc-tcu:aws:ap-southeast-1\nticdc-tcu:aws:ap-southeast-3\nticdc-tcu:aws:eu-central-1\nticdc-tcu:aws:us-east-1\nticdc-tcu:aws:us-west-2\nticdc-tcu:gcp:asia-east1\nticdc-tcu:gcp:asia-northeast1\nticdc-tcu:gcp:asia-northeast2\nticdc-tcu:gcp:asia-southeast1\nticdc-tcu:gcp:us-central1\nticdc-tcu:gcp:us-west1\nticdc:network-traffic", "\n")
	ufModel := &unit_filter.Model{}
	list, err := ufModel.ListExternalUnitFilters()
	assert.NoError(err)
	assert.Len(list, 1)
	err = (&migrate.MigrateModel{}).MigrateDataTrafficUnitFilters()
	assert.NoError(err)
	list, err = ufModel.ListExternalUnitFilters()
	assert.NoError(err)
	assert.Len(list, 6)
	tree, err := ufModel.GetUnitFilterTree()
	assert.NoError(err)
	assert.Len(tree.Children, 1)
	assert.Len(tree.Children[0].Children, 1)
	uf, err := ufModel.GetUnitFilter(tree.Children[0].Children[0].FilterID)
	assert.NoError(err)
	for unit, _ := range unitCatMap {
		assert.True(billing.UnitMatch(&forms.UnitInfo{
			UnitKey: unit,
		}, []*forms.UnitFilter{uf}, map[string]string{}))
	}
	for _, unit := range invalidUnits {
		assert.False(billing.UnitMatch(&forms.UnitInfo{
			UnitKey: unit,
		}, []*forms.UnitFilter{uf}, map[string]string{}))
	}
	assert.Len(tree.Children[0].Children[0].Children, 4)
	nameList := []string{"Same Region", "Cross Region", "Internet", "Load Balancing"}
	for i, ufSlim := range tree.Children[0].Children[0].Children {
		assert.Equal(fmt.Sprintf("Data Transfer (%s)", nameList[i]), ufSlim.Name)
		uf, err := ufModel.GetUnitFilter(ufSlim.FilterID)
		assert.NoError(err)
		for _, unit := range invalidUnits {
			assert.False(billing.UnitMatch(&forms.UnitInfo{
				UnitKey: unit,
			}, []*forms.UnitFilter{uf}, map[string]string{}))
		}
		for unit, cat := range unitCatMap {
			res := billing.UnitMatch(&forms.UnitInfo{
				UnitKey: unit,
			}, []*forms.UnitFilter{uf}, map[string]string{})
			assert.Equal(cat == fmt.Sprintf("Data Transfer Cost - AWS %s", nameList[i]) || cat == fmt.Sprintf("Data Transfer Cost - GCP %s", nameList[i]), res)
		}
	}
}

func (suite *MigrateTestSuite) TestMigrateTenantClosePolicy() {
	assert := suite.Assert()
	err := db.GetDB().Exec("INSERT INTO `credit_risk_close_policies` (`created_at`, `updated_at`, `deleted_at`, `credit_risk_level_id`, `close_policy`, `reason`)\nVALUES\n\t('2022-11-15 10:50:31.146', '2022-11-15 10:50:31.146', NULL, 12, '{\\\"actions\\\": [{\\\"action\\\": \\\"cleanup_tenant_dedicate_clusters\\\", \\\"action_time_in_hour\\\": 0}, {\\\"action\\\": \\\"close_tenant\\\", \\\"action_time_in_hour\\\": 1080}], \\\"cancel_action\\\": null}', 'risky'),\n\t('2022-11-22 02:55:53.000', '2022-11-22 02:55:53.000', '2022-11-22 02:57:27.026', 1, '{\\\"actions\\\": [{\\\"action\\\": \\\"cleanup_tenant_dedicate_clusters\\\", \\\"action_time_in_hour\\\": 0}, {\\\"action\\\": \\\"close_tenant\\\", \\\"action_time_in_hour\\\": 1080}], \\\"cancel_action\\\": null}', 'risky-1'),\n\t('2022-11-22 03:00:26.400', '2022-11-22 03:00:26.400', NULL, 1, '{\\\"actions\\\": [{\\\"action\\\": \\\"cleanup_tenant_dedicate_clusters\\\", \\\"action_time_in_hour\\\": 0}, {\\\"action\\\": \\\"send_tenant_credit_close_email\\\", \\\"action_time_in_hour\\\": 0}, {\\\"action\\\": \\\"cleanup_tenant_support_plan\\\", \\\"action_time_in_hour\\\": 0}, {\\\"action\\\": \\\"cleanup_tenant_serverless_clusters\\\", \\\"action_time_in_hour\\\": 1440}, {\\\"action\\\": \\\"cleanup_backups\\\", \\\"action_time_in_hour\\\": 1440}, {\\\"action\\\": \\\"close_tenant\\\", \\\"action_time_in_hour\\\": 1440}], \\\"cancel_action\\\": null}', 'credit_card_unpayable'),\n\t('2023-08-14 06:46:24.324', '2023-08-14 06:46:24.324', NULL, 0, '{\\\"actions\\\": [{\\\"action\\\": \\\"cleanup_tenant_dedicate_clusters\\\", \\\"action_time_in_hour\\\": 0}, {\\\"action\\\": \\\"cleanup_tenant_support_plan\\\", \\\"action_time_in_hour\\\": 0}, {\\\"action\\\": \\\"cleanup_tenant_serverless_clusters\\\", \\\"action_time_in_hour\\\": 1440}, {\\\"action\\\": \\\"cleanup_backups\\\", \\\"action_time_in_hour\\\": 1440}, {\\\"action\\\": \\\"close_tenant\\\", \\\"action_time_in_hour\\\": 1440}], \\\"cancel_action\\\": null}', 'marketplace_unsubscribed');\n").Error
	assert.NoError(err)
	err = db.GetDB().Exec("INSERT INTO `credit_risk_close_policies` (`created_at`,`updated_at`,`deleted_at`,`credit_risk_level_id`,`reason`,`close_policy`) VALUES ('2024-08-05 06:49:29.141','2024-08-05 06:49:29.141',NULL,0,'credit_card_unpayable_for_non_KA','{\"actions\":null,\"cancel_action\":null}')").Error
	assert.NoError(err)
	err = (&migrate.MigrateModel{}).MigrateTenantClosePolicy()
	assert.NoError(err)
	var policies []entity.TenantClosePolicy
	err = entity.NewTenantClosePolicyQuerySet(db.GetDB()).All(&policies)
	assert.NoError(err)
	assert.Len(policies, 4)
}

func (suite *MigrateTestSuite) TestMigrateDataTrafficUnit() {
	assert := suite.Assert()
	(&migrate.MigrateModel{}).MigrateDataTrafficUnit()
	var units []entity.Unit
	err := entity.NewUnitQuerySet(db.GetDB()).All(&units)
	assert.NoError(err)
	assert.Equal(100, len(units))
	unitModel := &billing.UnitModel{}
	info, err := unitModel.GetUnit("network-traffic:aws:ap-southeast-2:cross_az")
	assert.NoError(err)
	assert.Equal(info.Category, "Data Transfer Cost - AWS Same Region")
	assert.Equal(info.Region, "ap-southeast-2")
	assert.Equal(info.Provider, "AWS")
	assert.Equal(info.Price, decimal.NewFromFloat(0.000000010000000))
}

func (suite *MigrateTestSuite) TestMigratePublicSupportPlan() {
	assert := suite.Assert()
	tenantID := uint(1)
	model := &marketing.SupportPlanModel{}
	// create public standard supportplan
	infoV1, err := model.CreateSupportPlan(&forms.SupportPlan{
		FixedChargePrice:       decimal.NewFromInt(49),
		SupportPricePercentage: decimal.NewFromFloat(0.1),
		Type:                   entity.SupportPlanType_PercentagePrice,
		Public:                 true,
		Level:                  entity.SupportPlanLevel_Standard,
	})
	assert.NoError(err)
	assert.Equal(infoV1.FixedChargePrice, decimal.NewFromInt(49))

	// Bind the SupportPlan
	_, err = datainit.CreateBillingConfig(tenantID, entity.BillingConfigType_DirectCustomer)
	assert.NoError(err)
	err = datainit.CreatePaymentMock(tenantID)
	assert.NoError(err)
	timeutils.GetNowFunc = func() time.Time {
		return datainit.BillingDate // now = "2021-11-01 00:00:00"
	}
	bindedInfo, err := model.BindSupportPlanForPayableCustomer(tenantID, infoV1.SupportPlanID, forms.DateInterval{StartDate: timeutils.GetNowAddr()})
	assert.NoError(err)
	assert.Equal(bindedInfo.Status, entity.BindedSupportPlanStatus_ACTIVE)
	assert.Equal(bindedInfo.IsEligibleForFreeTrial, false)

	// create private standard supportplan
	infoV2, err := model.CreateSupportPlan(&forms.SupportPlan{
		FixedChargePrice:       decimal.NewFromInt(100),
		SupportPricePercentage: decimal.NewFromFloat(0.1),
		Type:                   entity.SupportPlanType_PercentagePrice,
		Public:                 false,
		Level:                  entity.SupportPlanLevel_Standard,
	})
	assert.NoError(err)
	assert.Equal(infoV2.FixedChargePrice, decimal.NewFromInt(100))

	// query all supportplans
	allPlans, err := model.ListSupportPlan()
	assert.NoError(err)
	assert.Equal(len(allPlans), 2)

	allPublicPlans, err := model.ListPublicSupportPlan()
	assert.NoError(err)
	assert.Equal(len(allPublicPlans), 1)
	assert.Equal(allPublicPlans[0].FixedChargePrice, decimal.NewFromInt(49))
	assert.Equal(allPublicPlans[0].IsSupportFreeTrial, false)

	// case-1: migrate
	err = (&migrate.MigrateModel{}).MigratePublicSupportPlan()
	assert.NoError(err)

	allPlans, err = model.ListSupportPlan()
	assert.NoError(err)
	assert.Equal(len(allPlans), 2)

	allPublicPlans, err = model.ListPublicSupportPlan()
	assert.NoError(err)
	assert.Equal(len(allPublicPlans), 1)
	assert.Equal(allPublicPlans[0].FixedChargePrice, decimal.NewFromInt(29))
	assert.Equal(allPublicPlans[0].Level, entity.SupportPlanLevel_Developer)
	assert.Equal(allPublicPlans[0].IsSupportFreeTrial, true)
	for _, plan := range allPlans {
		if !plan.Public {
			assert.Equal(plan.Level, entity.SupportPlanLevel_Developer)
			assert.Equal(plan.FixedChargePrice, decimal.NewFromInt(100))
			assert.Equal(plan.IsSupportFreeTrial, false)
			assert.Equal(plan.SupportPlanID, infoV2.SupportPlanID)
		}
	}
	// query the bindedSupportPlan
	bindedInfo, err = model.GetTenantActiveBindedPlan(tenantID)
	assert.NoError(err)
	assert.Equal(bindedInfo.SupportPlanID, infoV1.SupportPlanID) // infoV1 has been deleted, can also be query
	assert.Equal(bindedInfo.Level, entity.SupportPlanLevel_Developer)
	assert.Equal(bindedInfo.FixedChargePrice, decimal.NewFromInt(29))

	// case-2: re-migrate, the result is same
	err = (&migrate.MigrateModel{}).MigratePublicSupportPlan()
	assert.NoError(err)

	allPlans, err = model.ListSupportPlan()
	assert.NoError(err)
	assert.Equal(len(allPlans), 2)

	allPublicPlans, err = model.ListPublicSupportPlan()
	assert.NoError(err)
	assert.Equal(len(allPublicPlans), 1)
	assert.Equal(allPublicPlans[0].FixedChargePrice, decimal.NewFromInt(29))
	assert.Equal(allPublicPlans[0].Level, entity.SupportPlanLevel_Developer)
	assert.Equal(allPublicPlans[0].IsSupportFreeTrial, true)
	for _, plan := range allPlans {
		if !plan.Public {
			assert.Equal(plan.Level, entity.SupportPlanLevel_Developer)
			assert.Equal(plan.FixedChargePrice, decimal.NewFromInt(100))
			assert.Equal(plan.IsSupportFreeTrial, false)
			assert.Equal(plan.SupportPlanID, infoV2.SupportPlanID)
		}
	}
	// query the active bindedSupportPlan
	bindedInfo, err = model.GetTenantActiveBindedPlan(tenantID)
	assert.NoError(err)
	assert.Equal(bindedInfo.SupportPlanID, infoV1.SupportPlanID) // infoV1 has been deleted, can also be query
	assert.Equal(bindedInfo.Level, entity.SupportPlanLevel_Developer)
	assert.Equal(bindedInfo.FixedChargePrice, decimal.NewFromInt(29))

	// query all bindedSupport: infoV1 has been deleted, can also be query
	bindedInfos, err := model.ListTenantsBindedSupportPlan(tenantID, entity.BindedSupportPlanStatus_ACTIVE)
	assert.NoError(err)
	assert.Equal(len(bindedInfos), 1)

	// query the specified bindedSupportPlan, it's supportplan has been soft deleted
	bindedInfo, err = model.GetBindedSupportPlan(bindedInfo.BindedSupportPlanID)
	assert.NoError(err)
	assert.Equal(bindedInfo.SupportPlanID, infoV1.SupportPlanID) // infoV1 has been deleted, can also be query
	assert.Equal(bindedInfo.Level, entity.SupportPlanLevel_Developer)
	assert.Equal(bindedInfo.FixedChargePrice, decimal.NewFromInt(29))
}
