package agentbuild

import (
	"testing"
	"text/template"

	vmoperatorv1beta1 "github.com/VictoriaMetrics/operator/api/operator/v1beta1"
	"github.com/stretchr/testify/assert"
	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"sigs.k8s.io/controller-runtime/pkg/client"

	"github.com/tidbcloud/observability/agent-control-server/pkg/config"
	"github.com/tidbcloud/observability/agent-control-server/pkg/consts"
)

func TestBuildVectorResources(t *testing.T) {
	tests := []struct {
		name          string
		annotations   map[string]string
		baseResources *corev1.ResourceRequirements
		wantResources *corev1.ResourceRequirements
		wantJSON      string
	}{
		{
			name:        "no annotations",
			annotations: map[string]string{},
			baseResources: &corev1.ResourceRequirements{
				Requests: corev1.ResourceList{
					corev1.ResourceCPU:    resource.MustParse("100m"),
					corev1.ResourceMemory: resource.MustParse("200Mi"),
				},
				Limits: corev1.ResourceList{
					corev1.ResourceCPU:    resource.MustParse("200m"),
					corev1.ResourceMemory: resource.MustParse("400Mi"),
				},
			},
			wantResources: &corev1.ResourceRequirements{
				Requests: corev1.ResourceList{
					corev1.ResourceCPU:    resource.MustParse("100m"),
					corev1.ResourceMemory: resource.MustParse("200Mi"),
				},
				Limits: corev1.ResourceList{
					corev1.ResourceCPU:    resource.MustParse("200m"),
					corev1.ResourceMemory: resource.MustParse("400Mi"),
				},
			},
			wantJSON: `{"limits":{"cpu":"200m","memory":"400Mi"},"requests":{"cpu":"100m","memory":"200Mi"}}`,
		},
		{
			name: "override cpu request",
			annotations: map[string]string{
				consts.AnnotationKeyO11yVectorCPURequest: "500m",
			},
			baseResources: &corev1.ResourceRequirements{
				Requests: corev1.ResourceList{
					corev1.ResourceCPU: resource.MustParse("100m"),
				},
			},
			wantResources: &corev1.ResourceRequirements{
				Requests: corev1.ResourceList{
					corev1.ResourceCPU: resource.MustParse("500m"),
				},
			},
			wantJSON: `{"requests":{"cpu":"500m"}}`,
		},
		{
			name: "override all",
			annotations: map[string]string{
				consts.AnnotationKeyO11yVectorCPURequest:    "500m",
				consts.AnnotationKeyO11yVectorCPULimit:      "1000m",
				consts.AnnotationKeyO11yVectorMemoryRequest: "500Mi",
				consts.AnnotationKeyO11yVectorMemoryLimit:   "1Gi",
			},
			baseResources: &corev1.ResourceRequirements{
				Requests: corev1.ResourceList{},
				Limits:   corev1.ResourceList{},
			},
			wantResources: &corev1.ResourceRequirements{
				Requests: corev1.ResourceList{
					corev1.ResourceCPU:    resource.MustParse("500m"),
					corev1.ResourceMemory: resource.MustParse("500Mi"),
				},
				Limits: corev1.ResourceList{
					corev1.ResourceCPU:    resource.MustParse("1000m"),
					corev1.ResourceMemory: resource.MustParse("1Gi"),
				},
			},
			wantJSON: `{"limits":{"cpu":"1","memory":"1Gi"},"requests":{"cpu":"500m","memory":"500Mi"}}`,
		},
		{
			name: "override partial attributes",
			annotations: map[string]string{
				consts.AnnotationKeyO11yVectorCPURequest:  "500m",
				consts.AnnotationKeyO11yVectorMemoryLimit: "1Gi",
			},
			baseResources: &corev1.ResourceRequirements{
				Requests: corev1.ResourceList{
					corev1.ResourceCPU:    resource.MustParse("100m"),
					corev1.ResourceMemory: resource.MustParse("200Mi"),
				},
				Limits: corev1.ResourceList{
					corev1.ResourceCPU:    resource.MustParse("200m"),
					corev1.ResourceMemory: resource.MustParse("400Mi"),
				},
			},
			wantResources: &corev1.ResourceRequirements{
				Requests: corev1.ResourceList{
					corev1.ResourceCPU:    resource.MustParse("500m"),
					corev1.ResourceMemory: resource.MustParse("200Mi"),
				},
				Limits: corev1.ResourceList{
					corev1.ResourceCPU:    resource.MustParse("200m"),
					corev1.ResourceMemory: resource.MustParse("1Gi"),
				},
			},
			wantJSON: `{"limits":{"cpu":"200m","memory":"1Gi"},"requests":{"cpu":"500m","memory":"200Mi"}}`,
		},
		{
			name: "invalid cpu request",
			annotations: map[string]string{
				consts.AnnotationKeyO11yVectorCPURequest: "invalid",
			},
			baseResources: &corev1.ResourceRequirements{},
			wantResources: nil,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			agent := &corev1.Pod{
				ObjectMeta: metav1.ObjectMeta{
					Annotations: tt.annotations,
				},
			}
			res := tt.baseResources.DeepCopy()
			got, err := BuildVectorResources(agent, res)
			if tt.wantJSON == "" {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.wantResources, res)
				assert.JSONEq(t, tt.wantJSON, got)
			}
		})
	}
}

func testBuildTemplate(t *testing.T, annoKey string, buildFunc func(client.Object, config.Templates, string) (*template.Template, error)) {
	tmplDefault := template.New("default")
	tmplCustom := template.New("custom")
	tmpls := config.Templates{
		"default": tmplDefault,
		"custom":  tmplCustom,
	}

	tests := []struct {
		name           string
		annotations    map[string]string
		configTemplate string
		want           *template.Template
		wantErr        bool
	}{
		{
			name:           "use default template",
			annotations:    nil,
			configTemplate: "default",
			want:           tmplDefault,
			wantErr:        false,
		},
		{
			name: "use override template",
			annotations: map[string]string{
				annoKey: "custom",
			},
			configTemplate: "default",
			want:           tmplCustom,
			wantErr:        false,
		},
		{
			name:           "template not found",
			annotations:    nil,
			configTemplate: "not-exist",
			want:           nil,
			wantErr:        true,
		},
		{
			name: "override template not found",
			annotations: map[string]string{
				annoKey: "not-exist",
			},
			configTemplate: "default",
			want:           nil,
			wantErr:        true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			agent := &corev1.Pod{
				ObjectMeta: metav1.ObjectMeta{
					Annotations: tt.annotations,
				},
			}
			got, err := buildFunc(agent, tmpls, tt.configTemplate)
			if tt.wantErr {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.want, got)
			}
		})
	}
}

func TestBuildVMAgentTemplate(t *testing.T) {
	testBuildTemplate(t, consts.AnnotationKeyO11yVMAgentConfigTemplate, BuildVMAgentTemplate)
}

func TestBuildVectorTemplate(t *testing.T) {
	testBuildTemplate(t, consts.AnnotationKeyO11yVectorConfigTemplate, BuildVectorTemplate)
}

func TestBuildVMAgent(t *testing.T) {
	resources := &corev1.ResourceRequirements{
		Requests: corev1.ResourceList{
			corev1.ResourceCPU: resource.MustParse("100m"),
		},
	}
	storage := &vmoperatorv1beta1.StorageSpec{
		VolumeClaimTemplate: vmoperatorv1beta1.EmbeddedPersistentVolumeClaim{
			Spec: corev1.PersistentVolumeClaimSpec{
				Resources: corev1.VolumeResourceRequirements{
					Requests: corev1.ResourceList{
						corev1.ResourceStorage: resource.MustParse("10Gi"),
					},
				},
			},
		},
	}

	tests := []struct {
		name        string
		tmplText    string
		args        map[string]string
		values      map[string]string
		expectError bool
	}{
		{
			name: "success",
			tmplText: `
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMAgent
metadata:
  name: {{ .Name }}
`,
			args:        map[string]string{"arg1": "val1"},
			values:      map[string]string{"Name": "test-agent"},
			expectError: false,
		},
		{
			name:        "unmarshal error",
			tmplText:    `invalid: yaml: : :`,
			args:        map[string]string{},
			values:      map[string]string{},
			expectError: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tmpl, err := template.New("test").Parse(tt.tmplText)
			assert.NoError(t, err)

			agent, err := BuildVMAgent(tmpl, resources, storage, tt.args, tt.values)
			if tt.expectError {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
				assert.Equal(t, "test-agent", agent.Name)
				assert.Equal(t, true, agent.Spec.StatefulMode)
				assert.Equal(t, "val1", agent.Spec.ExtraArgs["arg1"])
				assert.Equal(t, agent.Spec.ExtraArgs["remoteWrite.maxDiskUsagePerURL"], "9GiB")
			}
		})
	}
}

func TestBuildVMAgentWithPodLabels(t *testing.T) {
	resources := &corev1.ResourceRequirements{
		Requests: corev1.ResourceList{
			corev1.ResourceCPU: resource.MustParse("100m"),
		},
	}
	storage := &vmoperatorv1beta1.StorageSpec{
		VolumeClaimTemplate: vmoperatorv1beta1.EmbeddedPersistentVolumeClaim{
			Spec: corev1.PersistentVolumeClaimSpec{
				Resources: corev1.VolumeResourceRequirements{
					Requests: corev1.ResourceList{
						corev1.ResourceStorage: resource.MustParse("10Gi"),
					},
				},
			},
		},
	}
	tmplWithMeta, err := template.New("withmeta").Parse(`
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMAgent
metadata:
  name: test-agent
spec:
  podMetadata:
    labels:
      existing: "keep"
`)
	assert.NoError(t, err)
	tmplNoMeta, err := template.New("nometa").Parse(`
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMAgent
metadata:
  name: test-agent
`)
	assert.NoError(t, err)

	tests := []struct {
		name        string
		tmpl        *template.Template
		affinity    *corev1.Affinity
		tolerations []corev1.Toleration
		podLabels   map[string]string
		verify      func(t *testing.T, agent *vmoperatorv1beta1.VMAgent)
	}{
		{
			name:      "podLabels does not overwrite existing keys",
			tmpl:      tmplWithMeta,
			podLabels: map[string]string{"existing": "overwrite", "new": "val"},
			verify: func(t *testing.T, agent *vmoperatorv1beta1.VMAgent) {
				assert.Equal(t, "keep", agent.Spec.PodMetadata.Labels["existing"])
				assert.Equal(t, "val", agent.Spec.PodMetadata.Labels["new"])
			},
		},
		{
			name:      "podLabels creates PodMetadata when nil",
			tmpl:      tmplNoMeta,
			podLabels: map[string]string{"app": "test"},
			verify: func(t *testing.T, agent *vmoperatorv1beta1.VMAgent) {
				assert.Equal(t, "test", agent.Spec.PodMetadata.Labels["app"])
			},
		},
		{
			name: "affinity is injected",
			tmpl: tmplWithMeta,
			affinity: &corev1.Affinity{
				NodeAffinity: &corev1.NodeAffinity{
					RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{
						NodeSelectorTerms: []corev1.NodeSelectorTerm{{
							MatchExpressions: []corev1.NodeSelectorRequirement{{
								Key:      "zone",
								Operator: corev1.NodeSelectorOpIn,
								Values:   []string{"us-east-1a"},
							}},
						}},
					},
				},
			},
			verify: func(t *testing.T, agent *vmoperatorv1beta1.VMAgent) {
				assert.NotNil(t, agent.Spec.Affinity)
				assert.Equal(t, "us-east-1a", agent.Spec.Affinity.NodeAffinity.RequiredDuringSchedulingIgnoredDuringExecution.NodeSelectorTerms[0].MatchExpressions[0].Values[0])
			},
		},
		{
			name: "tolerations are injected",
			tmpl: tmplWithMeta,
			tolerations: []corev1.Toleration{{
				Key:      "dedicated",
				Operator: corev1.TolerationOpEqual,
				Value:    "o11y",
				Effect:   corev1.TaintEffectNoExecute,
			}},
			verify: func(t *testing.T, agent *vmoperatorv1beta1.VMAgent) {
				assert.Len(t, agent.Spec.Tolerations, 1)
				assert.Equal(t, "dedicated", agent.Spec.Tolerations[0].Key)
			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			agent, err := BuildVMAgentWithPodLabels(tt.tmpl, resources, storage, tt.affinity, tt.tolerations, nil, nil, tt.podLabels)
			assert.NoError(t, err)
			tt.verify(t, agent)
		})
	}
}

func TestBuildVMPodScrape(t *testing.T) {
	tests := []struct {
		name        string
		tmplText    string
		values      map[string]string
		expectError bool
		expected    string
	}{
		{
			name: "success",
			tmplText: `
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMPodScrape
metadata:
  name: {{ .Name }}
`,
			values:      map[string]string{"Name": "test-scrape"},
			expectError: false,
			expected:    "test-scrape",
		},
		{
			name:        "template error",
			tmplText:    `{{ .Unknown }}`,
			values:      map[string]string{"Name": "test-scrape"},
			expectError: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tmpl, err := template.New("vmpodscrape").Parse(tt.tmplText)
			assert.NoError(t, err)

			scrape, err := BuildVMPodScrape(tmpl, tt.values)
			if tt.expectError {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.expected, scrape.Name)
			}
		})
	}
}

func TestBuildVectorValues(t *testing.T) {
	tests := []struct {
		name        string
		tmplText    string
		values      map[string]string
		expectError bool
		expected    string
	}{
		{
			name:        "success",
			tmplText:    `key: {{ .Value }}`,
			values:      map[string]string{"Value": "test-value"},
			expectError: false,
			expected:    "key: test-value",
		},
		{
			name:        "template error",
			tmplText:    `{{ .Unknown }}`,
			values:      map[string]string{"Value": "test-value"},
			expectError: true,
			expected:    "<no value>",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tmpl, _ := template.New("vector").Parse(tt.tmplText)
			res, err := BuildVectorValues(tmpl, tt.values)
			if err != nil {
				assert.Error(t, err)
			} else {
				assert.Equal(t, tt.expected, res)
			}
		})
	}
}

func TestBuildRemoteWriteURL(t *testing.T) {
	tests := []struct {
		name     string
		vendor   string
		expected string
	}{
		{
			name:     "AWS vendor",
			vendor:   consts.VendorTypeAWS,
			expected: "http://dns.com/o11y-id/api/v1/write",
		},
		{
			name:     "GCP vendor",
			vendor:   consts.VendorTypeGCP,
			expected: "http://endpoint.dns.com/o11y-id/api/v1/write",
		},
		{
			name:     "Azure vendor",
			vendor:   consts.VendorTypeAzure,
			expected: "http://dns.com/o11y-id/api/v1/write",
		},
		{
			name:     "unknown vendor",
			vendor:   "unknown",
			expected: "",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			agent := &corev1.Pod{
				ObjectMeta: metav1.ObjectMeta{
					Annotations: map[string]string{
						consts.AnnotationKeyO11yID:                       "o11y-id",
						consts.AnnotationKeyO11yServiceDNSName:           "dns.com",
						consts.AnnotationKeyO11ySvcInterfaceEndpointName: "endpoint",
					},
				},
			}
			url := BuildRemoteWriteURL(tt.vendor, agent)
			assert.Equal(t, tt.expected, url)
		})
	}
}

func TestBuildVMAgentResources(t *testing.T) {
	tests := []struct {
		name          string
		annotations   map[string]string
		baseResources *corev1.ResourceRequirements
		wantResources *corev1.ResourceRequirements
		expectError   bool
	}{
		{
			name:        "no annotations",
			annotations: map[string]string{},
			baseResources: &corev1.ResourceRequirements{
				Requests: corev1.ResourceList{
					corev1.ResourceCPU: resource.MustParse("100m"),
				},
			},
			wantResources: &corev1.ResourceRequirements{
				Requests: corev1.ResourceList{
					corev1.ResourceCPU: resource.MustParse("100m"),
				},
			},
			expectError: false,
		},
		{
			name: "override all",
			annotations: map[string]string{
				consts.AnnotationKeyO11yVMAgentCPURequest:    "200m",
				consts.AnnotationKeyO11yVMAgentCPULimit:      "400m",
				consts.AnnotationKeyO11yVMAgentMemoryRequest: "200Mi",
				consts.AnnotationKeyO11yVMAgentMemoryLimit:   "400Mi",
			},
			baseResources: &corev1.ResourceRequirements{
				Requests: corev1.ResourceList{},
				Limits:   corev1.ResourceList{},
			},
			wantResources: &corev1.ResourceRequirements{
				Requests: corev1.ResourceList{
					corev1.ResourceCPU:    resource.MustParse("200m"),
					corev1.ResourceMemory: resource.MustParse("200Mi"),
				},
				Limits: corev1.ResourceList{
					corev1.ResourceCPU:    resource.MustParse("400m"),
					corev1.ResourceMemory: resource.MustParse("400Mi"),
				},
			},
			expectError: false,
		},
		{
			name: "override partial attributes",
			annotations: map[string]string{
				consts.AnnotationKeyO11yVMAgentCPURequest:  "200m",
				consts.AnnotationKeyO11yVMAgentMemoryLimit: "400Mi",
			},
			baseResources: &corev1.ResourceRequirements{
				Requests: corev1.ResourceList{
					corev1.ResourceCPU:    resource.MustParse("100m"),
					corev1.ResourceMemory: resource.MustParse("200Mi"),
				},
				Limits: corev1.ResourceList{
					corev1.ResourceCPU:    resource.MustParse("200m"),
					corev1.ResourceMemory: resource.MustParse("300Mi"),
				},
			},
			wantResources: &corev1.ResourceRequirements{
				Requests: corev1.ResourceList{
					corev1.ResourceCPU:    resource.MustParse("200m"),
					corev1.ResourceMemory: resource.MustParse("200Mi"),
				},
				Limits: corev1.ResourceList{
					corev1.ResourceCPU:    resource.MustParse("200m"),
					corev1.ResourceMemory: resource.MustParse("400Mi"),
				},
			},
			expectError: false,
		},
		{
			name: "invalid memory limit",
			annotations: map[string]string{
				consts.AnnotationKeyO11yVMAgentMemoryLimit: "invalid",
			},
			baseResources: &corev1.ResourceRequirements{},
			wantResources: nil,
			expectError:   true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			agent := &corev1.Pod{
				ObjectMeta: metav1.ObjectMeta{
					Annotations: tt.annotations,
				},
			}
			res := tt.baseResources.DeepCopy()
			err := BuildVMAgentResources(agent, res)
			if tt.expectError {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.wantResources, res)
			}
		})
	}
}

func TestBuildVectorImage(t *testing.T) {
	testImageBuild(t, consts.AnnotationKeyO11yVectorImage, BuildVectorImage)
}

func TestBuildVMAgentImage(t *testing.T) {
	testImageBuild(t, consts.AnnotationKeyO11yVMAgentImage, BuildVMAgentImage)
}

func testImageBuild(t *testing.T, annotationKey string, buildFunc func(client.Object, string) (string, string, error)) {
	tests := []struct {
		name        string
		annotations map[string]string
		defaultImg  string
		wantRepo    string
		wantTag     string
		expectError bool
	}{
		{
			name:        "default image",
			annotations: map[string]string{},
			defaultImg:  "repo/image:tag",
			wantRepo:    "repo/image",
			wantTag:     "tag",
			expectError: false,
		},
		{
			name: "override image",
			annotations: map[string]string{
				annotationKey: "newrepo/newimage:newtag",
			},
			defaultImg:  "repo/image:tag",
			wantRepo:    "newrepo/newimage",
			wantTag:     "newtag",
			expectError: false,
		},
		{
			name:        "invalid image format",
			annotations: map[string]string{},
			defaultImg:  "invalidimage",
			wantRepo:    "",
			wantTag:     "",
			expectError: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			agent := &corev1.Pod{
				ObjectMeta: metav1.ObjectMeta{
					Annotations: tt.annotations,
				},
			}
			repo, tag, err := buildFunc(agent, tt.defaultImg)
			if tt.expectError {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.wantRepo, repo)
				assert.Equal(t, tt.wantTag, tag)
			}
		})
	}
}

func TestBuildVMAgentStorage(t *testing.T) {
	tests := []struct {
		name        string
		annotations map[string]string
		baseStorage *vmoperatorv1beta1.StorageSpec
		wantStorage *vmoperatorv1beta1.StorageSpec
		expectError bool
	}{
		{
			name:        "no annotations",
			annotations: map[string]string{},
			baseStorage: &vmoperatorv1beta1.StorageSpec{
				VolumeClaimTemplate: vmoperatorv1beta1.EmbeddedPersistentVolumeClaim{
					Spec: corev1.PersistentVolumeClaimSpec{
						Resources: corev1.VolumeResourceRequirements{
							Requests: corev1.ResourceList{
								corev1.ResourceStorage: resource.MustParse("20Gi"),
							},
						},
					},
				},
			},
			wantStorage: &vmoperatorv1beta1.StorageSpec{
				VolumeClaimTemplate: vmoperatorv1beta1.EmbeddedPersistentVolumeClaim{
					Spec: corev1.PersistentVolumeClaimSpec{
						Resources: corev1.VolumeResourceRequirements{
							Requests: corev1.ResourceList{
								corev1.ResourceStorage: resource.MustParse("20Gi"),
							},
						},
					},
				},
			},
			expectError: false,
		},
		{
			name: "override storage size",
			annotations: map[string]string{
				consts.AnnotationKeyO11yVMAgentStorageSize: "50Gi",
			},
			baseStorage: &vmoperatorv1beta1.StorageSpec{
				VolumeClaimTemplate: vmoperatorv1beta1.EmbeddedPersistentVolumeClaim{
					Spec: corev1.PersistentVolumeClaimSpec{
						Resources: corev1.VolumeResourceRequirements{
							Requests: corev1.ResourceList{
								corev1.ResourceStorage: resource.MustParse("20Gi"),
							},
						},
					},
				},
			},
			wantStorage: &vmoperatorv1beta1.StorageSpec{
				VolumeClaimTemplate: vmoperatorv1beta1.EmbeddedPersistentVolumeClaim{
					Spec: corev1.PersistentVolumeClaimSpec{
						Resources: corev1.VolumeResourceRequirements{
							Requests: corev1.ResourceList{
								corev1.ResourceStorage: resource.MustParse("50Gi"),
							},
						},
					},
				},
			},
			expectError: false,
		},
		{
			name: "override storage size with nil requests",
			annotations: map[string]string{
				consts.AnnotationKeyO11yVMAgentStorageSize: "100Gi",
			},
			baseStorage: &vmoperatorv1beta1.StorageSpec{
				VolumeClaimTemplate: vmoperatorv1beta1.EmbeddedPersistentVolumeClaim{
					Spec: corev1.PersistentVolumeClaimSpec{
						Resources: corev1.VolumeResourceRequirements{
							Requests: nil,
						},
					},
				},
			},
			wantStorage: &vmoperatorv1beta1.StorageSpec{
				VolumeClaimTemplate: vmoperatorv1beta1.EmbeddedPersistentVolumeClaim{
					Spec: corev1.PersistentVolumeClaimSpec{
						Resources: corev1.VolumeResourceRequirements{
							Requests: corev1.ResourceList{
								corev1.ResourceStorage: resource.MustParse("100Gi"),
							},
						},
					},
				},
			},
			expectError: false,
		},
		{
			name: "invalid storage size",
			annotations: map[string]string{
				consts.AnnotationKeyO11yVMAgentStorageSize: "invalid",
			},
			baseStorage: &vmoperatorv1beta1.StorageSpec{
				VolumeClaimTemplate: vmoperatorv1beta1.EmbeddedPersistentVolumeClaim{
					Spec: corev1.PersistentVolumeClaimSpec{
						Resources: corev1.VolumeResourceRequirements{
							Requests: corev1.ResourceList{
								corev1.ResourceStorage: resource.MustParse("20Gi"),
							},
						},
					},
				},
			},
			wantStorage: nil,
			expectError: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			agent := &corev1.Pod{
				ObjectMeta: metav1.ObjectMeta{
					Annotations: tt.annotations,
				},
			}
			storage := tt.baseStorage.DeepCopy()
			err := BuildVMAgentStorage(agent, storage)
			if tt.expectError {
				assert.Error(t, err)
			} else {
				assert.NoError(t, err)
				assert.Equal(t, tt.wantStorage, storage)
			}
		})
	}
}
