package service

import (
	"context"
	"fmt"
	"math/rand"
	"testing"

	asappsv1 "github.com/pingcap/advanced-statefulset/client/apis/apps/v1"
	"github.com/pingcap/tidb-operator/pkg/apis/pingcap/v1alpha1"
	"github.com/samber/lo"
	"github.com/stretchr/testify/assert"
	appv1 "k8s.io/api/apps/v1"
	corev1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/runtime"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
	"k8s.io/utils/ptr"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/client/fake"

	apiv1 "github.com/tidbcloud/infra-provider/api/tidbcloud/cluster-agent/v1"
	apicommon "github.com/tidbcloud/infra-provider/api/tidbcloud/common"
	"github.com/tidbcloud/infra-provider/pkg/consts"
	"github.com/tidbcloud/infra-provider/pkg/namer"
	"github.com/tidbcloud/infra-provider/pkg/pingcap/label"
)

func TestAgentService_buildComponentNodeInfos(t *testing.T) {

	buildNodeSelector := func(label map[string]string) labels.Selector {
		selector, _ := metav1.LabelSelectorAsSelector(metav1.SetAsLabelSelector(label))
		return selector
	}
	type args struct {
		tcsBuilder func() []*v1alpha1.TidbCluster
		compTypes  []apicommon.ComponentType
	}
	tests := []struct {
		name    string
		args    args
		want    []*componentNodeInfo
		wantErr bool
	}{
		{
			name: "one tc",
			args: args{
				tcsBuilder: func() []*v1alpha1.TidbCluster {
					tc1 := buildTestTC("tc1", "ns", false, nil)
					tc1.Spec.TiKV = &v1alpha1.TiKVSpec{
						Replicas: 3,
						ComponentSpec: v1alpha1.ComponentSpec{
							NodeSelector: map[string]string{"tikv": "tikv"},
						},
					}
					tc1.Spec.TiDB = &v1alpha1.TiDBSpec{
						Replicas: 1,
						ComponentSpec: v1alpha1.ComponentSpec{
							NodeSelector: map[string]string{"tidb": "tidb"},
						},
					}
					return []*v1alpha1.TidbCluster{tc1}
				},
				compTypes: []apicommon.ComponentType{apicommon.ComponentType_TIKV},
			},
			want: []*componentNodeInfo{
				{
					tcName:         "tc1",
					componentType:  "tikv",
					nodeSelector:   buildNodeSelector(map[string]string{"tikv": "tikv"}),
					desiredNodeNum: 3,
					actualNodeNum:  0,
				},
			},
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			s := &AgentService{}
			ctx := context.Background()
			tcs := tt.args.tcsBuilder()
			name2tc := make(map[string]*v1alpha1.TidbCluster)
			for _, tc := range tcs {
				name2tc[tc.Name] = tc
			}
			got, err := s.buildComponentNodeInfos(ctx, name2tc, tt.args.compTypes)
			assert.Equalf(t, tt.wantErr, err != nil, "wantErr")
			assert.Equalf(t, tt.want, got, "buildComponentNodeInfos()")
		})
	}
}

func TestAgentService_calcComponentNodeReadyResultForGCP(t *testing.T) {
	tc1 := buildTestTC("tc1", testNS, false, nil)
	tc1.Spec.TiKV = &v1alpha1.TiKVSpec{
		Replicas: 1,
		ComponentSpec: v1alpha1.ComponentSpec{
			NodeSelector: map[string]string{label.ComponentLabelKey: "tikv"},
		},
	}
	tc1.Spec.TiDB = &v1alpha1.TiDBSpec{
		Replicas: 1,
		ComponentSpec: v1alpha1.ComponentSpec{
			NodeSelector: map[string]string{label.ComponentLabelKey: "tidb"},
		},
	}
	opDeploymentTikv := buildOverProvisioningDeployment(tc1.Name, "tikv")
	opDeploymentTidb := buildOverProvisioningDeployment(tc1.Name, "tidb")
	opDeploymentTikv.Spec.Replicas = ptr.To(int32(1))
	opDeploymentTikv.Status.ReadyReplicas = 1
	opDeploymentTidb.Spec.Replicas = ptr.To(int32(1))
	opDeploymentTidb.Status.ReadyReplicas = 1

	type args struct {
		clusterId            string
		tcsBuilder           func() []*v1alpha1.TidbCluster
		opDeploymentsBuilder func() []*appv1.Deployment
		compTypes            []apicommon.ComponentType
	}
	tests := []struct {
		name    string
		args    args
		want    []*apiv1.IsNodeReadyForScaleUpDownResp_ComponentResult
		wantErr bool
	}{
		{
			name: "all deployments is ready",
			args: args{
				clusterId: testClusterId,
				tcsBuilder: func() []*v1alpha1.TidbCluster {
					return []*v1alpha1.TidbCluster{tc1}
				},
				opDeploymentsBuilder: func() []*appv1.Deployment {
					return []*appv1.Deployment{opDeploymentTikv, opDeploymentTidb}
				},
				compTypes: []apicommon.ComponentType{apicommon.ComponentType_TIKV, apicommon.ComponentType_TIDB},
			},
			want: []*apiv1.IsNodeReadyForScaleUpDownResp_ComponentResult{
				{
					TcName:        "tc1",
					ComponentType: apicommon.ComponentType_TIKV,
					Ready:         true,
					ReadyReason:   "desired: 1, actual: 1",
				},
				{
					TcName:        "tc1",
					ComponentType: apicommon.ComponentType_TIDB,
					Ready:         true,
					ReadyReason:   "desired: 1, actual: 1",
				},
			},
			wantErr: false,
		},
		{
			name: "tidb overProvisioning deployment is not found",
			args: args{
				clusterId: testClusterId,
				tcsBuilder: func() []*v1alpha1.TidbCluster {
					return []*v1alpha1.TidbCluster{tc1}
				},
				opDeploymentsBuilder: func() []*appv1.Deployment {
					return []*appv1.Deployment{opDeploymentTikv}
				},
				compTypes: []apicommon.ComponentType{apicommon.ComponentType_TIKV, apicommon.ComponentType_TIDB},
			},
			want: []*apiv1.IsNodeReadyForScaleUpDownResp_ComponentResult{
				{
					TcName:        "tc1",
					ComponentType: apicommon.ComponentType_TIKV,
					Ready:         true,
					ReadyReason:   "desired: 1, actual: 1",
				},
				{
					TcName:        "tc1",
					ComponentType: apicommon.ComponentType_TIDB,
					Ready:         false,
					ReadyReason:   "len(deployments)=0",
				},
			},
			wantErr: false,
		},
		{
			name: "tidb readyReplicas mismatch",
			args: args{
				clusterId: testClusterId,
				tcsBuilder: func() []*v1alpha1.TidbCluster {
					return []*v1alpha1.TidbCluster{tc1}
				},
				opDeploymentsBuilder: func() []*appv1.Deployment {
					opDeploymentTidb := opDeploymentTidb.DeepCopy()
					opDeploymentTidb.Status.ReadyReplicas = 0
					return []*appv1.Deployment{opDeploymentTikv, opDeploymentTidb}
				},
				compTypes: []apicommon.ComponentType{apicommon.ComponentType_TIKV, apicommon.ComponentType_TIDB},
			},
			want: []*apiv1.IsNodeReadyForScaleUpDownResp_ComponentResult{
				{
					TcName:        "tc1",
					ComponentType: apicommon.ComponentType_TIKV,
					Ready:         true,
					ReadyReason:   "desired: 1, actual: 1",
				},
				{
					TcName:        "tc1",
					ComponentType: apicommon.ComponentType_TIDB,
					Ready:         false,
					ReadyReason:   "desired: 1, actual: 0",
				},
			},
			wantErr: false,
		},
		{
			name: "two tc",
			args: args{
				clusterId: testClusterId,
				tcsBuilder: func() []*v1alpha1.TidbCluster {
					tc2 := tc1.DeepCopy()
					tc1.Spec.TiKV = nil // tc1 has only tidb
					tc2.Name = "tc2"
					tc2.Spec.TiDB = nil // tc2 has only tikv
					return []*v1alpha1.TidbCluster{tc1, tc2}
				},
				opDeploymentsBuilder: func() []*appv1.Deployment {
					// tc2 has only tikv
					tc2TikvDeployment := buildOverProvisioningDeployment("tc2", "tikv")
					tc2TikvDeployment.Spec.Replicas = ptr.To(int32(1))
					tc2TikvDeployment.Status.ReadyReplicas = 1
					return []*appv1.Deployment{opDeploymentTidb, tc2TikvDeployment}
				},
				compTypes: []apicommon.ComponentType{apicommon.ComponentType_TIKV, apicommon.ComponentType_TIDB},
			},
			want: []*apiv1.IsNodeReadyForScaleUpDownResp_ComponentResult{
				{
					TcName:        "tc2",
					ComponentType: apicommon.ComponentType_TIKV,
					Ready:         true,
					ReadyReason:   "desired: 1, actual: 1",
				},
				{
					TcName:        "tc1",
					ComponentType: apicommon.ComponentType_TIDB,
					Ready:         true,
					ReadyReason:   "desired: 1, actual: 1",
				},
			},
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			pods, nodes := buildPodsAndNodes()
			var initObjects []client.Object
			lo.ForEach(pods, func(pod *corev1.Pod, _ int) {
				initObjects = append(initObjects, pod)
			})
			lo.ForEach(nodes, func(node *corev1.Node, _ int) {
				initObjects = append(initObjects, node)
			})
			if tt.args.opDeploymentsBuilder != nil {
				lo.ForEach(tt.args.opDeploymentsBuilder(), func(deployment *appv1.Deployment, _ int) {
					initObjects = append(initObjects, deployment)
				})
			}

			cli := newFakeClient(initObjects)
			s := &AgentService{dataplaneCli: cli}
			ctx := context.Background()
			tcs := tt.args.tcsBuilder()
			name2tc := make(map[string]*v1alpha1.TidbCluster)
			for _, tc := range tcs {
				name2tc[tc.Name] = tc
			}
			got, err := s.calcComponentNodeReadyResultForGCP(ctx, tt.args.clusterId, name2tc, tt.args.compTypes)
			assert.Equalf(t, tt.wantErr, err != nil, "wantErr")
			assert.ElementsMatchf(t, tt.want, got, "calcComponentNodeReadyResultForGCP()")
		})
	}
}

func TestAgentService_calcComponentNodeReadyResultForAWS(t *testing.T) {
	tc1 := buildTestTC("tc1", testNS, false, nil)
	tc1.Spec.TiKV = &v1alpha1.TiKVSpec{
		Replicas: 1,
		ComponentSpec: v1alpha1.ComponentSpec{
			NodeSelector: map[string]string{label.ComponentLabelKey: "tikv"},
		},
	}
	tc1.Spec.TiDB = &v1alpha1.TiDBSpec{
		Replicas: 1,
		ComponentSpec: v1alpha1.ComponentSpec{
			NodeSelector: map[string]string{label.ComponentLabelKey: "tidb"},
		},
	}

	type args struct {
		clusterId    string
		tcsBuilder   func() []*v1alpha1.TidbCluster
		compTypes    []apicommon.ComponentType
		nodeModifier func(nodes []*corev1.Node)
	}
	tests := []struct {
		name    string
		args    args
		want    []*apiv1.IsNodeReadyForScaleUpDownResp_ComponentResult
		wantErr bool
	}{
		{
			name: "only get tidb",
			args: args{
				clusterId: testClusterId,
				tcsBuilder: func() []*v1alpha1.TidbCluster {
					return []*v1alpha1.TidbCluster{tc1}
				},
				compTypes: []apicommon.ComponentType{apicommon.ComponentType_TIDB},
				nodeModifier: func(nodes []*corev1.Node) {
				},
			},
			want: []*apiv1.IsNodeReadyForScaleUpDownResp_ComponentResult{
				{
					TcName:        "tc1",
					ComponentType: apicommon.ComponentType_TIDB,
					Ready:         true,
					ReadyReason:   "desired: 1, actual: 1",
				},
			},
			wantErr: false,
		},
		{
			name: "all node is ready",
			args: args{
				clusterId: testClusterId,
				tcsBuilder: func() []*v1alpha1.TidbCluster {
					return []*v1alpha1.TidbCluster{tc1}
				},
				compTypes: []apicommon.ComponentType{apicommon.ComponentType_TIKV, apicommon.ComponentType_TIDB},
				nodeModifier: func(nodes []*corev1.Node) {
				},
			},
			want: []*apiv1.IsNodeReadyForScaleUpDownResp_ComponentResult{
				{
					TcName:        "tc1",
					ComponentType: apicommon.ComponentType_TIKV,
					Ready:         true,
					ReadyReason:   "desired: 1, actual: 1",
				},
				{
					TcName:        "tc1",
					ComponentType: apicommon.ComponentType_TIDB,
					Ready:         true,
					ReadyReason:   "desired: 1, actual: 1",
				},
			},
			wantErr: false,
		},
		{
			name: "tidb node is unschedulable",
			args: args{
				clusterId: testClusterId,
				tcsBuilder: func() []*v1alpha1.TidbCluster {
					return []*v1alpha1.TidbCluster{tc1}
				},
				compTypes: []apicommon.ComponentType{apicommon.ComponentType_TIKV, apicommon.ComponentType_TIDB},
				nodeModifier: func(nodes []*corev1.Node) {
					for _, each := range nodes {
						if each.Name == "tidb-node" {
							each.Spec.Unschedulable = true
						}
					}
				},
			},
			want: []*apiv1.IsNodeReadyForScaleUpDownResp_ComponentResult{
				{
					TcName:        "tc1",
					ComponentType: apicommon.ComponentType_TIKV,
					Ready:         true,
					ReadyReason:   "desired: 1, actual: 1",
				},
				{
					TcName:        "tc1",
					ComponentType: apicommon.ComponentType_TIDB,
					Ready:         false,
					ReadyReason:   "desired: 1, actual: 0",
				},
			},
			wantErr: false,
		},
		{
			name: "tidb node mismatch",
			args: args{
				clusterId: testClusterId,
				tcsBuilder: func() []*v1alpha1.TidbCluster {
					return []*v1alpha1.TidbCluster{tc1}
				},
				compTypes: []apicommon.ComponentType{apicommon.ComponentType_TIKV, apicommon.ComponentType_TIDB},
				nodeModifier: func(nodes []*corev1.Node) {
					for _, each := range nodes {
						if each.Name == "tidb-node" {
							each.Labels[label.ComponentLabelKey] = "not-tidb"
						}
					}
				},
			},
			want: []*apiv1.IsNodeReadyForScaleUpDownResp_ComponentResult{
				{
					TcName:        "tc1",
					ComponentType: apicommon.ComponentType_TIKV,
					Ready:         true,
					ReadyReason:   "desired: 1, actual: 1",
				},
				{
					TcName:        "tc1",
					ComponentType: apicommon.ComponentType_TIDB,
					Ready:         false,
					ReadyReason:   "desired: 1, actual: 0",
				},
			},
			wantErr: false,
		},
		{
			name: "two tc",
			args: args{
				clusterId: testClusterId,
				tcsBuilder: func() []*v1alpha1.TidbCluster {
					tc2 := tc1.DeepCopy()
					tc2.Name = "tc2"
					// tc2 has only tikv
					tc2.Spec.TiDB = nil
					// tc1 has only tidb
					tc1.Spec.TiKV = nil
					return []*v1alpha1.TidbCluster{tc1, tc2}
				},
				compTypes: []apicommon.ComponentType{apicommon.ComponentType_TIKV, apicommon.ComponentType_TIDB},
				nodeModifier: func(nodes []*corev1.Node) {
				},
			},
			want: []*apiv1.IsNodeReadyForScaleUpDownResp_ComponentResult{
				{
					TcName:        "tc2",
					ComponentType: apicommon.ComponentType_TIKV,
					Ready:         true,
					ReadyReason:   "desired: 1, actual: 1",
				},
				{
					TcName:        "tc1",
					ComponentType: apicommon.ComponentType_TIDB,
					Ready:         true,
					ReadyReason:   "desired: 1, actual: 1",
				},
			},
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			pods, nodes := buildPodsAndNodes()
			if tt.args.nodeModifier != nil {
				tt.args.nodeModifier(nodes)
			}

			var initObjects []client.Object
			lo.ForEach(pods, func(pod *corev1.Pod, _ int) {
				initObjects = append(initObjects, pod)
			})
			lo.ForEach(nodes, func(node *corev1.Node, _ int) {
				initObjects = append(initObjects, node)
			})
			cli := newFakeClient(initObjects)
			s := &AgentService{dataplaneCli: cli}
			ctx := context.Background()
			tcs := tt.args.tcsBuilder()
			name2tc := make(map[string]*v1alpha1.TidbCluster)
			for _, tc := range tcs {
				name2tc[tc.Name] = tc
			}
			got, err := s.calcComponentNodeReadyResultForAWS(ctx, tt.args.clusterId, name2tc, tt.args.compTypes)
			assert.Equalf(t, tt.wantErr, err != nil, "wantErr")
			assert.ElementsMatchf(t, tt.want, got, "calcComponentNodeReadyResultForAWS()")
		})
	}
}

func TestAgentService_getNodesByClusterId(t *testing.T) {

	type args struct {
		clusterId string
	}
	tests := []struct {
		name                   string
		args                   args
		buildExtraPodsAndNodes func() ([]*corev1.Pod, []*corev1.Node)
		wantFunc               func(allNodes []*corev1.Node) map[string]*corev1.Node
		wantErr                bool
	}{
		{
			name: "match clusterId",
			args: args{
				clusterId: testClusterId,
			},
			wantFunc: func(allNodes []*corev1.Node) map[string]*corev1.Node {
				return lo.SliceToMap(allNodes, func(item *corev1.Node) (string, *corev1.Node) {
					return item.Name, item
				})
			},
			wantErr: false,
		},
		{
			name: "with a new AWS node which is not bound to TC",
			args: args{
				clusterId: testClusterId,
			},
			buildExtraPodsAndNodes: func() ([]*corev1.Pod, []*corev1.Node) {
				node := buildNode("new-node", testNS, "tidb")
				node.Labels["tidb-namespace"] = buildNamespace(testClusterId)
				return nil, []*corev1.Node{node}
			},
			wantFunc: func(allNodes []*corev1.Node) map[string]*corev1.Node {
				return lo.SliceToMap(allNodes, func(item *corev1.Node) (string, *corev1.Node) {
					return item.Name, item
				})
			},
			wantErr: false,
		},

		{
			name: "with a new GCP node which is not bound to TC",
			args: args{
				clusterId: testClusterId,
			},
			buildExtraPodsAndNodes: func() ([]*corev1.Pod, []*corev1.Node) {
				node := buildNode("new-node", testNS, "tidb")
				return nil, []*corev1.Node{node}
			},
			wantFunc: func(allNodes []*corev1.Node) map[string]*corev1.Node {
				filteredNodes := lo.Filter(allNodes, func(item *corev1.Node, index int) bool {
					return item.Name != "new-node"
				})

				return lo.SliceToMap(filteredNodes, func(item *corev1.Node) (string, *corev1.Node) {
					return item.Name, item
				})
			},
			wantErr: false,
		},
		{
			name: "mismatch clusterId",
			args: args{
				clusterId: "mismatch",
			},
			wantFunc: func(allNodes []*corev1.Node) map[string]*corev1.Node {
				return nil
			},
			wantErr: false,
		},
		{
			name: "with a new GCP node which doesn't have namer.ComponentSelectorKey but the corresponding pod has label.ComponentLabelKey",
			args: args{
				clusterId: testClusterId,
			},
			buildExtraPodsAndNodes: func() ([]*corev1.Pod, []*corev1.Node) {
				pod := buildPod("new-pod", testNS, "new-node", "tidb")
				node := buildNode(pod.Spec.NodeName, testNS, "tidb")
				delete(node.Labels, namer.ComponentSelectorKey) // remove namer.ComponentSelectorKey from node
				return []*corev1.Pod{pod}, []*corev1.Node{node}
			},
			wantFunc: func(allNodes []*corev1.Node) map[string]*corev1.Node {
				lo.ForEach(allNodes, func(item *corev1.Node, index int) {
					if item.Name == "new-node" {
						item.Labels[namer.ComponentSelectorKey] = "tidb"
					}
				})

				return lo.SliceToMap(allNodes, func(item *corev1.Node) (string, *corev1.Node) {
					return item.Name, item
				})
			},
			wantErr: false,
		}, {
			name: "with a new GCP node which doesn't have namer.ComponentSelectorKey but the corresponding OP pod has consts.OverProvisioningComponentLabelKey",
			args: args{
				clusterId: testClusterId,
			},
			buildExtraPodsAndNodes: func() ([]*corev1.Pod, []*corev1.Node) {
				pod := buildPod("new-pod", testNS, "new-node", "")
				pod.Labels[label.ComponentLabelKey] = consts.OverProvisioningComponentLabelValue
				pod.Labels[consts.OverProvisioningComponentLabelKey] = "tikv" // use OPComponentLabel

				node := buildNode(pod.Spec.NodeName, testNS, "")
				delete(node.Labels, namer.ComponentSelectorKey) // remove namer.ComponentSelectorKey from node
				return []*corev1.Pod{pod}, []*corev1.Node{node}
			},
			wantFunc: func(allNodes []*corev1.Node) map[string]*corev1.Node {
				lo.ForEach(allNodes, func(item *corev1.Node, index int) {
					if item.Name == "new-node" {
						item.Labels[namer.ComponentSelectorKey] = "tikv"
					}
				})

				return lo.SliceToMap(allNodes, func(item *corev1.Node) (string, *corev1.Node) {
					return item.Name, item
				})
			},
			wantErr: false,
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			pods, nodes := buildPodsAndNodes()
			if tt.buildExtraPodsAndNodes != nil {
				extraPods, extraNodes := tt.buildExtraPodsAndNodes()
				pods = append(pods, extraPods...)
				nodes = append(nodes, extraNodes...)
			}
			var initObjects []client.Object
			lo.ForEach(pods, func(pod *corev1.Pod, _ int) {
				initObjects = append(initObjects, pod)
			})
			lo.ForEach(nodes, func(node *corev1.Node, _ int) {
				initObjects = append(initObjects, node)
			})
			cli := newFakeClient(initObjects)
			s := &AgentService{dataplaneCli: cli}
			ctx := context.Background()

			got, err := s.getNodesByClusterId(ctx, tt.args.clusterId)
			assert.Equalf(t, tt.wantErr, err != nil, "wantErr")
			want := tt.wantFunc(nodes)
			assert.Equalf(t, want, got, "getNodesByClusterId()")
		})
	}
}

func buildPodsAndNodes() ([]*corev1.Pod, []*corev1.Node) {
	tikvPod := buildPod("tikvPod", testNS, "tikv-node", "tikv")
	tidbPod := buildPod("tidbPod", testNS, "tidb-node", "tidb")
	pods := []*corev1.Pod{tikvPod, tidbPod}
	tikvNode := buildNode(tikvPod.Spec.NodeName, testNS, "tikv")
	tidbNode := buildNode(tidbPod.Spec.NodeName, testNS, "tidb")
	nodes := []*corev1.Node{tikvNode, tidbNode}

	return pods, nodes
}

func buildPod(name, ns, nodeName, compoType string) *corev1.Pod {
	return &corev1.Pod{
		ObjectMeta: metav1.ObjectMeta{
			Name:      name,
			Namespace: ns,
			Labels: map[string]string{
				label.ComponentLabelKey: compoType,
				label.InstanceLabelKey:  testTcName,
			},
		},
		Spec: corev1.PodSpec{
			NodeName: nodeName,
		},
		Status: corev1.PodStatus{},
	}
}

func buildNode(name, ns, compoType string) *corev1.Node {
	return &corev1.Node{
		ObjectMeta: metav1.ObjectMeta{
			Name:      name,
			Namespace: ns,
			Labels: map[string]string{
				corev1.LabelHostname:       name, // node name as the hostname
				label.ComponentLabelKey:    compoType,
				namer.ComponentSelectorKey: compoType,
			},
		},
	}
}

func buildOverProvisioningDeployment(tcName, compoType string) *appv1.Deployment {
	return &appv1.Deployment{
		ObjectMeta: metav1.ObjectMeta{
			Name:      fmt.Sprintf("op-deploy-%s-%d", tcName, rand.Int()),
			Namespace: testNS,
			Labels:    buildOverProvisioningDeploymentLabels(tcName, compoType),
		},
	}
}

func newFakeClient(initObjs []client.Object) client.Client {
	scheme := runtime.NewScheme()
	utilruntime.Must(clientgoscheme.AddToScheme(scheme))
	utilruntime.Must(v1alpha1.SchemeBuilder.AddToScheme(scheme))
	utilruntime.Must(asappsv1.AddToScheme(scheme))

	cli := fake.NewClientBuilder().WithScheme(scheme).WithObjects(initObjs...).Build()
	return cli
}
