package cvt

import (
	"testing"
	"time"

	ccent "github.com/tidbcloud/devops/entity/cloudconfig"
	maintent "github.com/tidbcloud/devops/entity/maintenance"
	"github.com/tidbcloud/devops/models/base"
	ccmod "github.com/tidbcloud/devops/models/cloudconfig"
	"github.com/tidbcloud/devops/pkg/infra/utils/pointer"
	"github.com/tidbcloud/devops/pkg/infra/utils/test"

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
)

func TestRepo(t *testing.T) {
	RegisterFailHandler(Fail)
	RunSpecs(t, "CloudConfig Converter Suite")
}

var _ = Describe("[CloudConfig Converter]", func() {

	Describe("ConfigurationChange", func() {
		Context("[Model To Entity]", func() {
			It("should not miss fields when converting", func() {
				time := *test.ParseTimeOrDie(time.DateTime, "2023-06-12 11:00:00")

				// every fields MUST be set as a non zero value
				org := &ccmod.ConfigurationChange{
					Updatable: base.Updatable{
						Base:      base.Base{ID: base.ID(1), CreatedAt: time},
						UpdatedAt: &time,
					},

					TargetType:     string(ccent.ConfigurationChangeTargetTypeCluster),
					ChangeType:     "fulltidb",
					TargetVersion:  "v1.0.0",
					Reason:         "reason",
					Applicant:      "test@pingcap.com",
					OperatorEntity: "user:test@pingcap.com",
					ApplyPolicy:    string(ccent.ParameterApplyPolicyRestart),

					Phase:      string(ccent.ConfigurationChangePhaseCreated),
					ApprovalID: pointer.Pointer(uint64(10)),
					ClosedAt:   &time,
					AppliedAt:  &time,

					ExecutionWindowID: pointer.Pointer(uint64(20)),

					PremiumUpgradeStepID: pointer.Pointer(uint64(32)),

					Files: []*ccmod.ConfigurationFileChange{
						{
							Base:               base.Base{ID: base.ID(10), CreatedAt: time},
							Filename:           "tidb.toml",
							ConfigType:         "tidb",
							TemplateID:         10,
							AllParameters:      []byte(`[{"name":"a","value":11,"comment":"comment","source":"custom"},{"name":"b","value":"123","comment":"comment","source":"custom"}]`),
							ModifiedParameters: []byte(`[{"name":"a","from":1,"to":11,"from_source":"custom","to_source":"custom","risk_level":"low"}]`),
							ModifiedTemplate:   []byte(`{"from":11,"to":22}`),
							PreviousText:       `{"a":11,"b":"123"}`,

							ChangeID:          1,
							ClearCustomParams: true,
						},
						{
							Base:               base.Base{ID: base.ID(11), CreatedAt: time},
							Filename:           "tiflash.toml",
							ConfigType:         "tiflash",
							TemplateID:         10,
							AllParameters:      []byte(`[{"value":123,"comment":"comment","name":"c","source":"custom"}]`),
							ModifiedParameters: []byte(`[{"name":"c","from":1,"to":123,"from_source":"template","to_source":"custom","risk_level":"low"}]`),
							ModifiedTemplate:   []byte(`{"from":11,"to":22}`),
							PreviousText:       `{"c":123}`,

							ChangeID:          1,
							ClearCustomParams: true,
						},
					},
					Components: []*ccmod.ConfigurationComponentChange{
						{
							Base:                      base.Base{ID: base.ID(11), CreatedAt: time},
							Component:                 "tidb",
							ModifiedVersion:           []byte(`{"from":"v1.0.0","to":"v2.0.0"}`),
							ModifiedImageTag:          []byte(`{"from":"v1.0.0","to":"v2.0.0"}`),
							ModifiedOverwriteImageTag: []byte(`{"from":"v1.1.0","to":"v2.1.0"}`),
							ChangeID:                  1,
						},
					},
					Version: &ccmod.ConfigurationVersionChange{
						Base:        base.Base{ID: base.ID(100)},
						FromVersion: "v1.0.0",
						ToVersion:   "v2.0.0",
						ChangeID:    1,
					},
					ToCluster: &ccmod.ConfigurationChangeToCluster{
						ClusterType:     "tidb",
						ClusterID:       "53251515",
						ChangeID:        1,
					},
					ToTenantInit: &ccmod.ConfigurationChangeToTenantInit{
						ClusterType: "tenant_init",
						TenantID:    11111,
						ChangeID:    1,
					},
					ToTemplate: &ccmod.ConfigurationChangeToTemplate{
						ClusterType:  "DEDICATED_TIDB",
						TemplateType: "custom",
						TenantID:     pointer.Pointer("123"),
						ChangeID:     1,
					},
				}
				exp := &ccent.ConfigurationChange{
					ID:             1,
					TargetType:     ccent.ConfigurationChangeTargetTypeCluster,
					TargetVersion:  "v1.0.0",
					ChangeType:     "fulltidb",
					Reason:         "reason",
					Applicant:      "test@pingcap.com",
					OperatorEntity: "user:test@pingcap.com",
					ApplyPolicy:    ccent.ParameterApplyPolicyRestart,

					Phase:      ccent.ConfigurationChangePhaseCreated,
					ApprovalID: pointer.Pointer(uint64(10)),
					CreatedAt:  time.Unix(),
					ClosedAt:   pointer.Pointer(time.Unix()),
					AppliedAt:  pointer.Pointer(time.Unix()),

					ExecutionWindowID: pointer.Pointer(uint64(20)),

					PremiumUpgradeStepID: pointer.Pointer(uint64(32)),

					Scope: ccent.ConfigurationChangeScope{
						Files: []*ccent.ConfigurationFileChange{
							{
								ID:         10,
								Filename:   "tidb.toml",
								ConfigType: "tidb",
								TemplateID: 10,
								AllParameters: []ccent.UsedParameter{
									{
										NamedParameter: ccent.NamedParameter{
											Name: "a",
											ParameterValue: ccent.ParameterValue{
												Value:   float64(11),
												Comment: "comment",
											},
										},
										Source: ccent.ParameterCustom,
									},
									{
										NamedParameter: ccent.NamedParameter{
											Name: "b",
											ParameterValue: ccent.ParameterValue{
												Value:   "123",
												Comment: "comment",
											},
										},
										Source: ccent.ParameterCustom,
									},
								},
								ModifiedParameters: []ccent.ChangedParameter{
									{
										Name:       "a",
										From:       float64(1),
										To:         float64(11),
										FromSource: ccent.ParameterCustom,
										ToSource:   ccent.ParameterCustom,
										RiskLevel:  ccent.RiskLevelLow,
									},
								},
								ModifiedTemplate: &ccent.ChangedTemplate{
									From: 11,
									To:   22,
								},
								PreviousText:      `{"a":11,"b":"123"}`,
								ClearCustomParams: true,
							},
							{
								ID:         11,
								Filename:   "tiflash.toml",
								ConfigType: "tiflash",
								TemplateID: 10,
								AllParameters: []ccent.UsedParameter{
									{
										NamedParameter: ccent.NamedParameter{
											Name: "c",
											ParameterValue: ccent.ParameterValue{
												Value:   float64(123),
												Comment: "comment",
											},
										},
										Source: ccent.ParameterCustom,
									},
								},
								ModifiedParameters: []ccent.ChangedParameter{
									{
										Name:       "c",
										From:       float64(1),
										To:         float64(123),
										FromSource: ccent.ParameterTemplate,
										ToSource:   ccent.ParameterCustom,
										RiskLevel:  ccent.RiskLevelLow,
									},
								},
								ModifiedTemplate: &ccent.ChangedTemplate{
									From: 11,
									To:   22,
								},
								PreviousText:      `{"c":123}`,
								ClearCustomParams: true,
							},
						},
						Components: []*ccent.ConfigurationComponentChange{
							{
								ID:        11,
								Component: "tidb",
								ModifiedVersion: &ccent.ChangedVersion{
									From: "v1.0.0",
									To:   "v2.0.0",
								},
								ModifiedImageTag: &ccent.ChangedImageTag{
									From: "v1.0.0",
									To:   "v2.0.0",
								},
								ModifiedOverwriteImageTag: &ccent.ChangedImageTag{
									From: "v1.1.0",
									To:   "v2.1.0",
								},
							},
						},
						Version: &ccent.ConfigurationVersionChange{
							ID:   100,
							From: "v1.0.0",
							To:   "v2.0.0",
						},
					},

					TargetCluster: &ccent.ClusterConfigurationLocator{
						ClusterType:     "tidb",
						ClusterID:       "53251515",
					},
					TargetTenantInit: &ccent.TenantInitConfigurationLocator{
						ClusterType: "tenant_init",
						TenantID:    11111,
					},
					TargetTemplate: &ccent.ConfigurationTemplateLocator{
						ClusterType:  "DEDICATED_TIDB",
						TemplateType: ccent.TemplateTypeCustom,
						TenantID:     pointer.Pointer("123"),
					},
				}

				ignoredFields := []string{
					".ExecutionWindow",
				}

				Expect(test.CheckNonZeroValue(org, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")

				got := m2e{}.ConfigurationChange(org)
				Expect(test.CheckNonZeroValue(got, ignoredFields)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")
				Expect(test.IsEqual(exp, got)).To(BeNil())
			})

		})

		Context("[Entity To Model]", func() {
			It("should not miss fields when converting", func() {
				time := *test.ParseTimeOrDie(time.DateTime, "2023-06-12 11:00:00")

				// every fields MUST be set as a non zero value
				org := &ccent.ConfigurationChange{
					ID:             1,
					TargetType:     ccent.ConfigurationChangeTargetTypeCluster,
					TargetVersion:  "v1.0.0",
					ChangeType:     "fulltidb",
					Reason:         "reason",
					Applicant:      "test@pingcap.com",
					OperatorEntity: "user:test@pingcap.com",
					ApplyPolicy:    ccent.ParameterApplyPolicyRestart,

					Phase:      ccent.ConfigurationChangePhaseCreated,
					ApprovalID: pointer.Pointer(uint64(10)),
					CreatedAt:  time.Unix(),
					ClosedAt:   pointer.Pointer(time.Unix()),
					AppliedAt:  pointer.Pointer(time.Unix()),

					ExecutionWindowID: pointer.Pointer(uint64(20)),
					ExecutionWindow:   &maintent.OpsExecutionWindow{ID: 20, CreatedAt: 1, UpdatedAt: 2, StartAt: 100, EndAt: 200},

					PremiumUpgradeStepID: pointer.Pointer(uint64(32)),

					Scope: ccent.ConfigurationChangeScope{
						Files: []*ccent.ConfigurationFileChange{
							{
								ID:         10,
								Filename:   "tidb.toml",
								ConfigType: "tidb",
								TemplateID: 10,
								AllParameters: []ccent.UsedParameter{
									{
										NamedParameter: ccent.NamedParameter{
											Name: "a",
											ParameterValue: ccent.ParameterValue{
												Value:   float64(11),
												Comment: "comment",
											},
										},
										Source: ccent.ParameterCustom,
									},
									{
										NamedParameter: ccent.NamedParameter{
											Name: "b",
											ParameterValue: ccent.ParameterValue{
												Value:   "123",
												Comment: "comment",
											},
										},
										Source: ccent.ParameterCustom,
									},
								},
								ModifiedParameters: []ccent.ChangedParameter{
									{
										Name:       "a",
										From:       float64(1),
										To:         float64(11),
										FromSource: ccent.ParameterCustom,
										ToSource:   ccent.ParameterCustom,
										RiskLevel:  ccent.RiskLevelLow,
									},
								},
								ModifiedTemplate: &ccent.ChangedTemplate{
									From: 11,
									To:   22,
								},
								PreviousText:      `{"a":11,"b":"123"}`,
								ClearCustomParams: true,
							},
							{
								ID:         11,
								Filename:   "tiflash.toml",
								ConfigType: "tiflash",
								TemplateID: 10,
								AllParameters: []ccent.UsedParameter{
									{
										NamedParameter: ccent.NamedParameter{
											Name: "c",
											ParameterValue: ccent.ParameterValue{
												Value:   float64(123),
												Comment: "comment",
											},
										},
										Source: ccent.ParameterCustom,
									},
								},
								ModifiedParameters: []ccent.ChangedParameter{
									{
										Name:       "c",
										From:       float64(1),
										To:         float64(123),
										FromSource: ccent.ParameterKernelDefault,
										ToSource:   ccent.ParameterCustom,
										RiskLevel:  ccent.RiskLevelLow,
									},
								},
								ModifiedTemplate: &ccent.ChangedTemplate{
									From: 11,
									To:   22,
								},
								PreviousText:      `{"c":123}`,
								ClearCustomParams: true,
							},
						},
						Components: []*ccent.ConfigurationComponentChange{
							{
								ID:        11,
								Component: "tidb",
								ModifiedVersion: &ccent.ChangedVersion{
									From: "v1.0.0",
									To:   "v2.0.0",
								},
								ModifiedImageTag: &ccent.ChangedImageTag{
									From: "v1.0.0",
									To:   "v2.0.0",
								},
								ModifiedOverwriteImageTag: &ccent.ChangedImageTag{
									From: "v1.1.0",
									To:   "v2.1.0",
								},
							},
						},
						Version: &ccent.ConfigurationVersionChange{
							ID:   100,
							From: "v1.0.0",
							To:   "v2.0.0",
						},
					},
					TargetCluster: &ccent.ClusterConfigurationLocator{
						ClusterType:     "tidb",
						ClusterID:       "53251515",
					},
					TargetTenantInit: &ccent.TenantInitConfigurationLocator{
						ClusterType: "tenant_init",
						TenantID:    11111,
					},
					TargetTemplate: &ccent.ConfigurationTemplateLocator{
						ClusterType:  "DEDICATED_TIDB",
						TemplateType: ccent.TemplateTypeCustom,
						TenantID:     pointer.Pointer("123"),
					},
				}
				exp := &ccmod.ConfigurationChange{
					Updatable: base.Updatable{
						Base: base.Base{ID: base.ID(1)},
					},

					TargetType:     string(ccent.ConfigurationChangeTargetTypeCluster),
					TargetVersion:  "v1.0.0",
					ChangeType:     "fulltidb",
					Reason:         "reason",
					Applicant:      "test@pingcap.com",
					OperatorEntity: "user:test@pingcap.com",
					ApplyPolicy:    string(ccent.ParameterApplyPolicyRestart),

					Phase:      string(ccent.ConfigurationChangePhaseCreated),
					ApprovalID: pointer.Pointer(uint64(10)),
					ClosedAt:   &time,
					AppliedAt:  &time,

					ExecutionWindowID: pointer.Pointer(uint64(20)),

					PremiumUpgradeStepID: pointer.Pointer(uint64(32)),

					Files: []*ccmod.ConfigurationFileChange{
						{
							Base:               base.Base{ID: base.ID(10)},
							Filename:           "tidb.toml",
							ConfigType:         "tidb",
							TemplateID:         10,
							AllParameters:      []byte(`[{"value":11,"comment":"comment","name":"a","source":"custom"},{"value":"123","comment":"comment","name":"b","source":"custom"}]`),
							ModifiedParameters: []byte(`[{"name":"a","from":1,"to":11,"from_source":"custom","to_source":"custom","risk_level":"low"}]`),
							ModifiedTemplate:   []byte(`{"from":11,"to":22}`),
							PreviousText:       `{"a":11,"b":"123"}`,

							ChangeID:          1,
							ClearCustomParams: true,
						},
						{
							Base:               base.Base{ID: base.ID(11)},
							Filename:           "tiflash.toml",
							ConfigType:         "tiflash",
							TemplateID:         10,
							AllParameters:      []byte(`[{"value":123,"comment":"comment","name":"c","source":"custom"}]`),
							ModifiedParameters: []byte(`[{"name":"c","from":1,"to":123,"from_source":"kernel default","to_source":"custom","risk_level":"low"}]`),
							ModifiedTemplate:   []byte(`{"from":11,"to":22}`),
							PreviousText:       `{"c":123}`,

							ChangeID:          1,
							ClearCustomParams: true,
						},
					},
					Components: []*ccmod.ConfigurationComponentChange{
						{
							Base:                      base.Base{ID: base.ID(11)},
							Component:                 "tidb",
							ModifiedVersion:           []byte(`{"from":"v1.0.0","to":"v2.0.0"}`),
							ModifiedImageTag:          []byte(`{"from":"v1.0.0","to":"v2.0.0"}`),
							ModifiedOverwriteImageTag: []byte(`{"from":"v1.1.0","to":"v2.1.0"}`),
							ChangeID:                  1,
						},
					},
					Version: &ccmod.ConfigurationVersionChange{
						Base:        base.Base{ID: base.ID(100)},
						FromVersion: "v1.0.0",
						ToVersion:   "v2.0.0",
						ChangeID:    1,
					},
					ToCluster: &ccmod.ConfigurationChangeToCluster{
						ClusterType:     "tidb",
						ClusterID:       "53251515",
						ChangeID:        1,
					},
					ToTenantInit: &ccmod.ConfigurationChangeToTenantInit{
						ClusterType: "tenant_init",
						TenantID:    11111,
						ChangeID:    1,
					},
					ToTemplate: &ccmod.ConfigurationChangeToTemplate{
						ClusterType:  "DEDICATED_TIDB",
						TemplateType: "custom",
						ChangeID:     1,
						TenantID:     pointer.Pointer("123"),
					},
				}
				ignoredFields := []string{
					".Updatable.Base.CreatedAt",
					".Updatable.UpdatedAt",
					".Files[0].Base.CreatedAt",
					".Files[1].Base.CreatedAt",
					".Components[0].Base.CreatedAt",
				}

				Expect(test.CheckNonZeroValue(org, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")

				got := e2m{}.ConfigurationChange(org)
				Expect(test.CheckNonZeroValue(got, ignoredFields)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")
				Expect(test.IsEqual(exp, got)).To(BeNil())
			})

		})
	})

	Describe("DefaultConfigurationChange", func() {

		Context("[Model To Entity]", func() {
			It("should not miss fields when converting", func() {
				time := *test.ParseTimeOrDie(time.DateTime, "2023-06-12 11:00:00")

				// every fields MUST be set as a non zero value
				org := &ccmod.DefaultConfigurationChange{
					Updatable: base.Updatable{
						Base:      base.Base{ID: base.ID(1), CreatedAt: time},
						UpdatedAt: &time,
					},

					ClosedAt:     &time,
					Applicant:    "test@pingcap.com",
					Reason:       "test",
					DisplayName:  "display name",
					Phase:        string(ccent.DefaultConfigurationChangePhaseInProgress),
					PhaseReason:  "phase reason",
					ItemTypes:    []string{string(ccent.DefaultConfigurationChangeItemTypeVersionRelease)},
					Environments: []string{"dev", "staging"},
				}

				exp := &ccent.DefaultConfigurationChange{
					ID:        1,
					CreatedAt: time.Unix(),

					ClosedAt:     pointer.Pointer(time.Unix()),
					Applicant:    "test@pingcap.com",
					Reason:       "test",
					DisplayName:  "display name",
					Phase:        ccent.DefaultConfigurationChangePhaseInProgress,
					PhaseReason:  "phase reason",
					ItemTypes:    []ccent.DefaultConfigurationChangeItemType{ccent.DefaultConfigurationChangeItemTypeVersionRelease},
					Environments: []string{"dev", "staging"},
				}

				Expect(test.CheckNonZeroValue(org, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")

				got := m2e{}.DefaultConfigurationChange(org)
				Expect(test.CheckNonZeroValue(got, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")
				Expect(test.IsEqual(exp, got)).To(BeNil())
			})
		})

		Context("[Entity To Model]", func() {
			It("should not miss fields when converting", func() {
				time := *test.ParseTimeOrDie(time.DateTime, "2023-06-12 11:00:00")

				// every fields MUST be set as a non zero value

				org := &ccent.DefaultConfigurationChange{
					ID:        1,
					CreatedAt: time.Unix(),

					ClosedAt:     pointer.Pointer(time.Unix()),
					Applicant:    "test@pingcap.com",
					Reason:       "test",
					DisplayName:  "display name",
					Phase:        ccent.DefaultConfigurationChangePhaseInProgress,
					PhaseReason:  "phase reason",
					ItemTypes:    []ccent.DefaultConfigurationChangeItemType{ccent.DefaultConfigurationChangeItemTypeVersionRelease},
					Environments: []string{"dev", "staging"},
				}

				exp := &ccmod.DefaultConfigurationChange{
					Updatable: base.Updatable{
						Base: base.Base{ID: base.ID(1)},
					},

					ClosedAt:     &time,
					Applicant:    "test@pingcap.com",
					Reason:       "test",
					DisplayName:  "display name",
					Phase:        string(ccent.DefaultConfigurationChangePhaseInProgress),
					PhaseReason:  "phase reason",
					ItemTypes:    []string{string(ccent.DefaultConfigurationChangeItemTypeVersionRelease)},
					Environments: []string{"dev", "staging"},
				}
				ignoredFields := []string{
					".Updatable.Base.CreatedAt",
					".Updatable.UpdatedAt",
				}

				Expect(test.CheckNonZeroValue(org, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")

				got := e2m{}.DefaultConfigurationChange(org)
				Expect(test.CheckNonZeroValue(got, ignoredFields)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")
				Expect(test.IsEqual(exp, got)).To(BeNil())
			})
		})

	})

	Describe("DefaultConfigurationChangeRelease", func() {
		Context("[Model To Entity]", func() {
			It("should not miss fields when converting", func() {
				time := *test.ParseTimeOrDie(time.DateTime, "2023-06-12 11:00:00")

				org := &ccmod.DefaultConfigurationChangeRelease{
					ID:            base.ID(10),
					Environment:   "dev",
					Description:   "desc",
					Phase:         string(ccent.DefaultConfigurationChangeReleasePhaseReleased),
					ReleasedAt:    &time,
					ReleaseNumber: 1,
					ApprovalID:    10080,
					ParentID:      1,
				}

				exp := &ccent.DefaultConfigurationChangeRelease{
					ID:            10,
					Environment:   "dev",
					Description:   "desc",
					Phase:         ccent.DefaultConfigurationChangeReleasePhaseReleased,
					ReleasedAt:    pointer.Pointer(time.Unix()),
					ReleaseNumber: 1,
					ApprovalID:    10080,
					ParentID:      1,
				}

				Expect(test.CheckNonZeroValue(org, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")

				got := m2e{}.DefaultConfigurationChangeRelease(org)
				Expect(test.CheckNonZeroValue(got, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")
				Expect(test.IsEqual(exp, got)).To(BeNil())

			})
		})

		Context("[Entity To Model]", func() {
			It("should not miss fields when converting", func() {
				time := *test.ParseTimeOrDie(time.DateTime, "2023-06-12 11:00:00")

				org := &ccent.DefaultConfigurationChangeRelease{
					ID:            10,
					Environment:   "dev",
					Description:   "desc",
					Phase:         ccent.DefaultConfigurationChangeReleasePhaseReleased,
					ReleasedAt:    pointer.Pointer(time.Unix()),
					ReleaseNumber: 1,
					ApprovalID:    10080,
					ParentID:      1,
				}

				exp := &ccmod.DefaultConfigurationChangeRelease{
					ID:            base.ID(10),
					Environment:   "dev",
					Description:   "desc",
					Phase:         string(ccent.DefaultConfigurationChangeReleasePhaseReleased),
					ReleasedAt:    &time,
					ReleaseNumber: 1,
					ApprovalID:    10080,
					ParentID:      1,
				}
				ignoredFields := []string{}

				Expect(test.CheckNonZeroValue(org, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")

				got := e2m{}.DefaultConfigurationChangeRelease(org)
				Expect(test.CheckNonZeroValue(got, ignoredFields)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")
				Expect(test.IsEqual(exp, got)).To(BeNil())
			})
		})
	})

	PDescribe("DefaultConfigurationChangeItem", func() {
		Context("[Model To Entity]", func() {
			It("should not miss fields when converting", func() {
				org := &ccmod.DefaultConfigurationChangeItem{
					ID:       base.ID(10),
					ItemType: string(ccent.DefaultConfigurationChangeItemTypeDefaultComponentConfig),
					Data:     []byte(`{"version_release":{"cluster_type":"DEDICATED_TIDB","source_version":"v1.0.0","target_version":"v2.0.0","covering_instance_types":["aws:i3.metal"]},"template_default_case_binding":{"origin":{"default_case":{"cloud_provider":"aws","instance_type":"e2-medium","version":"v6.5.2","region":"us-west-2-byoc","config_type":"pd"},"cluster_type":"DEDICATED_TIDB","template_id":101},"modified":{"template_id":202}},"default_component_config":{"origin":{"default_case":{"cluster_type":"DEDICATED_TIDB","component":"pd","version":"v1.0.0"},"base_image":"xxx","image_tag":"v1.0.0"},"modified":{"base_image":"xxx","image_tag":"v2.0.0"}}}`),
					ParentID: 1,
				}

				exp := &ccent.DefaultConfigurationChangeItem{
					ID:       10,
					ItemType: ccent.DefaultConfigurationChangeItemTypeDefaultComponentConfig,
					Data: &ccent.DefaultConfigurationChangeItemDataUnion{
						VersionRelease: &ccent.VersionRelease{
							ClusterType:           ccent.ClusterTypeDedicatedTiDB,
							SourceVersion:         "v1.0.0",
							TargetVersion:         "v2.0.0",
							CoveringInstanceTypes: []string{"aws:i3.metal"},
						},

						TemplateDefaultCaseBinding: &ccent.TemplateDefaultCaseBindingChange{
							Origin: ccent.TemplateDefaultCaseBinding{
								DefaultCase: ccent.TemplateDefaultCase{
									CloudInstanceType: ccent.CloudInstanceType{
										CloudProvider: "aws",
										InstanceType:  "e2-medium",
									},
									Version:    "v6.5.2",
									ConfigType: "pd",
									Region:     "us-west-2-byoc",
									TenantID:   "123",
								},
								ClusterType: ccent.ClusterTypeDedicatedTiDB,
								TemplateID:  101,
							},
							Modified: ccent.TemplateDefaultCaseBindingChangeData{
								TemplateID: 202,
							},
						},

						DefaultComponentConfig: &ccent.DefaultComponentConfigChange{
							Origin: ccent.DefaultComponentConfig{
								DefaultCase: ccent.ComponentDefaultCase{
									ClusterType: ccent.ClusterTypeDedicatedTiDB,
									Component:   "pd",
									Version:     "v1.0.0",
								},
								BaseImage: "xxx",
								ImageTag:  "v1.0.0",
							},
							Modified: ccent.DefaultComponentConfigChangeData{
								BaseImage: "xxx",
								ImageTag:  "v2.0.0",
							},
						},
					},
					ParentID: 1,
				}

				Expect(test.CheckNonZeroValue(org, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")

				got := m2e{}.DefaultConfigurationChangeItem(org)
				Expect(test.CheckNonZeroValue(got, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")
				Expect(test.IsEqual(exp, got)).To(BeNil())
			})
		})

		Context("[Entity To Model]", func() {
			It("should not miss fields when converting", func() {
				org := &ccent.DefaultConfigurationChangeItem{
					ID:       10,
					ItemType: ccent.DefaultConfigurationChangeItemTypeDefaultComponentConfig,
					Data: &ccent.DefaultConfigurationChangeItemDataUnion{
						VersionRelease: &ccent.VersionRelease{
							ClusterType:           ccent.ClusterTypeDedicatedTiDB,
							SourceVersion:         "v1.0.0",
							TargetVersion:         "v2.0.0",
							CoveringInstanceTypes: []string{"aws:i3.metal"},
						},

						TemplateDefaultCaseBinding: &ccent.TemplateDefaultCaseBindingChange{
							Origin: ccent.TemplateDefaultCaseBinding{
								DefaultCase: ccent.TemplateDefaultCase{
									CloudInstanceType: ccent.CloudInstanceType{
										CloudProvider: "aws",
										InstanceType:  "e2-medium",
									},
									Version:    "v6.5.2",
									ConfigType: "pd",
									Region:     "us-west-2-byoc",
								},
								ClusterType: ccent.ClusterTypeDedicatedTiDB,
								TemplateID:  101,
							},
							Modified: ccent.TemplateDefaultCaseBindingChangeData{
								TemplateID: 202,
							},
						},

						DefaultComponentConfig: &ccent.DefaultComponentConfigChange{
							Origin: ccent.DefaultComponentConfig{
								DefaultCase: ccent.ComponentDefaultCase{
									ClusterType: ccent.ClusterTypeDedicatedTiDB,
									Component:   "pd",
									Version:     "v1.0.0",
								},
								BaseImage: "xxx",
								ImageTag:  "v1.0.0",
							},
							Modified: ccent.DefaultComponentConfigChangeData{
								BaseImage: "xxx",
								ImageTag:  "v2.0.0",
							},
						},
					},
					ParentID: 1,
				}

				exp := &ccmod.DefaultConfigurationChangeItem{
					ID:       base.ID(10),
					ItemType: string(ccent.DefaultConfigurationChangeItemTypeDefaultComponentConfig),
					Data:     []byte(`{"version_release":{"cluster_type":"DEDICATED_TIDB","source_version":"v1.0.0","target_version":"v2.0.0","covering_instance_types":["aws:i3.metal"]},"template_default_case_binding":{"origin":{"default_case":{"cloud_provider":"aws","instance_type":"e2-medium","version":"v6.5.2","region":"us-west-2-byoc","config_type":"pd"},"cluster_type":"DEDICATED_TIDB","template_id":101},"modified":{"template_id":202}},"default_component_config":{"origin":{"default_case":{"cluster_type":"DEDICATED_TIDB","component":"pd","version":"v1.0.0"},"base_image":"xxx","image_tag":"v1.0.0"},"modified":{"base_image":"xxx","image_tag":"v2.0.0"}}}`),
					ParentID: 1,
				}
				ignoredFields := []string{}

				Expect(test.CheckNonZeroValue(org, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")

				got := e2m{}.DefaultConfigurationChangeItem(org)
				Expect(test.CheckNonZeroValue(got, ignoredFields)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")
				Expect(test.IsEqual(exp, got)).To(BeNil())
			})
		})
	})

	Describe("DefaultConfigurationChangeItemRelease", func() {
		Context("[Model To Entity]", func() {
			It("should not miss fields when converting", func() {
				org := &ccmod.DefaultConfigurationChangeItemRelease{
					ID:            base.ID(10),
					Environment:   "dev",
					ItemID:        100,
					Data:          []byte(`{"template_default_case_binding":{"template_id":202},"default_component_config":{"base_image":"xxx","image_tag":"v2.0.0"}}`),
					ReleaseNumber: 1,
					ParentID:      1,
				}

				exp := &ccent.DefaultConfigurationChangeItemRelease{
					ID:          10,
					Environment: "dev",
					ItemID:      100,
					Data: &ccent.DefaultConfigurationChangeItemReleaseDataUnion{
						TemplateDefaultCaseBinding: &ccent.TemplateDefaultCaseBindingChangeData{
							TemplateID: 202,
						},

						DefaultComponentConfig: &ccent.DefaultComponentConfigChangeData{
							BaseImage: "xxx",
							ImageTag:  "v2.0.0",
						},
					},
					ReleaseNumber: 1,
					ParentID:      1,
				}

				Expect(test.CheckNonZeroValue(org, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")

				got := m2e{}.DefaultConfigurationChangeItemRelease(org)
				Expect(test.CheckNonZeroValue(got, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")
				Expect(test.IsEqual(exp, got)).To(BeNil())
			})
		})

		Context("[Entity To Model]", func() {
			It("should not miss fields when converting", func() {
				org := &ccent.DefaultConfigurationChangeItemRelease{
					ID:          10,
					Environment: "dev",
					ItemID:      100,
					Data: &ccent.DefaultConfigurationChangeItemReleaseDataUnion{
						TemplateDefaultCaseBinding: &ccent.TemplateDefaultCaseBindingChangeData{
							TemplateID: 202,
						},

						DefaultComponentConfig: &ccent.DefaultComponentConfigChangeData{
							BaseImage: "xxx",
							ImageTag:  "v2.0.0",
						},
					},
					ReleaseNumber: 1,
					ParentID:      1,
				}

				exp := &ccmod.DefaultConfigurationChangeItemRelease{
					ID:            base.ID(10),
					Environment:   "dev",
					ItemID:        100,
					Data:          []byte(`{"template_default_case_binding":{"template_id":202},"default_component_config":{"base_image":"xxx","image_tag":"v2.0.0"}}`),
					ReleaseNumber: 1,
					ParentID:      1,
				}

				ignoredFields := []string{}

				Expect(test.CheckNonZeroValue(org, nil)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")

				got := e2m{}.DefaultConfigurationChangeItemRelease(org)
				Expect(test.CheckNonZeroValue(got, ignoredFields)).To(BeNil(), "some fields missed, maybe added new fields but forgot to update converter")
				Expect(test.IsEqual(exp, got)).To(BeNil())
			})
		})
	})
})
